数据结构(8)--栈的应用之行编辑程序、括号匹配检验、数制转换、hanio塔问题

参考书籍:数据结构(C语言版)严蔚敏吴伟民编著清华大学出版社

本文中的代码可从这里下载:https://github.com/qingyujean/data-structure

1.行编辑程序

1.1问题描述

    一个简单的行编辑程序的功能是:接收用户从终端的输入的数据,并存入用户的数据区。而用户在终端可能输入差错,所以每接收一个字符就立即存入数据区显然是不合适的。此时就需要有一些“回退”或者“撤销”的操作,即我们需要维护一个“输入缓冲区”,用以接收用户的一行数据,然后逐行存入用户数据区。当用户输入时,允许用户输入出差错,并能及时更正。例如:

    1.当用户发现刚刚输入的一个字符是错的,可以补进一个"#"表示退格符,用以表示前面输入的那个字符无效;

    2.当用户发现键入的行内差错较多或难以补救时,可以键入"@"表示退行符,用以表示当前一整行均无效。

1.2代码实现:

#coding=utf-8
def lineEdit():
    #利用栈stack作为一个用户数据输入缓冲区,从终端接受一行数据并传送至调用过程的数据区
    stack = []
    line = raw_input("")
    #'$'为全文结束符,line不是空串
    while len(line)!=0:
        for i in range(len(line)):
            ch = line[i]
            if ch == '$':
                break;
            elif ch == '#':
                stack.pop()
            elif ch == '@':
                #清空stack
                stack = []
            else:
                #有效字符进栈
                stack.append(ch)
        #一行输入处理完了,将从栈底到栈顶的字符传送至调用过程的数据区,该过程用打印语句代替
        print ''.join(stack)
        #清空栈
        satck = []
        #读入下一行
        line = raw_input("")
def main():
    lineEdit()

if __name__ == '__main__':
    main()

1.3演示

2.括号匹配检验

2.1问题描述

    三种括号:()、[ ]、{ },依次读入括号串,后遇到的左括号总是“越急迫的渴望得到匹配”,反而先遇到的左括号的急迫程度低,这与栈的特点相吻合。算法的基本思想是:左括号总是入栈,栈顶的左括号的急迫程度最高,如果接下来读取的字符是左括号,则该左括号入栈,成为最高急迫渴望得到匹配,而之前的左括号的急迫程度均降低一层;若接下来读取的字符是右括号,则栈顶的左括号得到匹配,出栈‘以此类推,直到栈为空,则括号是完全匹配的。

    算法流程图如下:

2.2代码实现

#coding=utf-8
def isMatch(topElem, curChar):
    matcher = {')':'(', ']':'[', '}':'{'}
    return topElem == matcher[curChar]
      
def isParenthesisMatching():
    parenthesisStr = raw_input("请输入待检验的括号串:")     
    #维护一个顺序栈stack
    stack = [] 
    for i in range(len(parenthesisStr)):
        ch = parenthesisStr[i]
        if ch == '(' or ch == '[' or ch == '{':
            stack.append(ch)
        elif ch == ')' or ch == ']' or ch == '}':
            #栈是否为空,如果为空,则右括号多余
            if len(stack) == 0:
                return False
            #与栈顶元素匹配,则出栈
            elif isMatch(stack[-1], ch):
                stack.pop()
            #与栈顶元素不匹配,则入栈
            else:
                stack.append(ch)
        #print stack
    #如果栈为空,则是完全匹配
    return len(stack) == 0
   
def main():
    print isParenthesisMatching()

if __name__ == '__main__':
    main()

 

2.3演示

 

3.数制转换

3.1问题描述

    将一个十进制数N转化为d进制数,转化过程是用N不断除以d,将所得的余数记录下来,直至商为0,产生的余数逆向组合起来便是对应的d进制数了。这个过程刚好和栈的后进先出的特点相吻合。

    算法:

    1.初始化一个空栈

    2.N不断除以d,求余数,至商为0(循环)

    3.产生的余数依次入栈

    4.出栈的顺序刚好是转化好的数(即从栈顶到栈底)

