数据结构学习(栈与队列:三(栈的典型应用(递归嵌套)))

栈的典型应用

递归嵌套

栈还适合解决一类问题,这类问题的特点是:具有自相似的(某一局部往往和整体具有某种共性)问题多可嵌套的递归描述,但因分支位置和嵌套深度并不固定,其递归算法不易控制。

栈结构天然的具有递归嵌套性,故可高效地解决这类问题。

括号匹配

括号匹配就是一种递归嵌套的问题,其任务是,在任一程序块,判断其中的括号是否在嵌套的意义下完全匹配。对于这各任务,我们只需要将push、pop操作分别与左括号和右括号相对应即可:

bool paren(const char exp[], int lo, int hi)//表达式括号匹配,可兼顾三种括号
{
	Stack<char> S;//使用栈记录已发现但尚未匹配的左括号
	for(int i = lo; i <= hi; i++) //逐一检查当前字符
		switch(exp[i])//左括号直接进栈;右括号若与栈顶失配,则表达式不匹配
		{
			case '(' : case '[' : case '{' : S.push(exp[i]); break;
			case ')' : if((S.empty()) || (')' != S.pop())) return fasle; break;
			case ']' : if((S.empty()) || (']' != S.pop())) return false; break;
			case '}' : if((S.empty()) || ('}' != S.pop())) return false; break;
			default: break;// 非括号字符一律忽略
		}
		return S.empty();//整个表达式扫描过后,栈中若仍残留(左括号),则不匹配;否则(栈空)匹配
}

这种算法的流程比较简单,而且便于推广至多类括号并存的场景。它自左向右的逐个考察各字符,忽略所有的非括号字符,反遇到左括号,无论哪一类都压入栈中,反遇到右括号,者弹出栈顶的左括号并与之对比。若二者同类,则继续检查下一字符;否则,则可断定表达式不匹配。当然,栈S提前变空或者表达式扫描完之后栈S非空,也意味着不匹配。

栈混洗

另一个递归嵌套的问题就是栈混洗问题:考察三个栈A、B和S,其中B和S初始问空,A含有n个元素,自顶而下构成输入序列:A = < a1, a2, a3。。。an],这里用尖括号表示栈顶,方括号表示栈底。以下,只允许进行S.push(A.pop())或B.push(S.pop())操作,将A中的顶元素压入栈S中,或弹出S的顶元素压入B中,则在经过这两列操作各n次之后,栈A和S有可能均为空。原A中的元素均以转入栈B中。S就相当于一个中转站。若将B中元素自底而上构成的序列记作:B = [ak1, ak2, ak3, …akn> ,则该序列称作原输入序列的一个栈混洗。

比如A = < 1, 2, 3, 4], 则[3, 2, 4, 1>、[1, 2, 3, 4>、[4, 3, 2, 1>等等都是原输入的栈混洗。只是因为每次中转栈push和pop操作的顺序不同,所以会产生不同的栈混洗。现在分析一下:[3, 1, 2, 4>是不是原输入序列的一个栈混洗。这个栈混洗的第一个元素就是3,所以在从中转栈中pop出3时,中转栈中一定也有1和2,且2一定在1的上方,所以在栈混洗中,2一定是先于1被压入栈中。所以这个栈混洗一定是不存在的。

所以可以得出结论当i,j,k都是栈中元素的位置时,i<j<k,则栈中若以[…k, …i,…j…>排列,那么这个栈混洗一定不存在。

当原输入序列的元素个数为n时,它的栈混洗个数为 (2n)!/(n+1)!/n! 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值