栈与队列--python

一、栈

1、概述

一种先入后出的线性数据结构,类似于叠盘子,先放下的盘子得最后才能拿到。在最上面的盘子我们称为栈顶,在最底下的盘子我们称为栈底,将盘子添加到栈顶的操作叫做入栈,将盘子从栈顶抽走的操作叫做出栈

将上述的盘子替换为元素,就是我们常说的栈了。

2、常见操作

常见的操作一般是入栈出栈访问栈顶元素

# 初始化一个栈
stack: list[int] = []

# 元素入栈
stack.append(1)
stack.append(2)
stack.append(3)
stack.append(4)
stack.append(5)
stack.append(6)

# 访问栈顶元素
peek: int = stack[-1]

# 元素出栈
pop: int = stack.pop()

# 获取栈的长度
size: int = len(stack)

# 判空
is_empty: bool = len(stack) == 0

3、实现

因为栈遵循先入后出的原则,因此我们只能对栈顶的元素进行操作,包括添加、删除动作,而我们熟悉的两种数据结构都可以在任意的位置添加和删除元素,所以我们在模拟栈的时候,一般将其功能做一定的限制,将栈不能实现的功能给禁用掉,使他对外表现的逻辑符合栈的特性。

(一)链表实现

概述

在用链表实现时,我们可以用链表的头节点作为栈顶,尾节点作为栈底。入栈时,我们只需要将元素加入到链表头部,出栈时,我们只需要将元素从链表头部删除。

例如

class ListNode():
    def __init__(self, val):
        self.val = val
        self.next : ListNode | None = None
        self._size = 0


# 基于链表实现栈的效果,链表需要提前定义好
class LinkListStack():
    def __init__(self):
        self._head: ListNode | None = None
        self._size: int = 0


    # 获得栈的长度
    def get_size(self) -> int:
        return self._size


    # 判断栈是否为空
    def is_empty(self) -> bool:
        return self._size == 0


    # 入栈
    def push_ele(self, val):
        node = ListNode(val)
        node._head = node
        node._size += 1


    # 栈顶元素
    def head(self):
        if self.is_empty():
            raise IndexError('栈为空,无元素')
        return self._head.val


    # 出栈
    def pop_ele(self):
        num = self.head()
        self._head = self._head.next
        self._size -= 1
        return num

    # 转化为列表用于打印
    def to_list(self):
        arr = []
        node = self._head
        while node:
            arr.append(node.val)
            node = node.next
        arr.reverse()
        return arr

(二)数组实现

概述

使用数组实现栈,可以将数组的结尾作为栈顶,入栈就是在尾部加入一个元素,出栈就是在尾部删除一个元素。

代码

# 数组实现
class ArrayStack():
    # 定义数组
    def __init__(self):
        self._stack: list[int] = []

    # 查询长度
    def size(self):
        return len(self._stack)

    # 判空
    def is_empty(self):
        return self.size() == 0

    # 入栈
    def get_push(self, item):
        self._stack.append(item)

    # 出栈
    def get_pop(self):
        if self.is_empty():
            raise IndexError('栈为空,无元素')
        return self._stack.pop()

    # 获得栈顶元素
    def head(self):
        if self.is_empty():
            raise IndexError('栈为空,无元素')
        return self._stack[-1]

    # 打印
    def to_list(self):
        return self._stack

二、队列

1、概述

队列是一种先入先出的线性数据结构,类似于我们生活中的排队,先排队的人先离开,后排队的人后离开。队伍的头部我们称为队首,队伍的尾部我们称为队尾,加入队伍尾部我们称为入队,删除队伍头部我们称为出队

2、常见操作

一般是元素入队元素出队访问队首元素

因为python中自带了双向队列,所以我们直接引用双向队列来模拟队列。

from collections import deque
# 初始化
que = deque()

que.append(1)
que.append(2)
que.append(3)
que.append(4)
que.append(5)
# 队首元素
first = que[0]
# 元素出队
pop = que.popleft()
# 长度
size = len(que)
# 判空
is_empty = (len(que) == 0)

3、实现

(一)、链表实现

概述

链表的头结点表示队首,链表的尾结点表示队尾。队尾只能添加元素,队首只能删除元素。

代码

# 定义链表
class ListNode():
    def __init__(self, val):
        self.val = val
        self.next : ListNode | None = None
        self._size = 0

# 链表实现
class LinkListQueue():
    def __init__(self):
        self._front: ListNode | None = None
        self._rear: ListNode | None = None
        self._size: int = 0

    # 获取长度
    def size(self):
        return self._size

    # 判空
    def is_empty(self):
        return self._size == 0

    # 入队
    def get_push(self, num):
        # 在尾结点后加
        node = ListNode(num)
        # 如果本身是空的,则头尾都指向该元素
        if self._front is None:
            self._front = node
            self._rear = node
        # 如果队列不是空,则加到尾结点
        else:
            self._rear.next = node
            self._rear = node
        self._size += 1

    # 出队
    def get_pop(self):
        num = self.head()
        self._front = self._front.next
        self._size -= 1
        return num

    # 队首元素
    def head(self):
        if self.is_empty():
            raise IndexError('队列为空')

    # 转为列表输出
    def to_list(self):
        queue = []
        tmp = self._front
        while self._front:
            queue.append(tmp.val)
            tmp = tmp.next
        return queue

(二)数组实现

概述

数组删除元素不如链表方便,时间复杂度在O(n),我们可以采用一种取巧的方式来避免这种情况,也就是设置两个指针,front和rear,分别指向队列的首个元素和最后一个元素。这样的话可以实现在删除时,通过直接移动队首指针,不体现删除元素的方式来模拟队列。

