算法 栈、队列、二分查找

1. 栈

  • 类似于一个口的客栈,先进去的后出来,后进去的先出来,代码实现如下:
  • Stack() 创建一个空的新栈。 它不需要参数,并返回一个空栈。
  • push(item)将一个新项添加到栈的顶部。它需要 item 做参数并不返回任何内容。
  • pop() 从栈中删除顶部项。它不需要参数并返回 item 。栈被修改。
  • isEmpty() 测试栈是否为空。不需要参数,并返回布尔值。
  • size() 返回栈中的 item 数量。不需要参数,并返回一个整数。
class Stack():
    def __init__(self): # 实例化一个空栈
        self.items = [] # 容器
    def push(self,item): # item就是向栈中添加的元素(从栈顶添加到栈底)
        self.items.append(item)
    def pop(self):
        return self.items.pop()
    def isEmpty(self):
        return self.items == []
    def size(self):
        return len(self.items)
# 实例化一个空栈    
stack = Stack()
stack.push(1)
stack.push(2)
stack.push(3)

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

2. 队列

  • 类似于两个口的胡同,一个只进,一个只出,且先进的先出,代码如下:
  • Queue() 创建一个空的新队列。 它不需要参数,并返回一个空队列。
  • enqueue(item) 将新项添加到队尾。 它需要 item 作为参数,并不返回任何内容。
  • dequeue() 从队首移除项。它不需要参数并返回 item。 队列被修改。
  • isEmpty() 查看队列是否为空。它不需要参数,并返回布尔值。
  • size() 返回队列中的项数。它不需要参数,并返回一个整数。
# 队列实现思路:先进先出,将元素存于列表中,添加时永远插在索引为0的位置,取出时永远取索引的最后一个
class Queue():
    def __init__(self):     # 实例化一个空队列
        self.items = []
    def enqueue(self,item):  # 添加元素
        self.items.insert(0,item)
    def dequeue(self):      # 取元素
        return self.items.pop()
    def isEmpty(self):      # 是否为空
        return self.items == []
    def size(self):         # 判断长度
        return len(self.items)
    
q = Queue()
q.enqueue(1)
q.enqueue(2)
q.enqueue(3)

print(q.dequeue())
print(q.dequeue())
print(q.dequeue())
  • 应用场景:
    • 我们的计算机实验室有 30 台计算机与一台打印机联网。当学生想要打印时,他们的打印任务与正在等待的所有其他打印任务“一致”。第一个进入的任务是先完成。如果你是最后一个,你必须等待你前面的所有其他任务打印
  • 案例:烫手的山芋
    • 烫手山芋游戏介绍:6个孩子围城一个圈,排列顺序孩子们自己指定。第一个孩子手里有一个烫手的山芋,需要在计时器计时1秒后将山芋传递给下一个孩子,依次类推。规则是,在计时器每计时7秒时,手里有山芋的孩子退出游戏。该游戏直到剩下一个孩子时结束,最后剩下的孩子获胜。请使用队列实现该游戏策略,排在第几个位置最终会获胜。
    • 关键因素:
      • 必须要保证手里有山芋的孩子永远在队头的位置
        • 结论:
          • 计时器计时7秒或者山芋被传递6次则一轮游戏结束,淘汰一个孩子,游戏继续。
# 队列实现思路:先进先出,将元素存于列表中,添加时永远插在索引为0的位置,取出时永远取索引的最后一个
class Queue():
    def __init__(self):     # 实例化一个空队列
        self.items = []
    def enqueue(self,item):  # 添加元素
        self.items.insert(0,item)
    def dequeue(self):      # 取元素
        return self.items.pop()
    def isEmpty(self):      # 是否为空
        return self.items == []
    def size(self):         # 判断长度
        return len(self.items)
kids = ['A','B','C','D','E','F']
# 将孩子加入到队列中
kids_queue = Queue()  # 实例化一个空队列
for kid in kids:
    kids_queue.enqueue(kid)

while kids_queue.size() > 1:  # 长度为1时结束
    for i in range(6):
        first_kid = kids_queue.dequeue()
        kids_queue.enqueue(first_kid)
    # 6次传递结束之后需要将队头孩子删除出队列
    kids_queue.dequeue()
print('获胜的孩子是:',kids_queue.dequeue())

3. 二分查找

  • 有序列表对于我们的实现搜索是很有用的。在顺序查找中,当我们与第一个元素进行比较时,如果第一个元素不是我们要查找的,则最多还有 n-1 个元素需要进行比较。 二分查找则是从中间元素开始,而不是按顺序查找列表。 如果该元素是我们正在寻找的元素,我们就完成了查找。 如果它不是,我们可以使用列表的有序性质来消除剩余元素的一半。如果我们正在查找的元素大于中间元素,就可以消除中间元素以及比中间元素小的一半元素。如果该元素在列表中,肯定在大的那半部分。然后我们可以用大的半部分重复该过程,继续从中间元素开始,将其与我们正在寻找的内容进行比较。
  • 例题:给定列表,用二分查找,查找元素7
# 二分查找的前提是序列有序,所以先排序
# lst = [1,3,11,18,4,5,7,9]
# print(sorted(lst))

def find(alist, item):
    # left,right表示列表的起始索引
    left = 0
    right = len(alist) - 1
    isFind = False  # 是否找到的标识
    while left <= right:
        # 中间值的索引,地板除
        mid_index = (right + left) // 2
        # 中间值大于要查找的值,right移动
        if alist[mid_index] > item:
            right = mid_index - 1
        else:
            # 查找到,修改isFind,并终止循环
            if alist[mid_index] == item:
                isFind = True
                break
            else:
                left = mid_index + 1
    return isFind

alist = [1, 3, 4, 5, 7, 9]
print(find(alist, 7))
posted @ 2020-04-06 16:24  lvweihe  阅读(385)  评论(0编辑  收藏  举报