数据结构与算法 栈与队列

简介: 数据结构与算法 栈与队列

基于数组的实现

class ArrayStack:
    def __init__(self) -> None:
        self.__stack = []
        
    def size(self):
        return len(self.__stack)
        
    def is_empty(self):
        if self.size() == 0:
            return True
        else:
            return False
    def push(self, val):
        self.__stack.append(val)
    def pop(self):
        if self.is_empty():
            raise IndexError('栈中无数据')
        else:
            return self.__stack.pop(-1)
    def peek(self):
        if self.is_empty():
            raise IndexError('栈中无数据')
        else:
            return self.__stack[-1]
    def to_list(self):
        return self.__stack

基于链表的实现

class ListNode:
    def __init__(self, value) -> None:
        self.val = value
        self.next = None
class ListStack:
    def __init__(self) -> None:
        self.__peek = None
        self.__size = 0
    def size(self):
        return self.__size
    def is_empty(self):
        if self.__peek == None:
            return True
        else:
            return False
    def push(self, val):
        node = ListNode(val)
        if self.is_empty():
            self.__peek = node
        else:
            stack_next = self.__peek
            self.__peek = node
            self.__peek.next = stack_next
            self.__size += 1
    def pop(self):
        if self.is_empty():
            raise IndexError('栈中无数据')
        else:
            pop_listnode = self.__peek
            self.__peek = self.__peek.next
            return pop_listnode.val
    def peek(self):
        if self.is_empty():
            raise IndexError('栈中无数据')
        else:
            return self.__peek.val
    def to_list(self):
        lst = []
        peek = self.__peek
        while peek:
            lst.append(peek.val)
            peek = peek.next
        lst.reverse()
        return lst

两种类型栈的区别

  • 时间效率
  • 基于数组实现的栈在触发扩容时效率会降低,但由于扩容是低频操作,因此平均效率更高。
  • 基于链表实现的栈可以提供更加稳定的效率表现。
  • 空间效率
  • 基于数组实现的栈可能造成一定的空间浪费。
  • 由于链表节点需要额外存储指针,因此链表节点占用的空间相对较大。
  • 我们不能简单地确定哪种实现更加节省内存,需要针对具体情况进行分析。

队列

基于数组的实现

class ArrayQueue:
    def __init__(self) -> None:
        self.__queue = []
        self.__size = 0
    def size(self):
        return self.__size
        
    def is_empty(self):
        if self.size() == 0:
            return True
        else:
            return False
    def push(self, val):
        self.__queue.append(val)
        self.__size += 1
    def pop(self):
        if self.is_empty():
            raise IndexError('队列无数据')
        else:
            val = self.__queue.pop(0)
            self.__size -= 1
            return val
            
    def to_list(self):
        return self.__queue

基于链表的实现

class ListNode:
    def __init__(self, value) -> None:
        self.val = value
        self.next = None
class ListQueue:
    def __init__(self) -> None:
        self.__front = None
        self.__rear = None
        self.__size = 0
    def size(self):
        return  self.__size
    def is_empty(self):
        if self.size() == 0:
            return True
        else:
            return False
    def push(self, value):
        node = ListNode(value)
        if self.is_empty():
            self.__front = node
            self.__rear = node
        else:
            self.__rear.next = node
            self.__rear = node
        self.__size += 1
    def pop(self):
        if self.is_empty():
            raise IndexError('队列无数据')
        else:
            node = self.__front
            self.__front = self.__front.next
            self.__size -= 1
            return node.val
    def to_list(self):
        lst = []
        node = self.__front
        while node:
            lst.append(node.val)
            node = node.next
        return lst

双向队列

基于数组的实现

class ArrayDeque:
    def __init__(self) -> None:
        self.__deque = []
        self.__size = 0
  
    def size(self):
        return self.__size
        
    def is_empty(self):
        if self.size() == 0:
            return True
        else:
            return False
    def push(self, val, where):
        if where == 'front':
            self.__deque.insert(0, val)
        elif where == 'rear':
            self.__deque.insert(-1, val)
        self.__size += 1
    def pop(self, where):
        if self.is_empty():
            raise IndexError('队列无数据')
        else:
            if where == 'front':
                val = self.__deque.pop(0)
            elif where == 'rear':
                val = self.__deque.pop(-1)
            self.__size -= 1
            return val
    def to_list(self):
        return self.__deque

基于链表的实现

class ListNode:
    def __init__(self, value) -> None:
        self.val = value
        self.next = None
        self.prev = None
class ListDeque:
    def __init__(self) -> None:
        self.__front = None
        self.__rear = None
        self.__size = 0
    def size(self):
        return self.__size
    def is_empty(self):
        if self.size() == 0:
            return True
        else:
            return False
    def push(self, value, where):
        node = ListNode(value)
        if self.is_empty():
            self.__front = node
            self.__rear = node
        else:
            if where == 'front':
                self.__front.prev = node
                node.next = self.__front
                self.__front = node
            elif where == 'rear':
                self.__rear.next = node
                node.prev = self.__rear
                self.__rear = node
        self.__size += 1
    def pop(self, where):
        if self.is_empty():
            raise IndexError('队列无数据')
        else:
            if where == 'front':
                node = self.__front.next
                if node:
                    self.__front.next = None
                    self.__front = node
                    self.__front.prev = None
            elif where == 'rear':
                node = self.__rear.prev
                if node:
                    self.__rear.prev = None
                    self.__rear = node
                    self.__rear.next = None
        self.__size -= 1
    def to_list(self):
        lst = []
        node = self.__front
        while node:
            lst.append(node.val)
            node = node.next
        return lst

