线性数据结构---队列,栈 随笔

我们从四个简单但重要的概念开始研究数据结构。栈,队列,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
posted @ 2019-09-15 20:57  AnthonyWang  阅读(233)  评论(0编辑  收藏  举报