链表
-
定义
线性表的一种,不像顺序表连续存储数据,而是在每一个数据存储单元(节点)中存放下一数据单元的位置信息(地址)。如下图 -
特点
充分利用计算机的内存空间,实现灵活的动态内存管理,但数据操作相对于顺序表的连续存储效率较低。 -
单向链表
单向链表,也叫单链表,每个节点包含两个域,一个是元素域用于存放数据元素,一个是链接域用于链接下一节点,最后一个节点的链接域指向空值。请看下图:
图中elem表示元素域,next表示链接域,p表示链表的头结点位置,由p出发才能找到表中的任意节点
#-----------------------单链表python实现-------------------#
class Node(object):
"""节点"""
def __init__(self,data):
self.data = data # 元素区
self.next = None # 链接区
class SingleLinkList(object):
"""单链表"""
def __init__(self,data=None):
node = None
if data:
node = Node(data)
self.__head = node
def is_empty(self): #时间复杂度:O(1)
"""链表判空"""
return self.__head == None
def lenth(self): #时间复杂度:O(n)
"""链表长度"""
cur_node = self.__head # 游标节点
count = 0 # 计数
while cur_node != None:
count += 1
cur_node = cur_node.next
return count
def __len__(self):
"""链表长度"""
return self.lenth()
def travel(self): #时间复杂度:O(n)
"""遍历"""
print("SingleLinkList:[",end="")
cur_node = self.__head
while cur_node != None:
if cur_node.next == None:
print(cur_node.data,end="")
break
print(cur_node.data,end=", ")
cur_node = cur_node.next
print("]")
def add(self,data): #时间复杂度:O(1)
"""在头部添加元素"""
new_node = Node(data)
new_node.next = self.__head
self.__head = new_node
def append(self,data): #时间复杂度:O(n)
"""在末尾添加元素"""
new_node = Node(data)
if self.is_empty():
self.__head = new_node
else:
cur_node = self.__head
while cur_node.next != None:
cur_node = cur_node.next
cur_node.next = new_node
def insert(self,pos,data): #时间复杂度:O(n)
"""在指定位置添加节点"""
new_node = Node(data)
# pos <=0 在头结点处插入
if pos <= 0:
self.add(data)
# pos > len()-1 在尾结点插入
elif pos > self.lenth()-1:
self.append(data)
else:
pre_node = None # 前节点游标
cur_node = self.__head # 节点游标
count = 0
while count <= pos-1:
count += 1
pre_node = cur_node
cur_node = cur_node.next
new_node.next = cur_node
pre_node.next = new_node
return data
def remove(self,data): #时间复杂度:O(n)
"""删除指定元素"""
pre_node = None
cur_node = self.__head
while cur_node != None:
if cur_node.data == data:
if cur_node == self.__head:
self.__head = cur_node.next
return data
pre_node.next = cur_node.next
return data
pre_node = cur_node
cur_node = cur_node.next
return None
def search(self,data): #时间复杂度:O(n)
"""查找元素"""
cur_node = self.__head
pos = 0
while cur_node != None:
if cur_node.data == data:
return pos
cur_node = cur_node.next
pos += 1
return None
def clear(self): #时间复杂度:O(1)
"""清空链表"""
self.__head = None # 清除头节点后其他节点可由python垃圾回收机制自动回收
def pop(self): #时间复杂度:O(n)
"""弹出尾部元素"""
if self.is_empty():
return None
pre_node = None
cur_node = self.__head
if cur_node.next == None:
self.__head = None
else:
while cur_node.next != None:
pre_node = cur_node
cur_node = cur_node.next
pre_node.next = None
return cur_node.data
#---------------------------------------------------------#
- 双向链表
每个节点有两个链接,一个指向前一个节点,当此节点为第一个节点时,指向空值;一个指向下一个节点,当此节点为最后一个节点时,指向空值。如下图所示:
图中head表示头节点地址,0表示指向空
#----------------------双向链表python实现----------------------------#
from SingleLinkList import SingleLinkList
class Node(object):
"""双向链表节点"""
def __init__(self,data):
self.data = data
self.prev = None
self.next = None
class DoubleLinkList(SingleLinkList):
"""双向链表"""
def __init__(self,data=None):
super().__init__(data)
# 继承单链表的判空
# 继承单链表的长度
# 继承单链表的遍历
def add(self,data): #时间复杂度:O(1)
"""在头部添加元素"""
new_node = Node(data)
if self.is_empty():
self._SingleLinkList__head = new_node
else:
new_node.next = self._SingleLinkList__head
self._SingleLinkList__head.prev = new_node
self._SingleLinkList__head = new_node
def append(self,data): #时间复杂度:O(n)
"""在末尾添加元素"""
new_node = Node(data)
if self.is_empty():
self._SingleLinkList__head = new_node
else:
cur_node = self._SingleLinkList__head
while cur_node.next != None:
cur_node = cur_node.next
new_node.prev = cur_node
cur_node.next = new_node
def insert(self,pos,data): #时间复杂度:O(n)
"""在指定位置添加节点"""
new_node = Node(data)
# pos <=0 在头结点处插入
if pos <= 0:
self.add(data)
# pos > len()-1 在尾结点插入
elif pos > self.lenth()-1:
self.append(data)
else:
cur_node = self._SingleLinkList__head # 节点游标
count = 0
while count <= pos-1:
count += 1
cur_node = cur_node.next
new_node.prev = cur_node.prev
new_node.next = cur_node
cur_node.prev = new_node
new_node.prev.next = new_node
return data
def remove(self,data): #时间复杂度:O(n)
"""删除指定元素"""
cur_node = self._SingleLinkList__head
while cur_node != None:
if cur_node.data == data:
if cur_node == self._SingleLinkList__head:
self._SingleLinkList__head = cur_node.next
if cur_node.next:
cur_node.next.prev = None
return data
cur_node.prev.next = cur_node.next
if cur_node.next:
cur_node.next.prev = cur_node.prev
return data
cur_node = cur_node.next
return None
def search(self,data): #时间复杂度:O(n)
"""查找元素"""
cur_node = self._SingleLinkList__head
pos = 0
while cur_node != None:
if cur_node.data == data:
return pos
cur_node = cur_node.next
pos += 1
return None
def pop(self): #时间复杂度:O(n)
"""弹出尾部元素"""
cur_node = self._SingleLinkList__head
if self.is_empty():
return None
if cur_node.next == None:
self._SingleLinkList__head = None
else:
while cur_node.next != None:
cur_node = cur_node.next
cur_node.prev.next = None
return cur_node.data
#-------------------------------------------------------------------#
- 单向循环链表
单向循环链表是单链表的一个变形,链表中最后一个节点的链接域不再指向空,而是指向头结点。如图所示:
图中p表示头结点地址,指向头节点 - 链表与顺序表对比
链表失去了顺序表的随机读取优点,同时增加了节点链接域,空间开销较大,但对存储空间使用相对灵活。链表与顺序表各操作复杂度比较:
操作 | 链表 | 顺序表 |
---|---|---|
元素访问 | O(n) | O(1) |
在头部插入/删除 | O(1) | O(n) |
在尾部插入/删除 | O(n) | O(1) |
在中间插入/删除 | O(n) | O(n) |