3.2代码实现

#coding=utf-8
#数值转换
def conversion():
    stack = []
    n = input("请输入一个待转换的十进制数字:")
    d = input("想转化为几进制?")
    if n == 0:
        return 0
    while n:
        stack.append(n%d)
        n/=d
    stack.reverse()
    return ''.join(map(str, stack))
    
def main():
    print conversion()

if __name__ == '__main__':
    main()

 

3.3演示

 

4.Hanoi塔问题

4.1问题描述

    古代有一个梵塔,塔内有三个座A、B、C,A座上有64个盘子,盘子大小不等,大的在下,小的在上(如图)。有一个和尚想把这64个盘子从A座移到B座,但每次只能允许移动一个盘子,并且在移动过程中,3个座上的盘子始终保持大盘在下,小盘在上。在移动过程中可以利用B座,要求打印移动的步骤。

    汉诺塔问题的求解示意图:

    

分析:

1.多个函数嵌套调用的内部执行过程 

  通常,当在一个函数的运行期间调用另一个函数时,在运行被调用函数之前,系统需要先完成三件事: 
  (1)将所有的实在参数、返回地址等信息传递给被调用函数保存;
  (2)为被调用函数的局部变量分配存储区;
  (3)将控制转移到被调用函数的入口。
  而从被调用函数返回调用函数之前,系统也应完成三件工作: 

  (1)保存被调函数的计算结果;
  (2)释放被调函数的数据区;
  (3)依照被调函数保存的返回地址将控制转移到调用函数。
  当有多个函数构成嵌套调用时,按照“后调用先返回”的原则,上述函数之间的信息传递和控制转移必须通过“栈”来实现,即系统将整个程序运行时所需的数据空间安排在一个栈中,每当调用一个函数时,就为它在栈顶分配一个存储区,每当从一个函数退出时,就释放它的存储区,则当前正运行的数据区必在栈顶。

2.递归函数的内部执行过程 

  在计算机内部,一个递归函数的调用过程类似于多个函数的嵌套调用,只不过调用函数和被调用函数是同一个函数。为了保证递归函数的正确执行,系统需设立一个工作栈。具体地说,递归调用的内部执行过程如下: 
 ⑴ 运行开始时,首先为递归调用建立一个工作栈,其结构包括值参、局部变量和返回地址;
 ⑵ 每次执行递归调用之前,把递归函数的值参和局部变量的当前值以及调用后的返回地址压栈;
 ⑶ 每次递归调用结束后,将栈顶元素出栈,使相应的值参和局部变量恢复为调用前的值,然后转向返回地址指定的位置继续执行。 
 这些执行过程都有系统的工作栈来维护。

4.2代码实现

Hanoi问题的递归算法

#coding=utf-8
#count为全局变量,记录搬动次数
count = 0
def move(x, n, z):
    #搬动操作
    global count
    count +=1
    print "%d. 将%d号盘子从塔座%s搬到%s" %(count, n, x, z)
    
#将x塔座上按直径由小到大且自上而下编号为1--n的n个圆盘按规则搬到塔座z上,y可作为辅助塔座
def hanoi(n, x, y, z):
    if n == 1:
        move(x, n, z)
    else:
        hanoi(n-1, x, z, y)
        move(x, n, z)
        hanoi(n-1, y, x, z)


def main():
    hanoi(3, 'a', 'b', 'c')
    
if __name__ == '__main__':
    main()

 

4.3演示

我们为Hanoi问题的核心递归算法语句编上号,如下

1    def hanoi(n, x, y, z):
2       if n == 1:
3            move(x, n, z)
        else:
4           hanoi(n-1, x, z, y)
5           move(x, n, z)
6           hanoi(n-1, y, x, z)
    那么上述汉诺塔算法在执行过程中,工作栈的变化如下图所示,其中栈元素的结构为(返回地址,n值,A值,B值,C值),返回地址对应算法中语句的行号,图的序号对应递归调用和返回的序号。

本文中的代码可从这里下载:https://github.com/qingyujean/data-structure

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值