队列——层次遍历,循环队列,单调队列

队列的特性:先进先出

队列实现,python内置队列

import queue


q = queue.Queue()
# 入队
q.put()
# 队列长度
q.qsize()
# 出队
q.get()

1.层次遍历

例1-1:内置函数实现层次遍历

'''
0619 02队列
二叉树的层次遍历
FIFO队列用Qsize表示
每一层开始处理之前记录
一个while,一个for
'''

import queue


class TreeNode(object):
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None


class Solution(object):
    def levelOrder(self, root):
        res = []
        q = queue.Queue()  # 一个队列来保存

        # 初始化根节点加入队列中
        if root:
            q.put(root)

        while q.qsize() > 0:  # 这一步是层次遍历
            q_size = q.qsize()  # 当前层里面节点的个数
            cur_level = []

            for i in range(q_size):  # 获得q_size后要顺序遍历获取下一层节点
                cur = q.get()
                cur_level.append(cur.val)
                if cur.left:
                    q.put(cur.left)
                if cur.right:
                    q.put(cur.right)
                # 将下一层节点放到队列中

            res.append([x for x in cur_level])

        return res


if __name__ == '__main__':
    root = TreeNode(3)
    root.left = TreeNode(9)
    root.right = TreeNode(8)
    root.right.left = TreeNode(6)
    root.right.right = TreeNode(7)

    s = Solution()
    print(s.levelOrder(root))

例1-2:两个数组实现层次遍历

'''
0619 02队列
二叉树的层次遍历
FIFO队列用两层level list表示

'''


class TreeNode(object):
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None


class Solution(object):
    def levelOrder(self, root):
        ans = []  # 存放每一层的结果
        cur = []  # 存放当前层的结果

        # 初始化
        if root:
            cur.append(root)

        while len(cur):  # 相当于q_size
            next_level = []  # 存放下一层的节点
            cur_val = []  # 存放当前层的值

            for i in cur:  # 顺序遍历
                # 循环当前队列
                cur_val.append(i.val)
                if i.left:
                    next_level.append(i.left)
                if i.right:
                    next_level.append(i.right)
            cur = next_level  # 获取当前层的元素个数——分层遍历

            ans.append([x for x in cur_val])
        return ans


'''
1.q_size用表示当前层的数组长度
2.如何让队首出列,将值保存,再用新的队列替换旧队列
3.每一层都要初始化
        q_size = 1
        res = []
        q = [root]
        while q_size > 0 and root.left and root.right:
            cur = q[0]
            q.pop(0)
            r = [cur.val]
            if cur.left:
                q.append(cur.left)
            if cur.right:
                q.append(cur.right)
            q_size -= 1
            q_size = len(q)
            res.append(r)

        return res

'''

if __name__ == '__main__':
    root = TreeNode(3)
    root.left = TreeNode(9)
    root.right = TreeNode(8)
    root.right.left = TreeNode(6)
    root.right.right = TreeNode(7)

    s = Solution()
    print(s.levelOrder(root))

2.循环队列

例2:设计一个可以容纳k个元素的循环队列

'''
0619 循环队列
设计一个可以容纳K个元素的循环队列,实现以下接口
1.循环队列重点在于循环使用固定空间
2.难点在于控制好front和rear两个首尾指示器
方法1:K个元素空间,3个变量 front,rear,used
队列为空,used=0
队列为满,used=K
下标在0~K-1的范围内移动
取模:index=i的后面一个=(i+1)%capacity
index=i的前面一个=(i-1+capacity)%capacity
'''


class MyCircularQueue:
    # 参数K表示这个循环队列最多只能容纳K个元素
    def __init__(self, k: int):
        self.front = 0
        self.rear = 0
        self.used = 0
        self.a = [0] * k
        self.capacity = k

    # 将value放入队列中,成功返回true
    def enQueue(self, value: int) -> bool:
        if self.isFull():
            return False
        # 放入新元素
        self.a[self.rear] = value
        # 队尾指针向后移一位
        self.rear = (self.rear + 1) % self.capacity
        # 使用标记加一
        self.used += 1
        return True

    # 删除队首元素,成功返回true
    def deQueue(self) -> bool:
        if self.isEmpty():
            return False
        # 队首指针向后移一位
        self.front = (self.front + 1) % self.capacity
        # 使用标记减一
        self.used -= 1
        return True

    # 得到队首元素,如果为空,返回-1
    def Front(self) -> int:
        if self.isEmpty():
            return -1
        return self.a[self.front]

    # 得到队尾元素,如果为空,返回-1
    def Rear(self) -> int:
        # rear指针指向的是队尾后面的空位置
        if self.isEmpty():
            return -1
        # 获取rear指针的前一位
        tail = (self.rear - 1 + self.capacity) % self.capacity
        return self.a[tail]

    # 判断循环队列是否为空
    def isEmpty(self) -> bool:
        return self.used == 0

    # 判断循环队列是否满了
    def isFull(self) -> bool:
        return self.used == self.capacity


if __name__ == '__main__':
    obj = MyCircularQueue(5)
    param_1 = obj.enQueue(1)
    param_2 = obj.deQueue()
    param_3 = obj.Front()
    param_4 = obj.Rear()
    param_5 = obj.isEmpty()
    param_6 = obj.isFull()
'''
0619 循环队列
设计一个可以容纳K个元素的循环队列,实现以下接口
方法2:K+1个元素空间,2个变量 front,rear
队列为空,front==rear
队列为满:(rear+1)%capacity==front
下标活动范围0~K
变量越少有利于无锁队列的实现
'''