代码

class ArrayQueue():
    def __init__(self, size):
        self._nums: list[int] = [0] * size
        self._front: int = 0
        self._size: int = 0

    # 获取队列的容量
    def how_many(self):
        return self._size

    # 获取队列的长度
    def size(self):
        return self._size

    # 判空
    def is_empty(self):
        return self._size == 0

    # 入队
    def get_push(self, num):
        if self._size == self.how_many():
            raise IndexError('队列已经满了嗷~')
        rear = (self._front + self._size) % self.how_many()
        self._nums[rear] = num
        self._size += 1

    # 出队
    def get_pop(self):
        num = self.head()
        self._front = (self._front + 1) % self.how_many()
        self._size -= 1
        return num

    # 获得队首
    def head(self):
        if self.is_empty():
            raise IndexError('队列是空的嗷~')
        return self._nums[self._front]

    # 输出
    def to_list(self):
        res = [0] * self.size()
        j = self._front
        for i in range(self.size()):
            res[i] = self._nums[(j % self.how_many())]
            j += 1
        return res

三、双向队列

1、概述

队列中我们只能,对队列的队首做删除,对队尾做添加动作,而双向队列更加灵活,可以对队首或者队尾做删除或者添加动作。

2、常见操作

获取队首元素获取队尾元素删除队首元素删除队尾元素增加队首元素增加队尾元素

# 双向队列
deq = deque()
# 添加至队尾
deq.append(1)       
deq.append(2)
# 添加至队首
deq.appendleft(3)   
deq.appendleft(4)
# 队首元素
front = deq[0]      
# 队尾元素
rear = deq[-1]      
# 队首出队
get_pop_front = deq.popleft() 
# 队尾出队
get_pop_rear = deq.pop()      
# 获取长度
lenth = len(deq)  
# 判空
is_empty: bool = (len(deq) == 0) 

3、实现

(一)、链表实现

# 双向队列--链表实现
# 创建链表结点
class ListNode():
    def __init__(self, val):
        self.val = val
        self.next : ListNode | None = None
        self.prev : ListNode | None = None
        self._size = 0


class LinkListDeque():
    # 定义结点
    def __init__(self):
        self._front: ListNode | None = None
        self._rear: ListNode | None = None
        self._size = 0

    # 长度
    def size(self):
        return self._size

    # 判空
    def is_empty(self):
        return self._size == 0

    # 入队
    def get_push(self, num, is_front):
        node = ListNode(num)
        if self.is_empty():
            self._front = self._rear = node
        elif is_front:
            self._front.next = node
            node.next = self._front
            self._front = node
        else:
            self._rear.next = node
            node.prev = self._rear
            self._rear = node
        self._size += 1

    # 队首入队
    def get_push_front(self, num):
        self.get_push(num, True)

    # 队尾入队
    def get_push_rear(self, num):
        self.get_push(num, False)

    # 出队
    def get_pop(self, is_front):
        if self.is_empty():
            raise IndexError('双向队列为空~')
        if is_front:
            val = self._front.val
            fnext: ListNode | None = self._front.next
            if fnext != None:
                fnext.prev = None
                self._front.next = None
            self._front = fnext
        else:
            val = self._rear.val
            rprev: ListNode | None = self._rear.prev
            if rprev != None:
                rprev.prev = None
                self._rear.next = None
            self._rear = rprev
        self._size -= 1
        return val

    # 队首出队
    def get_pop_front(self):
        return self.get_pop(True)

    # 队尾出队
    def get_pop_rear(self):
        return self.get_pop(False)

    # 获得队首
    def peek_front(self):
        if self.is_empty():
            raise IndexError('双向队列为空~')
        return self._front.val

    # 获得队尾
    def peek_rear(self):
        if self.is_empty():
            raise IndexError('双向队列为空~')
        return self._rear.val

    # 返回打印
    def to_array(self):
        node = self._front
        res = [0] * self.size()
        for i in range(self.size()):
            res[i] = node.val
            node = node.next
        return res

(二)、数组实现

# 环形数组实现双向队列
class ArrayDeque():
    def __init__(self, how_many):
        self._nums = [0] * how_many
        self._front = 0
        self._size = 0

    # 容量
    def how_many(self):
        return len(self._nums)

    # 大小
    def size(self):
        return self._size

    # 判空
    def is_empty(self):
        return self._size == 0

    # 获取当前位置
    def index(self, i):
        res = (i + self.how_many()) % self.how_many()
        return res

	# 加入队首
    def get_push_front(self, num):
        if self._size == self.how_many():
            print('双向队列满了~')
            return
        self._front = self.index(self._front - 1)
        self._nums[self._front] = num
        self._size += 1

	# 加入队尾
    def get_push_rear(self, num):
        if self._size == self.how_many():
            print('双向队列满了~')
            return
        rear = self.index(self._front + self._size)
        self._nums[rear] = num
        self._size += 1

	# 删除队首
    def get_pop_front(self):
        num = self.peek_front()
        self._front = self.index(self._front + 1)
        self._size -= 1
        return num
	
	# 删除队尾
    def get_pop_rear(self):
        num = self.peek_rear()
        self._size -= 1
        return num
	
	# 获得队首
    def peek_front(self):
        if self.is_empty():
            raise IndexError('双向队列为空~')
        return self._nums[self._front]

	# 获得队尾
    def peek_rear(self):
        if self.is_empty():
            raise IndexError('双向队列为空~')
        rear = self.index(self._front + self._size - 1)
        return self._nums[rear]

	# 做数组输出
    def to_array(self):
        res = []
        for i in range(self._size):
            res.append(self._nums[self.index(self._front + i)])
        return res
  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值