zoukankan      html  css  js  c++  java
  • 线性数据结构---队列,栈 随笔

    我们从四个简单但重要的概念开始研究数据结构。栈,队列,deques(双向队列), 列表是一类数据的容器,它们数据元素之间的顺序由添加或删除的顺序决定。一旦一个数据元素被添加,它相对于前后元素一直保持该位置不变。诸如此类的数据结构被称为线性数据结构。

      线性数据结构有两端,有时被称为左右,某些情况被称为前后。你也可以称为顶部和底部,名字都不重要。将两个线性数据结构区分开的方法是添加和移除元素的方式,特别是添加和移除元素的位置。例如一些结构允许从一端添加元素,另一些允许从另一端移除元素。

    概念:栈(有时称为“后进先出栈”)是一个元素的有序集合,其中添加移除新元素总发生在同一端。这一端通常称为“顶部”。与顶部对应的端称为“底部”。栈的底部很重要,因为在栈中靠近底部的元素是存储时间最长的。最近添加的元素是最先会被移除的。这种排序原则有时被称为 LIFO,后进先出。它基于在集合内的时间长度做排序。较新的项靠近顶部,较旧的项靠近底部。

      案例:栈的例子很常见。几乎所有的自助餐厅都有一堆托盘或盘子,你从顶部拿一个,就会有一个新的托盘给下一个客人。想象桌上有一堆书, 只有顶部的那本书封面可见,要看到其他书的封面,只有先移除他们上面的书。

    栈的分析与应用:

       - 分析:和栈相关的最有用的想法之一来自对它的观察。假设从一个干净的桌面开始,现在把书一本本叠起来,你在构造一个栈。考虑下移除一本书会发生什么。移除的顺序跟刚刚被放置的顺序相反。栈之所以重要是因为它能反转项的顺序。插入跟删除顺序相反。

       - 应用:每个 web 浏览器都有一个返回按钮。当你浏览网页时,这些网页被放置在一个栈中(实际是网页的网址)。你现在查看的网页在顶部,你第一个查看的网页在底部。如果按‘返回’按钮,将按相反的顺序浏览刚才的页面。

    Python实现栈

    栈的抽象数据类型应该由以下结构和操作定义。栈操作如下: 

    • Stack() 创建一个空的新栈。 它不需要参数,并返回一个空栈。
    • push(item)将一个新项添加到栈的顶部。它需要 item 做参数并不返回任何内容。
    • pop() 从栈中删除顶部项。它不需要参数并返回 item 。栈被修改。
    • peek() 从栈返回顶部项,但不会删除它。不需要参数。 不修改栈。
    • isEmpty() 测试栈是否为空。不需要参数,并返回布尔值。
    • size() 返回栈中的 item 数量。不需要参数,并返回一个整数。

      代码实现:

      Python 中的列表类提供了有序集合机制和一组方法。例如,如果我们有列表 [2,5,3,6,7,4],我们只需要确定列表的哪一端将被认为是栈的顶部。一旦确定,可以使用诸如 append 和 pop 的列表方法来实现操作。

    复制代码
    # 创建栈
    class Stack():
        def __init__(self):
            self.items = []
            
        # 入栈(压栈)
        def push(self,item):
            self.items.append(item)
            
        # 出栈
        def pop(self):
            return self.items.pop()
        
        # 栈指针回到栈顶部
        def peek(self):
            return len(self.items) - 1
        
        # 判断栈是否为空,空返回Ture,否则为False
        def isEmpty(self):
            return self.items == []
        
        # 获取栈长度
        def size(self):
            return len(self.items)
    复制代码

      测试应用:

    复制代码
    from basic.stack import Stack
    
    s=Stack()
    
    print(s.isEmpty())
    s.push(4)
    s.push('dog')
    print(s.peek())
    s.push(True)
    print(s.size())
    print(s.isEmpty())
    s.push(8.4)
    print(s.pop())
    print(s.pop())
    print(s.size())
    复制代码

    栈的应用实例(URL存放机制)

      模拟网站url地址存放机制:

    复制代码
    s = Stack()
    
    # 点击进入一个新的网页
    def getRequest(url):
        s.push(url)
        
    # 查看当前网页
    def showCurenrUrl():
        print('当前页面展示的url:'+s.pop())
       
    # 回退到前一个网页
    def back():
        print('回退按钮点击后显示的url:',s.pop())
    
    
    getRequest('www.1.com')
    getRequest('www.2.com')
    getRequest('www.3.com')
    
    showCurenrUrl()
    back()
    back()
    # 结果:>>>
    当前页面展示的url:www.3.com
    回退按钮点击后显示的url: www.2.com
    回退按钮点击后显示的url: www.1.com

    双端队列(Deque)

      概念:deque(也称为双端队列)是与队列类似的项的有序集合。它有两个端部,首部和尾部,并且项在集合中保持不变。

      特性:deque 特殊之处在于添加和删除项是非限制性的。可以在前面或后面添加新项。同样,可以从任一端移除现有项。在某种意义上,这种混合线性结构提供了单个数据结构中的栈和队列的所有能力。

      注意:即使 deque 可以拥有栈和队列的许多特性,它不需要由那些数据结构强制的 LIFO 和 FIFO 排序。这取决于你如何持续添加和删除操作。

    Python实现Deque

      Deque的抽象数据类型应该由以下结构和操作定义。其中元素可以从首部或尾部的任一端添加和移除。Deque操作如下:

      • Deque() 创建一个空的新 deque。它不需要参数,并返回空的 deque。
      • addFront(item) 将一个新项添加到 deque 的首部。它需要 item 参数 并不返回任何内容。
      • addRear(item) 将一个新项添加到 deque 的尾部。它需要 item 参数并不返回任何内容。
      • removeFront() 从 deque 中删除首项。它不需要参数并返回 item。deque 被修改。
      • removeRear() 从 deque 中删除尾项。它不需要参数并返回 item。deque 被修改。
      • isEmpty() 测试 deque 是否为空。它不需要参数,并返回布尔值。
      • size() 返回 deque 中的项数。它不需要参数,并返回一个整数。

       创建双端队列:

    复制代码
    # 创建双端队列
    class Dequeue():
        def __init__(self):
            self.items = []
            
        # 从队列头部插入数据
        def addFont(self,item):
            self.items.insert(0,item)
            
        # 从队列尾部插入数据
        def addRear(self,item):
            self.items.append(item)
            
        # 队头取出元素
        def removeFont(self):
            return self.items.pop()
        
        # 队尾取元素
        def removeRear(self):
            return self.items.pop(0)
        
        # 获取队列长度
        def size(self):
            return len(self.items)
    复制代码

      队列测试:

    复制代码
    q = Dequeue()
    q.addFont(1)
    q.addFont(2)
    q.addFont(3)
    
    # print(q.removeFont())
    # print(q.removeFont())
    # print(q.removeFont())
    print(q.removeRear())
    print(q.removeRear())
    print(q.removeRear())
    
    # 结果>>>
    3
    2
    1

    双端队列的应用案例(回文检查)

      回文检测:设计程序,检测一个字符串是否为回文。

      回文:回文是一个字符串,读取首尾相同的字符,例如,radar toot madam

      分析:该问题的解决方案将使用 deque 来存储字符串的字符。我们从左到右处理字符串,并将每个字符添加到 deque 的尾部。在这一点上,deque 像一个普通的队列。然而,我们现在可以利用 deque 的双重功能。 deque 的首部保存字符串的第一个字符,deque 的尾部保存最后一个字符。我们可以直接删除并比较首尾字符,只有当它们匹配时才继续。如果可以持续匹配首尾字符,我们最终要么用完字符,要么留出大小为 1 的deque,取决于原始字符串的长度是偶数还是奇数。在任一情况下,字符串都是回文。

    class Dequeue():
        def __init__(self):
            self.items = []
    
        def addFront(self,item):
            self.items.insert(0,item)
    
        def addRear(self,item):
            self.items.append(item)
    
        def removeFront(self):
            return self.items.pop()
        def removeRear(self):
            return self.items.pop(0)
    
        def size(self):
            return len(self.items)
    
    
    
    def isHuiWen(s):
        de = Dequeue()
        ex = True
        for sr in s:
            de.addFront(sr)
    
        while de.size() > 1:
            if de.removeFront() != de.removeRear():
                ex = False
                break
    
        return ex
    
    print(isHuiWen("abcba"))

    队列的应用实例(烫手的山芋)

      实验规则:烫手山芋游戏介绍:6个孩子围城一个圈,排列顺序孩子们自己指定。第一个孩子手里有一个烫手的山芋,需要在计时器计时1秒后将山芋传递给下一个孩子,依次类推。规则是,在计时器每计时7秒时,手里有山芋的孩子退出游戏。该游戏直到剩下一个孩子时结束,最后剩下的孩子获胜。请使用队列实现该游戏策略,排在第几个位置最终会获胜。

      分析:

    • 为了模拟这个圈,我们可以使用队列。假设游戏开始时,排在队列中的第一个(队首)的孩子手里拿着山芋。游戏开始后,拿着山芋的孩子出队列然后再入队列,将山芋传递给下一个孩子。每当山芋到队首孩子手里后,队首的孩子先出队列再入队列,依次类推。当传递六次后,手里有山芋的孩子淘汰,游戏继续,继续传递山芋。
    • 手里有山芋的孩子淘汰后,队列指针指向下一个孩子,保证手里有山芋的孩子永远站在队列的头部

      代码实现:

    复制代码
    q = Queue()
    kids = ['A','B','C','D','E','F']
    
    # 进队列(循环队列)
    for kid in kids:
        q.enqueue(kid)
    
    # 队列中剩最后一个孩子则跳出循环,孩子获胜
    while q.size() > 1:
        # 内层循环是用来将手里有山芋的孩子排在队头
        # 每次计时器到时,删除当前孩子,则指针指向的下一个孩子位置
        # 每次计时,循环队列
        for i in range(6):
            # 删除队列最后一个孩子
            kid = q.dequeue()
            # 删除的孩子重新添加在队首位置,实现队列循环
            q.enqueue(kid)
        # 6s计时到时,删除最后一个孩子,指针指向下一个孩子
        q.dequeue()
    
    # 打印最后获胜的孩子
    print(q.dequeue())
    
    # 孩子E获胜,留下的最后一个孩子
    # 结果>>>E
    复制代码

    Python实现队列

      队列的抽象数据类型应该由以下结构和操作定义。队列操作如下:

      • Queue() 创建一个空的新队列。 它不需要参数,并返回一个空队列。
      • enqueue(item) 将新项添加到队尾。 它需要 item 作为参数,并不返回任何内容。
      • dequeue() 从队首移除项。它不需要参数并返回 item。 队列被修改。
      • isEmpty() 查看队列是否为空。它不需要参数,并返回布尔值。
      • size() 返回队列中的项数。它不需要参数,并返回一个整数。
    复制代码






    class Queue(): def __init__(self): self.items = [] # 队列插入元素(左端) def enqueue(self,item): self.items.insert(0,item) # 队列删除元素(右端) def dequeue(self): return self.items.pop() # 判断队列是否为空,空返回True,否则返回False def isEmpty(self): return self.items == [] # 返回队列长度 def size(self): return len(self.items)
    复制代码

      队列测试:

    复制代码
    >>> q.size()
    3
    >>> q.isEmpty()
    False
    >>> q.enqueue(8.4)
    >>> q.dequeue()
    4
    >>> q.dequeue()
    'dog'
    >>> q.size()
    2
  • 相关阅读:
    C# HTTP请求返回内容为乱码解决办法
    C# WinForm点击按钮后有黑色边框的解决办法
    C# WinForm 拖动无边框窗体
    C# 解决panel或者其他控件叠加时,此控件背景透明,显示的背景色为窗体背景色问题
    C# Winform的panel控件添加背景图片后窗体闪烁问题解决办法
    C# webBrower空间跨域问题处理办法
    C# Winform 点击TreeView控件节点的CheckBox不触发NodeMouseClick事件的做法
    C# Winform 快速点击TreeView控件的CheckBox导致显示不同步
    【转】input file标签限制上传文件类型
    使用node.js仿写Apache
  • 原文地址:https://www.cnblogs.com/anthony-wang0228/p/11524197.html
Copyright © 2011-2022 走看看