重点回顾

  • 栈是一种遵循先入后出原则的数据结构,可通过数组或链表来实现。
  • 从时间效率角度看,栈的数组实现具有较高的平均效率,但在扩容过程中,单次入栈操作的时间复杂度会降低至 𝑂(𝑛) 。相比之下,基于链表实现的栈具有更为稳定的效率表现。
  • 在空间效率方面,栈的数组实现可能导致一定程度的空间浪费。但需要注意的是,链表节点所占用的内存空间比数组元素更大。
  • 队列是一种遵循先入先出原则的数据结构,同样可以通过数组或链表来实现。在时间效率和空间效率的对比上,队列的结论与前述栈的结论相似。
  • 双向队列是一种具有更高自由度的队列,它允许在两端进行元素的添加和删除操作。


目录
相关文章
|
6月前
|
前端开发 Java
java实现队列数据结构代码详解
本文详细解析了Java中队列数据结构的实现,包括队列的基本概念、应用场景及代码实现。队列是一种遵循“先进先出”原则的线性结构,支持在队尾插入和队头删除操作。文章介绍了顺序队列与链式队列,并重点分析了循环队列的实现方式以解决溢出问题。通过具体代码示例(如`enqueue`入队和`dequeue`出队),展示了队列的操作逻辑,帮助读者深入理解其工作机制。
178 1
|
4月前
|
编译器 C语言 C++
栈区的非法访问导致的死循环(x64)
这段内容主要分析了一段C语言代码在VS2022中形成死循环的原因,涉及栈区内存布局和数组越界问题。代码中`arr[15]`越界访问,修改了变量`i`的值,导致`for`循环条件始终为真,形成死循环。原因是VS2022栈区从低地址到高地址分配内存,`arr`数组与`i`相邻,`arr[15]`恰好覆盖`i`的地址。而在VS2019中,栈区先分配高地址再分配低地址,因此相同代码表现不同。这说明编译器对栈区内存分配顺序的实现差异会导致程序行为不一致,需避免数组越界以确保代码健壮性。
75 0
栈区的非法访问导致的死循环(x64)
232.用栈实现队列,225. 用队列实现栈
在232题中,通过两个栈(`stIn`和`stOut`)模拟队列的先入先出(FIFO)行为。`push`操作将元素压入`stIn`,`pop`和`peek`操作则通过将`stIn`的元素转移到`stOut`来实现队列的顺序访问。 225题则是利用单个队列(`que`)模拟栈的后入先出(LIFO)特性。通过多次调整队列头部元素的位置,确保弹出顺序符合栈的要求。`top`操作直接返回队列尾部元素,`empty`判断队列是否为空。 两题均仅使用基础数据结构操作,展示了栈与队列之间的转换逻辑。
|
9月前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
365 77
|
8月前
|
算法 调度 C++
STL——栈和队列和优先队列
通过以上对栈、队列和优先队列的详细解释和示例,希望能帮助读者更好地理解和应用这些重要的数据结构。
189 11
|
8月前
|
DataX
☀☀☀☀☀☀☀有关栈和队列应用的oj题讲解☼☼☼☼☼☼☼
### 简介 本文介绍了三种数据结构的实现方法:用两个队列实现栈、用两个栈实现队列以及设计循环队列。具体思路如下: 1. **用两个队列实现栈**: - 插入元素时,选择非空队列进行插入。 - 移除栈顶元素时,将非空队列中的元素依次转移到另一个队列,直到只剩下一个元素,然后弹出该元素。 - 判空条件为两个队列均为空。 2. **用两个栈实现队列**: - 插入元素时,选择非空栈进行插入。 - 移除队首元素时,将非空栈中的元素依次转移到另一个栈,再将这些元素重新放回原栈以保持顺序。 - 判空条件为两个栈均为空。
|
9月前
|
存储 C++ 索引
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
【数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】初始化队列、销毁队列、判断队列是否为空、进队列、出队列等。本关任务:编写一个程序实现环形队列的基本运算。(6)出队列序列:yzopq2*(5)依次进队列元素:opq2*(6)出队列序列:bcdef。(2)依次进队列元素:abc。(5)依次进队列元素:def。(2)依次进队列元素:xyz。开始你的任务吧,祝你成功!(4)出队一个元素a。(4)出队一个元素x。
292 13
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
|
8月前
|
缓存 监控 算法
内网监控管理软件:PHP 语言队列算法揭秘
在数字化办公环境中,内网监控管理软件对企业的稳定运行和信息安全至关重要。本文深入介绍PHP中的队列算法及其在内网监控软件中的应用,包括监控数据收集、任务调度和日志记录等场景,通过代码示例展示其实现方法。队列算法可提高性能、保证数据顺序并实现异步处理,为企业提供高效的安全保障。
105 1
|
9月前
|
C++
【C++数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】
【数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】(1)遇到左括号:进栈Push()(2)遇到右括号:若栈顶元素为左括号,则出栈Pop();否则返回false。(3)当遍历表达式结束,且栈为空时,则返回true,否则返回false。本关任务:编写一个程序利用栈判断左、右圆括号是否配对。为了完成本关任务,你需要掌握:栈对括号的处理。(1)遇到左括号:进栈Push()开始你的任务吧,祝你成功!测试输入:(()))
204 7
|
20天前
|
传感器 机器学习/深度学习 编解码
MATLAB|主动噪声和振动控制算法——对较大的次级路径变化具有鲁棒性
MATLAB|主动噪声和振动控制算法——对较大的次级路径变化具有鲁棒性
137 3

热门文章

最新文章