为什么需要链表
顺序表的构建需要预先知道数据大小来申请连续的存储空间,而在进行扩充时又需要进行数据的搬迁,所以使用起来并不是很灵活。
链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。
链表的定义
链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是不像顺序表一样连续存储数据,而是在每一个节点(数据存储单元)里存放下一个节点的位置信息(即地址)。

1.单向链表
单向链表也叫单链表,是链表中最简单的一种形式,它的每个节点包含两个域,一个信息域(元素域)和一个链接域。这个链接指向链表中的下一个节点,而最后一个节点的链接域则指向一个空值。

- 表元素域elem用来存放具体的数据。
- 链接域next用来存放下一个节点的位置(python中的标识)。
- 变量p指向链表的头节点(首节点)的位置,从p出发能找到表中的任意节点。
(1) 节点实现
class SingleNode(object):
"""单链表的节点"""
# 节点有两个属性,item 存放数据元素,next 存放下一个节点的地址
def __init__(self,item):
self.item = item
self.next = None
(2)单链表的操作
- is_empty() 链表是否为空
- length() 链表长度
- travel() 遍历整个链表
- add(item) 链表头部添加元素
- append(item) 链表尾部添加元素
- insert(pos, item) 指定位置添加元素
- remove(item) 删除节点
- search(item) 查找节点是否存在
(3)单链表的实现
- 判断链表是否为空
- 计算链表长度
- 遍历链表
class SingleLinkList(object):
"""单链表"""
def __init__(self):
# head存放单链表首节点地址
self.head = None
def is_empty(self):
"""判断单链表是否为空"""
return self.head == None
def length(self):
"""计算链表长度"""
cur = self.head
count = 0
# 当未到达尾部时
while cur:
cur = cur.next
count += 1
return count
def travel(self):
"""遍历链表"""
cur = self.head
while cur:
print(cur.item)
cur = cur.next
- 从链表头部插入元素

def add(self,item):
"""头部插入元素"""
# 先新建一个节点
node = SingleNode(item)
# 新节点的尾部指向原首节点
node.next = self.head
# 新首节点为新建节点
self.head = node
- 从链表尾部插入元素
def append(self,item):
"""尾部插入元素"""
# 新建节点
node = SingleNode(item)
# 先判断链表是否为空,若是空链表,则将_head指向新节点
if self.is_empty():
self.head = node
# 若不为空,则找到尾部,将尾节点的next指向新节点
else:
cur = self.head
while cur.next:
cur = cur.next
# 找到最后一个节点,最后一个节点的next为新节点
cur.next = node
- 从链表指定位置插入元素

def insert(self, pos, item):
"""在指定位置添加元素"""
# 在头部插入
if pos <=0:
self.add(item)
# 在尾部插入
elif pos >= self.length():
self.append(item)
# 在中间插入
else:
# pre用来指向指定位置pos的前一个位置pos-1,初始从头节点开始移动到指定位置
pre = self.head
count = 0
node = SingleNode(item)
while count < pos-1:
pre = pre.next
count += 1
# 先将新节点node的next指向插入位置的节点
node.next = pre.next
# 将插入位置的前一个节点的next指向新节点
pre.next = node
- 删除节点

def remove(self,item):
"""删除节点"""
# pre 存着指定item的前一个节点
pre = None
cur = self.head
while cur:
if cur.item != item:
pre = cur
cur = cur.next
else:
# 如果item是首节点,则将头指针指向头节点的后一个节点
if pre == None:
self.head = cur.next
# 否则item是中间节点,将删除位置前一个节点的next指向删除位置的后一个节点
else:
pre.next = cur.next
break
- 查找某个节点是否存在
def search(self,item):
cur = self.head
while cur:
if cur.item == item:
return True
cur = cur.next
return False
测试
class SingleLinkList(object):
"""单链表"""
def __init__(self):
# head存放单链表首节点地址
self.head = None
def is_empty(self):
"""判断单链表是否为空"""
return self.head == None
def length(self):
"""计算链表长度"""
cur = self.head
count = 0
# 当未到达尾部时
while cur:
cur = cur.next
count += 1
return count
def travel(self):
"""遍历链表"""
cur = self.head
while cur:
print(cur.item)
cur = cur.next
def add(self,item):
"""头部插入元素"""
# 先新建一个节点
node = SingleNode(item)
# 新节点的尾部指向原首节点
node.next = self.head
# 新首节点为新建节点
self.head = node
def append(self,item):
"""尾部插入元素"""
# 新建节点
node = SingleNode(item)
# 先判断链表是否为空,若是空链表,则将_head指向新节点
if self.is_empty():
self.head = node
# 若不为空,则找到尾部,将尾节点的next指向新节点
else:
cur = self.head
while cur.next:
cur = cur.next
# 找到最后一个节点,最后一个节点的next为新节点
cur.next = node
def insert(self, pos, item):
"""在指定位置添加元素"""
# 在头部插入
if pos <=0:
self.add(item)
# 在尾部插入
elif pos >= self.length():
self.append(item)
# 在中间插入
else:
# pre用来指向指定位置pos的前一个位置pos-1,初始从头节点开始移动到指定位置
pre = self.head
count = 0
node = SingleNode(item)
while count < pos-1:
pre = pre.next
count += 1
# 先将新节点node的next指向插入位置的节点
node.next = pre.next
# 将插入位置的前一个节点的next指向新节点
pre.next = node
def remove(self,item):
"""删除节点"""
# pre 存着指定item的前一个节点
pre = None
cur = self.head
while cur:
if cur.item != item:
pre = cur
cur = cur.next
else:
# 如果item是首节点,则将头指针指向头节点的后一个节点
if pre == None:
self.head = cur.next
# 否则item是中间节点,将删除位置前一个节点的next指向删除位置的后一个节点
else:
pre.next = cur.next
break
def search(self,item):
cur = self.head
while cur:
if cur.item == item:
return True
cur = cur.next
return False
if __name__ == "__main__":
ll = SingleLinkList()
ll.add(1)
ll.add(2)
ll.append(3)
ll.insert(2, 4)
print("length:",ll.length())
ll.travel()
print (ll.search(3))
print(ll.search(5))
ll.remove(1)
print("length:",ll.length())
ll.travel()
length: 4
2
1
4
3
True
False
length: 3
2
4
3