class MyCircularQueue:
    # 参数K表示这个循环队列最多只能容纳K个元素
    def __init__(self, k: int):
        self.front = 0
        self.rear = 0
        self.a = [0] * (k + 1)
        self.capacity = k + 1

    # 将value放入队列中,成功返回true
    def enQueue(self, value: int) -> bool:
        if self.isFull():
            return False
        # 放入新元素
        self.a[self.rear] = value
        # 队尾指针向后移一位
        self.rear = (self.rear + 1) % self.capacity
        return True

    # 删除队首元素,成功返回true
    def deQueue(self) -> bool:
        if self.isEmpty():
            return False
        # 队首指针向后移一位
        self.front = (self.front + 1) % self.capacity
        return True

    # 得到队首元素,如果为空,返回-1
    def Front(self) -> int:
        if self.isEmpty():
            return -1
        return self.a[self.front]

    # 得到队尾元素,如果为空,返回-1
    def Rear(self) -> int:
        # rear指针指向的是队尾后面的空位置
        if self.isEmpty():
            return -1
        # 获取rear指针的前一位
        tail = (self.rear - 1 + self.capacity) % self.capacity
        return self.a[tail]

    # 判断循环队列是否为空
    def isEmpty(self) -> bool:
        return self.front == self.rear

    # 判断循环队列是否满了
    def isFull(self) -> bool:
        next_rear = (self.rear + 1) % self.capacity
        return next_rear == self.front


if __name__ == '__main__':
    obj = MyCircularQueue(5)
    param_1 = obj.enQueue(1)
    param_2 = obj.deQueue()
    param_3 = obj.Front()
    param_4 = obj.Rear()
    param_5 = obj.isEmpty()
    param_6 = obj.isFull()

3.单调队列

例3:滑动窗口的最大值

'''
0619 单调队列 滑动窗口的最大值
要求队列中的元素必须满足单调性
1.入队前队列已经满足单调性
2.入队后任然满足单调性
单调递减队列
1.队首元素是队列中的最大值
2.一个元素被其他元素剔除,则不会再出队
3.一个元素是当前元素的最大值,出队后还会再次出队
出队元素不等于队首元素,什么都不做,出队元素与队首元素相比,相等才出队
入队是扩张单调队列的覆盖范围
出队是控制单调递减队列的覆盖范围
队首元素是覆盖范围的最大值

双端队列实现单调队列
'''

from collections import deque


class Solution(object):
    def __init__(self):
        # 单调队列使用双端队列来实现
        self.Q = deque()

    # 单调递减队列新元素入队
    def push(self, val):
        while self.Q and self.Q[-1] < val:
            # 队尾元素比新元素小,队尾元素出队
            self.Q.pop()
        # 新元素加入队尾
        self.Q.append(val)

    # 单调递减队首元素出队
    def pop(self, val):
        # 比较队首元素与要出队元素
        if self.Q and self.Q[0] == val:
            self.Q.popleft()

    def maxSlidingWindow(self, nums, k):
        res = []
        for i in range(len(nums)):
            self.push(nums[i])
            if i < k - 1:
                continue
            res.append(self.Q[0])
            self.pop(nums[i - k + 1])

        return res


if __name__ == '__main__':
    nums = [1, 3, -1, -3, 5, 3]
    k = 3
    s = Solution()
    print(s.maxSlidingWindow(nums, k))
'''
0620 滑动窗口最大值
数组实现单调队列
1.单调递减入队
2.将前k个元素全部入队
3.第k+1元素时,将队首元素放入结果集中
4.第i-k+1的元素出队
'''


class Solution(object):

    def maxSlidingWindow(self, nums, k):
        # 如果列表为空,返回空数组
        if not nums or len(nums) == 0 or k == 0:
            return []
        # 如果滑动窗口大于数组的长度,返回数组的最大值
        if k > len(nums):
            return [max(nums)]

        q = []  # 单调递减队列
        res = []  # 保存结果

        for i in range(len(nums)):
            while len(q) > 0 and q[-1] < nums[i]:
                q.pop()  # 删除队尾元素 保证单调性
            q.append(nums[i])
            # 前k个元素全部入队列
            if i < k - 1:
                continue
            # 到第k+1的元素的时候,取队首元素放入结果数组中
            res.append(q[0])
            # 删除第i-k+1,如果和队首元素相同删除,如果不同,不操作
            if nums[i - k + 1] == q[0]:
                q.pop(0)  # 删除队首元素

        return res


if __name__ == '__main__':
    nums = [1, 3, -1, -3, 5, 3]
    k = 3
    s = Solution()
    print(s.maxSlidingWindow(nums, k))
'''
0620 循环队列实现滑动窗口最大值
'''


class Queue(object):
    def __init__(self, cap):
        self.cap = cap
        self.head = 0
        self.tail = 0
        self.used = 0
        self.q = [0] * cap

    def backIndex(self):
        return (self.tail - 1 + self.cap) % self.cap

    def push(self, val):
        while self.used > 0 and self.q[self.backIndex()] < val:
            self.tail = self.backIndex()
            self.used -= 1
        self.q[self.tail] = val
        self.tail = (self.tail + 1) % self.cap
        self.used += 1

    def pop(self, val):
        if self.used > 0 and self.q[self.head] == val:
            self.head = (self.head + 1) % self.cap
            self.used -= 1

    def front(self):
        return self.q[self.head]


class Solution(object):
    def maxSlidingWindow(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        if not nums or len(nums) < k:
            return []

        Q = Queue(k + 1)

        ans = []
        for i in range(0, len(nums)):
            Q.push(nums[i])
            if i < k - 1:
                continue

            ans.append(Q.front())

            Q.pop(nums[i - k + 1])

        return ans

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值