大家好呀,又见面了,本次更新栈和队列,有不懂的小伙伴可以驻足学习,本文有错误之处请指出,不胜感激!
下面进入正文:
栈
线性表和栈都是常见的数据结构,在计算机科学中应用广泛。下面是线性表栈的知识点:
线性表是一种数据结构,可以用数组或链表实现。它是由一组元素组成的有序序列,这些元素按照线性顺序排列。
线性表支持的基本操作包括插入、删除和查找等,其中查找操作可以按照元素的位置或者值进行。
栈是一种特殊的线性表,它的插入和删除操作只能在栈顶进行。栈的特性是先进后出(LIFO),最后进入的元素先被删除。
栈有两种实现方式,一种是基于数组的实现,称为顺序栈;另一种是基于链表的实现,称为链式栈。
栈的基本操作包括入栈和出栈,其中入栈操作是将一个元素压入栈顶,出栈操作是将栈顶元素弹出。
栈还有一个常用的操作是查看栈顶元素,即返回栈顶元素但不弹出。
栈的应用场景非常广泛,比如表达式求值、括号匹配、函数调用栈等。
栈(Stack)是一种线性数据结构,它的特点是“先进后出”,即最后一个进入栈的元素,会成为第一个弹出栈的元素。栈是一种限定插入和删除操作的线性表,插入和删除操作只能在栈顶进行。
栈通常用于进行表达式求值、递归算法等领域。在计算机系统中,栈被广泛应用,比如程序的调用栈,操作系统中的进程栈等等。
栈有两种基本操作:入栈和出栈。入栈就是向栈顶位置插入一个元素,出栈就是从栈顶位置弹出一个元素。栈还有一个很重要的性质是空间效率高,因为它不需要像链表一样保存额外的指针来表示节点间的关系,只需要一个指向栈顶元素的指针即可。
栈的实现方式有多种,最常见的是使用数组或链表来实现。使用数组实现的栈叫做顺序栈,使用链表实现的栈叫做链式栈。在实际应用中,需要根据具体情况来选择不同的实现方式。
顺序栈
顺序表和链式表都是数据结构中的线性表,用来存储一组相同类型的数据元素,具有前驱后继关系。它们的主要区别在于存储方式的不同。
顺序表是用一段连续的物理存储单元来存储线性表的,也就是说,它的数据元素在内存中是顺序存储的。顺序表可以随机访问,即通过元素的下标来访问,因此访问速度非常快。但是在插入和删除元素时,需要移动大量的数据,因此时间复杂度较高。
以下来用python实现顺序栈:
class SqStack(object):
def __init__(self, maxsize=None):
self.maxsize = maxsize
self.stack = [] # 存储栈元素的列表,初始化为空列表
self.top = -1 # 栈顶指针初始化为-1
def __len__(self):
return len(self.stack)
def is_empty(self):
return self.top == -1
def is_full(self):
return len(self.stack) == self.maxsize
def push(self, value):
if self.is_full():
raise Exception('Stack is full')
else:
self.stack.append(value) # 将新元素压入栈顶
self.top += 1 # 栈顶指针加1
def pop(self):
if self.is_empty():
raise Exception('Stack is empty')
else:
self.top -= 1 # 栈顶指针减1
return self.stack.pop() # 弹出栈顶元素
def peek(self):
if self.is_empty():
return None
else:
return self.stack[self.top] # 返回栈顶元素
链式栈
链式表是通过一些结点来存储线性表的,每个结点包含一个数据元素和一个指向下一个结点的指针。由于链式表的结点不一定是连续的,因此不支持随机访问,必须从表头开始遍历整个链表才能找到目标结点。在插入和删除元素时,只需要改变指针的指向,因此时间复杂度较低。
实现:
class Node(object):
def __init__(self, value=None, next=None):
self.value = value
self.next = next
class LinkedStack(object):
def __init__(self):
self.top = None
def is_empty(self):
return self.top is None
def push(self, value):
self.top = Node(value=value, next=self.top) # 将新元素作为新的栈顶
def pop(self):
if self.is_empty():
raise Exception('Stack is empty')
else:
value = self.top.value # 取出栈顶元素的值
self.top = self.top.next # 栈顶指针下移一位
return value # 返回栈顶元素的值
def peek(self):
if self.is_empty():
return None
else:
return self.top.value # 返回栈顶元素的值
在实际应用中,顺序表和链式表的选择取决于具体的场景和需求。如果需要随机访问元素的时间尽可能短,那么顺序表是一个不错的选择;如果需要经常插入和删除元素,那么链式表更加适合。当然,有些情况下需要综合考虑,比如需要支持高效的随机访问同时又需要频繁的插入和删除操作,这时可以采用其他的数据结构,如平衡树等。
队列(Queue)
队列(Queue)是一种线性数据结构,具有先进先出(First In First Out,FIFO)的特点。与栈不同的是,队列只允许在队尾插入元素,在队头删除元素。
在队列中,我们通常称添加元素的操作为入队(enqueue),删除元素的操作为出队(dequeue)。同时,队列还有一个重要的概念——队头(front)和队尾(rear)。
队头是指队列中的第一个元素,也就是将要被删除的元素;队尾是指队列中的最后一个元素,也就是将要被添加的元素。
队列通常有两种实现方式,一种是顺序队列,一种是链式队列。
顺序队列的底层实现是一个数组,数组中的每一个元素代表队列中的一个元素,队列头指针 front 和队列尾指针 rear 分别指向队头和队尾元素的下标。顺序队列的特点是随机访问快,但插入和删除的时间复杂度较高。
链式队列的底层实现是一个链表,队列头指针 front 和队列尾指针 rear 分别指向链表的头和尾节点。链式队列的特点是插入和删除的时间复杂度较低,但随机访问较慢。
队列常见的应用场景包括任务调度、消息传递、缓存等。
除了上述的应用场景,队列还可以用于:
多线程编程中的线程安全队列。比如Python中的queue模块提供了队列的线程安全实现,可以用于多线程编程中的任务分发、任务汇总等场景。
数据结构中的广度优先搜索。在图的遍历过程中,广度优先搜索可以使用队列实现,从而实现对图的层次遍历。
模拟等待队列。比如在操作系统中,当多个进程或线程同时需要访问共享资源时,可以使用队列来实现等待队列,从而保证资源的公平分配。
事件处理器。在事件驱动编程中,事件处理器可以使用队列实现。当事件触发时,将事件添加到队列中,由事件处理器依次处理队列中的事件。
总之,队列是一种非常常用的数据结构,在计算机程序设计和算法实现中都具有广泛的应用场景。
普通队列(Queue)
普通队列是一种先进先出(FIFO)的数据结构,可以通过数组或链表来实现。在队列中,数据只能从队尾进入队列,从队头出队。队列通常用于任务调度、消息传递、缓存等场景。
下面是一个使用 Python 实现的普通队列的代码,其中包括一些注释和解释:
class Queue:
def __init__(self):
self.items = []
def is_empty(self):
"""检查队列是否为空"""
return self.items == []
def enqueue(self, item):
"""将元素添加到队列尾部"""
self.items.append(item)
def dequeue(self):
"""从队列头部移除元素并返回"""
return self.items.pop(0)
def size(self):
"""返回队列中元素个数"""
return len(self.items)
双端队列(Deque)
双端队列是一种允许从队列两端添加或移除元素的数据结构。双端队列通常通过数组或链表来实现,可以在队列的两端添加和删除元素。
下面是一个使用 Python 实现的双端队列的代码,其中包括一些注释和解释:
class Deque:
def __init__(self):
self.items = []
def is_empty(self):
"""检查队列是否为空"""
return self.items == []
def add_front(self, item):
"""将元素添加到队列前面"""
self.items.insert(0, item)
def add_rear(self, item):
"""将元素添加到队列尾部"""
self.items.append(item)
def remove_front(self):
"""从队列头部移除元素并返回"""
return self.items.pop(0)
def remove_rear(self):
"""从队列尾部移除元素并返回"""
return self.items.pop()
def size(self):
"""返回队列中元素个数"""
return len(self.items)
阻塞队列(BlockingQueue)
阻塞队列是一种允许多个线程同时操作的队列。在阻塞队列中,如果队列为空,则获取元素的线程会被阻塞,直到队列中有新的元素。如果队列已满,则添加元素的线程会被阻塞,直到队列中有空闲位置。
下面是一个使用 Python 实现的阻塞队列的代码,其中包括一些注释和解释:
class BlockingQueue:
def __init__(self, maxsize=0):
self.queue = Queue(maxsize) # 初始化一个Queue队列对象
def put(self, item):
"""将元素添加到队列尾部,如果队列已满则阻塞"""
self.queue.put(item) # 调用Queue对象的put方法将元素添加到队列中,如果队列已满则会阻塞等待
def get(self):
"""从队列头部取出一个元素,如果队列为空则阻塞"""
return self.queue.get() # 调用Queue对象的get方法从队列头部取出一个元素,如果队列为空则会阻塞等待
井发队列的实现,以及阻塞井发队列的实现
class BurstQueue:
def __init__(self, maxsize=0):
self.queue = Queue(maxsize)
def put(self, items):
"""将元素列表一次性添加到队列尾部"""
for item in items:
self.queue.put(item, block=False)
def get(self, size):
"""从队列头部一次性取出指定数量的元素"""
items = []
for i in range(size):
try:
items.append(self.queue.get(block=False))
except Empty:
break
return items
class BlockingBurstQueue:
def __init__(self, maxsize=0):
self.queue = Queue(maxsize)
def put(self, items):
"""将元素列表一次性添加到队列尾部,如果队列已满则阻塞"""
for item in items:
self.queue.put(item, block=True)
def get(self, size):
"""从队列头部一次性取出指定数量的元素,如果队列为空则阻塞"""
items = []
for i in range(size):
items.append(self.queue.get(block=True))
return items
这里实现的是一个井发队列,它可以一次性将多个元素添加到队列尾部,也可以一次性从队列头部取出指定数量的元素。在实现中,我们依然使用了Python内置的Queue模块,put方法中使用了for循环遍历items列表,并调用Queue对象的put方法将元素逐个添加到队列尾部。在get方法中,我们使用了for循环从队列头部一次性取出指定数量的元素,并将它们存放到一个列表中返回。如果队列中没有足够的元素可以取出,那么get方法会在取够指定数量的元素之前一直等待。
接下来是阻塞井发队列的实现。这个队列在井发队列的基础上,增加了阻塞的特性,如果队列已满则put方法会阻塞等待,如果队列为空则get方法会阻塞等待。在实现中,我们依然使用了Python内置的Queue模块,并将block参数设置为True,表示如果队列已满或者为空,则会阻塞等待。这样就实现了一个阻塞井发队列。
以上便是数据结构有关线性表的相关知识点与实现,见到即是缘分留个关注吧,下期更新树的相关内容。感谢大家的支持!