1.数组
优点:
- 索引操作速度快:通过索引可以直接访问元素,因此索引操作的时间复杂度是 $O(1)$,即常数级
缺点:
- 插入、删除元素慢: 如果需要在中间或开始位置插入或删除元素,可能需要移动大量元素,因此这样的操作的时间复杂度是$O(n)$
- 预先设置空间大小: 数组通常需要预先设置空间大小,这意味着在创建时需要估计数据的大小,并为其分配足够的内存空间。如果数组大小不够,可能需要重新分配内存并复制数据,这会带来额外的开销。如果数组太多,浪费空间
需要的参数:数组名称,大小,采用索引进行各种操作
2.链表
优点:
- 不需要预先知道数据大小,实现灵活的内存动态管理
- 插入、删除指定数据速度快
缺点:
- 读取指定位置数据速度慢
- 空间开销比较大
分类
单向链表
链表中最简单的一种是单向链表,它包含两个域,一个信息域和一个指针域。这个链接指向列表中的下一个节点,而最后一个节点则指向一个空值
需要的参数:节点的值,节点的后一个节点
循环链表(环形链表)
在一个循环链表中, 首节点和末节点被连接在一起,要遍历一个循环链表,可以开始于任意一个节点然后沿着列表的任一方向直到返回开始的节点
双向链表
一种更复杂的链表是"双向链表"或"双面链表",每个节点有两个连接:一个指向前一个节点,(当此"连接"为第一个"连接"时,指向空值或者空列表);而另一个指向下一个节点, (当此“连接”为最后一个“连接”时,指向空值或者空列表)
需要的参数:节点的值,节点的前一个节点,节点的后一个节点
3.栈
特点:
- 先入后出,后入先出
- 除头尾节点之外,每个元素有一个前驱,一个后继
栈的结构是先进后出,类似于子弹的弹夹, 计算机结构如图:
4.队列
特点:
队列(queue)是一种遵循先入先出规则的线性数据结构,只允许在有序的线性结构集合的一端(队尾)进行加入数据(push)和 另一端(队首)移除数据(pop)的运算。
- 先入先出,后入后出
- 除头尾节点之外,每个元素有一个前驱,一个后继
5.双向对列
双向队列 ,就是在队列的基础上增加一个双端操作的功能。允许在头部和尾部执行元素的添加或删除操作
栈,队列,双向队列都可以用数组和链表表示
6.各种实现代码
6.1单链表
class ListNode:def __init__(self,val:int):self.val=valself.next=None
class MyLinkNode:def __init__(self):self.size=0self.head=ListNode(0)def add_index(self,val:int,index:int):if index>self.size:return -1index=max(0,index)add_node=ListNode(val)pre=self.headfor _ in range(index):pre=pre.nextadd_node.next=pre.nextpre.next=add_nodeself.size+=1def add_head(self,val:int):self.add_index(val,0)def add_tail(self,val:int):self.add_index(val,self.size)def get(self,index:int):if index<0 or index>=self.size:return -1pred=self.headfor _ in range(index+1):pred=pred.nextreturn pred.valdef delete(self,index:int):if index<0 or index>=self.size:return -1pred=self.headfor _ in range(index):pred=pred.nextpred.next=pred.next.nextself.size-=1def traverse(self):cur=self.head.nextwhile cur:print(cur.val)cur=cur.next
if __name__=='__main__':link=MyLinkNode()link.add_tail(1)link.add_tail(2)link.add_tail(3)link.add_tail(4)link.add_index(8,2)link.delete(3)link.traverse()
6.2双向链表
class ListNode:def __init__(self,val):self.val=valself.next=Noneself.pre=None
class MyListNode:def __init__(self):self.head=ListNode(0)self.tail=ListNode(0)self.head.next=self.tailself.tail.pre=self.headself.size=0def add_index(self,index:int,val:int):if index>self.size:return -1else:if index<self.size-index:pred=self.headfor _ in range(index):pred=pred.nextsucc=pred.nextelse:succ=self.tailfor _ in range(self.size-index):succ=succ.prepred=succ.preadd_node=ListNode(val)add_node.next=succadd_node.pre=predpred.next=add_nodesucc.pre=add_nodeself.size+=1def add_head(self,val):self.add_index(0,val)def add_tail(self,val):self.add_index(self.size,val)def get(self,index):if index<0 or index>=self.size:return -1else:if index<self.size-index:cur=self.headfor _ in range(index+1):cur=cur.nextreturn cur.valelse:cur=self.tailfor _ in range(self.size-index+1):cur=cur.prereturn cur.valdef delete(self,index):if index<0 or index>=self.size:return -1else:if index<self.size-index:pred=self.headfor _ in range(index):pred=pred.nextsucc=pred.next.nextelse:succ=self.tailfor _ in range(self.size-index-1):succ=succ.prepred=succ.pre.prepred.next=succsucc.pre=predself.size-=1def print_all(self):cur=self.headwhile cur:print(cur.val)cur=cur.next
if __name__=='__main__':link=MyListNode()link.add_tail(1)link.add_tail(2)link.add_tail(3)link.add_tail(4)link.add_tail(5)# link.delete(0)link.add_index(3,8)link.add_index(6,8)link.add_tail(11)link.add_head(20)link.print_all()
6.3循环链表
class ListNode:def __init__(self,val:int):self.val=valself.next=None
class MyLinkNode:def __init__(self):self.size=0self.head=ListNode(0)self.head.next=self.headdef add_index(self,val:int,index:int):if index>self.size:return -1index=max(0,index)add_node=ListNode(val)pre=self.headfor _ in range(index):pre=pre.nextadd_node.next=pre.nextpre.next=add_nodeself.size+=1def add_head(self,val:int):self.add_index(val,0)def add_tail(self,val:int):self.add_index(val,self.size)def get(self,index:int):if index<0 or index>=self.size:return -1pred=self.headfor _ in range(index+1):pred=pred.nextreturn pred.valdef delete(self,index:int):if index<0 or index>=self.size:return -1pred=self.headfor _ in range(index):pred=pred.nextpred.next=pred.next.nextself.size-=1def traverse(self):cur=self.head.nextcount=1while cur:print(cur.val)cur=cur.nextcount+=1if count>self.size+3:break
if __name__=='__main__':link=MyLinkNode()link.add_tail(1)link.add_tail(2)link.add_tail(3)link.add_tail(4)link.traverse()
6.4栈——数组表示
class ArrayStack:def __init__(self):self.data:list[int]=[]def push(self,val):self.data.append(val)def pop(self):if self.is_empty():raise Exception('栈为空')else:return self.data.pop()def is_empty(self):return len(self.data)==0def top(self):if self.is_empty():raise Exception('栈为空')else:return(self.data[-1])def to_list(self):return self.data
if __name__=='__main__':stack=ArrayStack()stack.push(1)stack.push(2)stack.push(3)stack.push(4)print(stack.to_list())print(stack.top())stack.pop()print(stack.to_list())
6.5栈——链表表示
class ListNode:def __init__(self,val:int):self.val: int = valself.next = Noneclass LinkedListStack:def __init__(self):self.flag: ListNode|None = Noneself._size: int = 0def size(self) -> int:'''获取栈中元素的个数'''return self._sizedef is_empty(self) -> bool:'''判断栈是否为空'''return self._size == 0def push(self, val: int) -> None:'''入栈'''# 创建节点node = ListNode(val)# 将新节点的next指向原来的栈顶元素node.next = self.flag# 将栈顶指针指向新节点self.flag = node# 栈中元素个数+1self._size += 1def pop(self) -> int:'''出栈'''# 获取栈顶元素的值data = self.top()# 将栈顶指针指向栈顶元素的下一个元素self.flag = self.flag.next# 栈中元素个数-1self._size -= 1return datadef top(self)-> int:'''获取栈顶元素'''if self.is_empty():raise Exception('Stack is empty')return self.flag.valdef to_list(self):'''将栈转换为列表'''result = []# 获取栈顶元素node = self.flag# 判断栈顶元素是否为空while node:result.append(node.val)node = node.nextreturn resultif __name__ =='__main__':stack = LinkedListStack()stack.push(1)stack.push(2)stack.push(3)print(stack.to_list())print(f'获取栈顶元素:{stack.top()}')print(stack.to_list())print(f'出栈:{stack.pop()}')print(f'栈的元素个数:{stack.size()}')print(f'栈是否为空:{stack.is_empty()}')
6.6队列——数组表示
class MyQueue:def __init__(self):self.items = []def push(self,val:int) ->None:'''入队'''self.items.append(val)def pop(self) ->int:'''出队'''return self.items.pop(0)def size(self) ->int:'''队列大小'''return len(self.items)def is_empty(self) ->bool:'''队列是否为空'''return self.size() == 0def peek(self) ->int:'''获取队首元素'''return self.items[0]def to_list(self) ->list:'''转换为列表'''return self.itemsif __name__ == '__main__':queue = MyQueue()queue.push(1)queue.push(2)queue.push(3)print(f'转成列表后:{queue.to_list()}')print(f'出队:{queue.pop()}')print(f'转成列表后:{queue.to_list()}')print(f'访问队首元素:{queue.peek()}')print(f'转成列表后:{queue.to_list()}')print(f'队列是否为空:{queue.is_empty()}')print(f'队列是元素个数:{queue.size()}')
6.7队列——链表表示
class MyQueue:def __init__(self):self.items = []def push(self,val:int) ->None:'''入队'''self.items.append(val)def pop(self) ->int:'''出队'''return self.items.pop(0)def size(self) ->int:'''队列大小'''return len(self.items)def is_empty(self) ->bool:'''队列是否为空'''return self.size() == 0def peek(self) ->int:'''获取队首元素'''return self.items[0]def to_list(self) ->list:'''转换为列表'''return self.itemsif __name__ == '__main__':queue = MyQueue()queue.push(1)queue.push(2)queue.push(3)print(f'转成列表后:{queue.to_list()}')print(f'出队:{queue.pop()}')print(f'转成列表后:{queue.to_list()}')print(f'访问队首元素:{queue.peek()}')print(f'转成列表后:{queue.to_list()}')print(f'队列是否为空:{queue.is_empty()}')print(f'队列是元素个数:{queue.size()}')
6.8双向队列-数组表示
class ArrayDeque:def __init__(self,capacity:int=8):self._data = [0] * capacity # 存储数据的数组self._head = 0 # 队头元素的下标self._size = 0 # 队列中元素的个数def capacity(self):'''返回队列的容量'''return len(self._data)def is_empty(self) -> bool:'''判断队列是否为空'''return self._size == 0def index(self,i:int) -> int:'''获取指定正确的索引'''return (i+self.capacity())%self.capacity()def peek_first(self) -> int:'''查看队头元素'''if self.is_empty():raise Exception("Deque is empty")return self._data[self._head]def peek_last(self) -> int:'''查看队尾元素'''if self.is_empty():raise Exception("Deque is empty")# 获取队尾元素的下标i = self.index(self._head + self._size - 1)return self._data[i]def push_last(self,val:int):'''增加队尾元素'''# 判断队列是否已满if self._size == self.capacity():raise Exception("Deque is full")# 获取队尾元素的下标i = self.index(self._head + self._size)# 将元素添加到队尾self._data[i] = val# 队列中元素的个数加1self._size += 1def push_first(self,val:int):'''增加队头元素'''# 判断队列是否已满if self._size == self.capacity():raise Exception("Deque is full")# 获取队头元素的下标i = self.index(self._head - 1)# 将元素添加到队头self._data[i] = val# 队列中元素的个数加1self._size += 1# 修改队头元素的下标self._head = idef pop_first(self) -> int:'''删除队头元素'''if self.is_empty():raise Exception("Deque is empty")# 获取队头元素的值val = self.peek_first()# 修改队头元素的下标self._head = self.index(self._head + 1)# 队列中元素的个数减1self._size -= 1return valdef pop_last(self) -> int:'''删除队尾元素'''if self.is_empty():raise Exception("Deque is empty")# 获取队尾元素的值val = self.peek_last()# 队列中元素的个数减1self._size -= 1return valdef to_list(self):'''转换为列表'''res = []for i in range(self._size):tmp_index = self.index(self._head + i)res.append(self._data[tmp_index])return resif __name__ == "__main__":deque = ArrayDeque(5)deque.push_last(1)deque.push_last(2)deque.push_last(3)deque.push_last(4)deque.push_last(5)print(deque.to_list()) # [1,2,3,4,5]deque.pop_first() # 1deque.push_last(6) # [2,3,4,5,6]print(deque.to_list()) # [2,3,4,5,6]print(f'队尾拿到数据:{deque.pop_last()}') # 6deque.push_first(7) # [7,2,3,4,5]print(deque.to_list()) # [7,2,3,4,5]
6.9双向队列-链表表示
class ArrayDeque:def __init__(self,capacity:int=8):self._data = [0] * capacity # 存储数据的数组self._head = 0 # 队头元素的下标self._size = 0 # 队列中元素的个数def capacity(self):'''返回队列的容量'''return len(self._data)def is_empty(self) -> bool:'''判断队列是否为空'''return self._size == 0def index(self,i:int) -> int:'''获取指定正确的索引'''return (i+self.capacity())%self.capacity()def peek_first(self) -> int:'''查看队头元素'''if self.is_empty():raise Exception("Deque is empty")return self._data[self._head]def peek_last(self) -> int:'''查看队尾元素'''if self.is_empty():raise Exception("Deque is empty")# 获取队尾元素的下标i = self.index(self._head + self._size - 1)return self._data[i]def push_last(self,val:int):'''增加队尾元素'''# 判断队列是否已满if self._size == self.capacity():raise Exception("Deque is full")# 获取队尾元素的下标i = self.index(self._head + self._size)# 将元素添加到队尾self._data[i] = val# 队列中元素的个数加1self._size += 1def push_first(self,val:int):'''增加队头元素'''# 判断队列是否已满if self._size == self.capacity():raise Exception("Deque is full")# 获取队头元素的下标i = self.index(self._head - 1)# 将元素添加到队头self._data[i] = val# 队列中元素的个数加1self._size += 1# 修改队头元素的下标self._head = idef pop_first(self) -> int:'''删除队头元素'''if self.is_empty():raise Exception("Deque is empty")# 获取队头元素的值val = self.peek_first()# 修改队头元素的下标self._head = self.index(self._head + 1)# 队列中元素的个数减1self._size -= 1return valdef pop_last(self) -> int:'''删除队尾元素'''if self.is_empty():raise Exception("Deque is empty")# 获取队尾元素的值val = self.peek_last()# 队列中元素的个数减1self._size -= 1return valdef to_list(self):'''转换为列表'''res = []for i in range(self._size):tmp_index = self.index(self._head + i)res.append(self._data[tmp_index])return resif __name__ == "__main__":deque = ArrayDeque(5)deque.push_last(1)deque.push_last(2)deque.push_last(3)deque.push_last(4)deque.push_last(5)print(deque.to_list()) # [1,2,3,4,5]deque.pop_first() # 1deque.push_last(6) # [2,3,4,5,6]print(deque.to_list()) # [2,3,4,5,6]print(f'队尾拿到数据:{deque.pop_last()}') # 6deque.push_first(7) # [7,2,3,4,5]print(deque.to_list()) # [7,2,3,4,5]