数据结构与算法之栈、队列、递归思想、判断出栈顺序的合法性

数据结构与算法第二节课内容的复习与总结
栈:限定在表尾进行插入/删除的线性表。(FILO)
数据结构特点:先进后出(子弹弹匣)
小结论:如果进栈的顺序是123…则出栈的顺序不能是312结构的(三个数(不一定要连在一起)最大的在左边最小的在中间第二大的在右边)``
这是一个充要条件。
在这里插入图片描述
用数组的形式按照栈的数据结构存放数据,return -1并没有实际意义,只是作为判断值进行后续的操作。出栈要使用指针形式。
递归在操作系统内部的实现就是利用栈的原理。


递归:递归的核心思想就是把任务拆分,要思考该把什么分给下一个运行单元
递归的两个案例:
在这里插入图片描述
在这里插入图片描述
经典的汉诺塔问题:这里的AB代表的塔不是固定的,可以换,但是C是固定的。每一次递归都把问题拆分,先把上面的n-1个移到辅助塔,再把第n个移到C塔,再把辅助塔上的n-1个移到C塔(以另一个塔作为辅助塔)。


队列:先进先出的数据结构(FIFO),
队列也可以放到数组里实现。防止队列溢出的方法,构造环形队列,但是环形队列存在无法分辨是空队列还是满队列的问题,这里可以用队满少用一个空间的方法解决。以下是入队和出队的代码。
在这里插入图片描述

在出队的代码中,队首的位置不断更新,但是求余那句限制了队首的标号不能超过数组的容量。在入队的代码中,拿队尾+1求余和队首序号比较,首先队尾肯定在队首前面,所以等于的情况必须是队尾领先队首一圈还差一个,就解决了问题。


案例演练:判断一个序列是否是FILO序列。提供有两种很简便的算法,第一种是在添加数据的时候就开始检查,巧妙地利用了栈数据结构的特点,代码简洁性和时间复杂度都很好。第二种是利用312的结论,这种思考起来逻辑比较简单,但是时间复杂度比较高。

int main() {
    char s, Q[8], x = 'A';
    int count = 0, top = 0;
    scanf("%c", &s);
    while (count < 8) {
        if (top > 0 && Q[top - 1] == s) {
            top--; scanf("%c", &s); count++;//一边向栈中输入元素一边检查,检查通过后继续输入要判断的序列
        }
        else if (x <= 'H')	Q[top++] = x++;//输入符合出栈顺序的一个序列
        else { printf("0"); return 0; }//不符合条件,判断失败
    }
    printf("1"); return 0;//循环跑完,符合条件,判断成功


******************************************************************

int main()
{
	char a[8]; int flag=1;
	for (int i = 0; i < 8; i++)
		cin >> a[i];
	for (int i = 7; i >= 2; i--) //312反过来是213,这里用的是反向213的判断,这个细节很好,如果用312来判断条件会复杂一点。
	{//(>=2)注意边界的判断,一开始写的时候不要太在意,但是调试的时候数据的选择要在边界上做文章,从而判断出正确的边界。
	
	
		{
			for (int j = i; j >=1; j--)
			{
				if (a[j] < a[i])
					
				{
					for (int k = j; k >= 0; k--)
					{
						if (a[k] > a[i])
							flag = 0;
					}
				}

			}
		}
		
	}
	if (flag == 0)
		cout << "is not a filo" << endl;
	else
		cout << "is a filo" << endl;
	system("pause");
	return 0;

}

另外本节课还涉及到另一个回溯算法,大体就是通过对遍历过的部分做标记,不断地返回上一级,以此完成整个数据的遍历。

下一节课出现了循环队列的一道难题,在这里做一个整理。

#include <iostream>
using namespace std;
//输入格式:
//第一行有2个整数m 和 n  (2<=m<=20表示循环队列的定长。n<=100 表示命令的个数)
//以下n行每行描述一个入队/出队命令
//1 x     表示字符x入队,。 输出当前front、rear的值(空格分开、加回车)
//2        表示队头出队。 输出当前front、rear的值(空格分开、加回车)
//除以上操作输出之外,执行完所有操作后输出队列所有元素(队头开始,不要空格)。
//数据保证任何时候队列中元素<=m-1。


int main()
{
	int m,n,front=0,rear=0;//基础框架搭好之后有两个关键问题1.实现队尾跑到队头 2.输入2指令 
	char x;//1的方法就是在迭代的时候使用front/rear=((front/rear)+1)%m (这里的/不是除号,而是或者的意思)

	cin>>m>>n;
	getchar();
	char que[m];
	for(int i=0;i<n;i++)
	{
		char a[4] ;//2的方法是创建字符数组,这样就可以既能输入一个又能输入两个字符了,这里注意判断条件要加'' 
		gets(a);//对于创建字符数组的位置,写进循环里比较稳妥,每次循环都会重新创建,若在外面创建就可能有风险 
		if (a[0] == '1'&&(rear+1)%m!=front)//且之后的是牺牲一个元素的空间排除是空队列的可能,题目要求元素个数<m-1 
		{//原答案语句没有&&后面的,若爆满则无法执行while语句,修改后无法输入最后一个数据,拿下! 
			que[rear]=a[2];
			rear=(rear+1)%m;
			cout<<front<<" "<<rear<<endl;		
		}
		else if(a[0]=='2')
		{
			front=(front+1)%m;
			cout<<front<<" "<<rear<<endl;	
		}
		
	}
while(front!=rear)//注意入队和出队的区别,入队需要排除满队列的可能,而出队只管大胆出即可。 
{
cout<<que[front];
front=(front+1)%m;
}
return 0;
}

在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值