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