链表
为什么需要链表
顺序表的构建需要预知数据大小来申请连续的储存空间,而进行扩充时又需要进行数据的搬迁,所以使用起来并不是很灵活。
链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。
链表的定义
链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是不像顺序表一样的连续储存数据,而是在每一个节点(数据储存单元)里存放下一个节点的位置信息(即是地址)。前面的是元素信息,后面是位置信息。
单项链表
单项链表也叫单链表,是链表中最简单的一种形式,他的每个节点包含两个域。
- 信息域(元素域) : 元素的具体数字多少
- 一个链接域 : 这个链接指向链表中的下一个节点,而最后一个节点的连接域则指向一个空置
None
- 表元素域elem用来存放具体的数据
- 连接域next用来存放下一个节点的位置(Python中的标识)
- 变量p指向链表的头结点(首节点)的位置,从p出发能找到表中的任意结点
结点的代码实现
class Node(object):
'''单链表的节点'''
def __init__(self,elem):
self.elem = elem # elem 是存放数据的元素
self.next = None # next 是下一个节点的标识
单链表的实现
基本实现
class SingleLinkList(object):
'''单链表的操作'''
def __init__(self,node = None):
# '''这个目的是把头结点连上 是为了方便调用下面的方法'''
self.__head = node
def is_empty(self):
# '''链表是否为空'''
return self.__head == None
def length(self):
# '''链表长度'''
# current游标,用来移动遍历节点
current = self.__head
# count 记录数量
count = 0
while current != None:
count += 1
current = current.next
return count # 移动了几位就是链表长度是多少
def travel(self):
# '''遍历整个链表'''
current = self.__head
while current != None:
print(current.elem,end=' ')
current = current.next
头部添加元素
def add(self,item):
# '''链表头部添加元素 头插法'''
node = Node(item)
node.next = self.__head # 将新插入元素的next和__head(此时__head指向第一个元素)连接上
self.__head = node # 将新元素的节点赋给最前面的__head
尾部添加元素
def append(self,item): # item不是节点 是具体的一个元素
# '''链表尾部添加元素 尾插法'''
node = Node(item)
if self.is_empty(): # 空列表 直接到头上
self.__head = node
else:
current = self.__head
while current.next != None:
current = current.next
current.next = node
指定位置添加元素
def insert(self,pos,item):
# '''指定位置添加元素 pos:从0开始的'''
if pos <= 0:
self.add(item)
elif pos > (self.length() - 1):
self.append(item)
else:
pre = self.__head
count = 0
while count <= (pos-1):
count += 1
pre = pre.next
# 循环退出后 pre指向了pos减一的位置
node = Node(item)
node.next = pre.next
pre.next = node
删除节点
def remove(self,item):
# '''删除节点'''
current = self.__head
pre = None
while current != None:
if current.elem == item:
# 先判断此节点是否是头结点
# 如果是头结点的话
if current == self.__head:
self.__head = current.next
break
else:
pre.next = current.next # 核心步骤 删除步骤
break
else:
pre = current
current = current.next
查找节点时否存在
def search(self,item):
# '''查找节点是否存在'''
current = self.__head
while current != None:
if current.elem == item:
return True
else:
current = current.next
return False
测试
if __name__ == "__main__": # 这是主函数 就是程序的入口 基本上标准的程序都要写这个main函数
ll = SingleLinkList()
print(ll.is_empty())
print(ll.length())
print('---')
print(ll.is_empty())
print(ll.length())
print('---')
ll.append(1)
ll.append(2)
ll.append(3)
ll.append(4)
ll.append(5)
ll.append(6)
ll.add(100) # 添加到头部
ll.travel()
print('\n---')
ll.insert(2,99)
ll.travel()
print('\n---')
ll.insert(-1,12)
ll.travel()
print('\n---')
ll.insert(99,89)
ll.travel()
print('\n---')
ll.remove(12)
ll.travel()
print('\n---')
ll.remove(6)
ll.travel()
print('\n---')
ll.travel()
print(ll.search(3))
输出:
True
0
---
True
0
---
100 1 2 3 4 5 6
---
100 1 2 99 3 4 5 6
---
12 100 1 2 99 3 4 5 6
---
12 100 1 2 99 3 4 5 6 89
---
100 1 2 99 3 4 5 6 89
---
100 1 2 99 3 4 5 89
---
100 1 2 99 3 4 5 89 True
双向链表
一种更加复杂的链表是双向链表或双面链表。每个节点有两个链接: 一个指向前一个节点,当此节点为第一个节点时,指向空值。
而另一个指向下一个节点,当此节点为最后一个节点,指向空值。
实现
class Node(object):
'''节点'''
def __init__(self,item):
self.elem = item
self.prev = None
self.next = None
class DoubleLinkList(object):
'''双链表'''
def __init__(self,node = None):
# '''这个目的是把头结点连上 是为了方便调用下面的方法'''
self.__head = node
def is_empty(self):
# '''链表是否为空'''
return self.__head is None # 最好用is ==也可以达到效果
def length(self):
# '''链表长度'''
# current游标,用来移动遍历节点
current = self.__head
# count 记录数量
count = 0
while current != None:
count += 1
current = current.next
return count # 移动了几位就是链表长度是多少
def travel(self):
# '''遍历整个链表'''
current = self.__head
while current != None:
print(current.elem,end=' ')
current = current.next
def add(self,item):
# '''链表头部添加元素 头插法'''
node = Node(item)
node.next = self.__head # 将新插入元素的next和__head(此时__head指向第一个元素)连接上
self.__head = node # 将新元素的节点赋给最前面的__head
node.next.prev = node
def append(self,item): # item不是节点 是具体的一个元素
# '''链表尾部添加元素 尾插法'''
node = Node(item)
if self.is_empty(): # 空列表 直接到头上
self.__head = node
else:
current = self.__head
while current.next != None:
current = current.next
current.next = node
node.prev = current
def search(self,item):
# '''查找节点是否存在'''
current = self.__head
while current != None:
if current.elem == item:
return True
else:
current = current.next
return False
指定位置插入节点
def insert(self,pos,item):
# '''指定位置添加元素 pos:从0开始的'''
if pos <= 0:
self.add(item)
elif pos > (self.length() - 1):
self.append(item)
else:
current = self.__head
count = 0
while count < pos:
count += 1
current = current.next
# 循环退出后 pre指向了pos减一的位置
node = Node(item)
node.next = current # 插入到链表元素之间
node.prev = current.prev
current.prev.next = node
current.prev = node
删除元素
def remove(self,item):
# '''删除节点'''
current = self.__head
pre = None
while current != None:
if current.elem == item:
# 先判断此节点是否是头结点
# 如果是头结点的话
if current == self.__head:
self.__head = current.next
if current.next != None:
# 判断链表是否只有一个节点
current.next.prev = None
break
else:
current.prev.next = current.next # 这两部是核心步骤
if current.next:
current.next.prev = current.prev
break
else:
current = current.next
测试:
if __name__ == "__main__":
ll = DoubleLinkList()
print(ll.is_empty())
print(ll.length())
print('---')
print(ll.is_empty())
print(ll.length())
print('---')
ll.append(1)
ll.append(2)
ll.append(3)
ll.append(4)
ll.append(5)
ll.append(6)
ll.add(100) # 添加到头部
ll.travel()
print('\n---')
ll.insert(2,99)
ll.travel()
print('\n---')
ll.insert(-1,12)
ll.travel()
print('\n---')
ll.insert(99,89)
ll.travel()
print('\n---')
ll.remove(12)
ll.travel()
print('\n---')
ll.remove(6)
ll.travel()
print('\n---')
ll.travel()
print(ll.search(3))
输出结果:
True
0
---
True
0
---
100 1 2 3 4 5 6
---
100 1 99 2 3 4 5 6
---
12 100 1 99 2 3 4 5 6
---
12 100 1 99 2 3 4 5 6 89
---
100 1 99 2 3 4 5 6 89
---
100 1 99 2 3 4 5 89
---
100 1 99 2 3 4 5 89 True
单项循环链表
单链表的一个变形是单向循环链表,链表中最后一个节点的next域不再为None,而是指向链表的头节点。
class Node(object):
'''节点'''
def __init__(self,elem):
self.elem = elem # elem是存放数据的元素
self.next = None # next是下一个节点的标识
# node = Node(100)
class SingleCycleLinkList(object):
'''单项循环链表的操作'''
def __init__(self,node = None):
# '''这个目的是把头结点连上 是为了方便调用下面的方法'''
self.__head = node
if node:
node.next = node # 使其收尾相连
def is_empty(self):
# '''链表是否为空'''
return self.__head == None
def length(self):
# '''链表长度'''
if self.is_empty():
return 0
# current游标,用来移动遍历节点
current = self.__head
# count 记录数量
count = 1
while current.next != self.__head:
count += 1
current = current.next
return count # 移动了几位就是链表长度是多少
def travel(self):
# '''遍历整个链表'''
if self.is_empty():
return '空列表'
current = self.__head
while current.next != self.__head:
print(current.elem,end=' ')
current = current.next
# 退出循环时 current指向尾结点 但尾结点的元素未打印 现在要打印
print(current.elem)
def add(self,item):
# '''链表头部添加元素 头插法'''
node = Node(item)
if self.is_empty():
self.__head == node
node.next = node
else:
current = self.__head
while current.next != self.__head:
current = current.next # 只要不到列表的头就要一直往后移动
# 退出循环 current指向尾结点
node.next = self.__head
self.__head = node
# current.next = node
current.next = self.__head
def append(self,item): # item不是节点 是具体的一个元素
# '''链表尾部添加元素 尾插法'''
node = Node(item)
if self.is_empty(): # 空列表 直接到头上
self.__head = node
node.next = node # 只要不到列表的头就要一直往后移动
else:
current = self.__head
while current.next != self.__head:
current = current.next
# current.next = node
node.next = self.__head
current.next = node
def insert(self,pos,item):
# '''指定位置添加元素 pos:从0开始的'''
if pos <= 0:
self.add(item)
elif pos > (self.length() - 1):
self.append(item)
else:
pre = self.__head
count = 0
while count <= (pos-1):
count += 1
pre = pre.next
# 循环退出后 pre指向了pos减一的位置
node = Node(item)
node.next = pre.next
pre.next = node
def remove(self,item):
# '''删除节点'''
if self.is_empty():
return '空字符串'
current = self.__head
pre = None
while current.next != self.__head:
if current.elem == item:
# 先判断此节点是否是头结点
# 如果是头结点的话
if current == self.__head:
# 头结点处理
# 找尾结点 rear 尾部的意思
rear = self.__head
while rear.next != self.__head:
rear = rear.next
self.__head = current.next
rear.next = self.__head
# self.__head = current.next
else:
# 中间节点处理
pre.next = current.next # 核心步骤 删除步骤
return
else:
pre = current
current = current.next
# 退出循环 current指向尾结点
if current.elem == item:
if current == self.__head:
# 链表只有一个节点
self.__head = None
else:
pre.next = current.next # 核心步骤 删除步骤
def search(self,item):
# '''查找节点是否存在'''
if self.is_empty():
return False
current = self.__head
while current != self.__head:
if current.elem == item:
return True
else:
current = current.next
# 退出循环 current指向了尾结点
if current.elem == item:
return True
return False
# 测试
if __name__ == "__main__":
ll = SingleCycleLinkList()
print(ll.is_empty())
print(ll.length())
print('---')
print(ll.is_empty())
print(ll.length())
print('---')
ll.append(1)
ll.append(2)
ll.append(3)
ll.append(4)
ll.append(5)
ll.append(6)
ll.add(100) # 添加到头部
ll.travel()
print('\n---')
ll.insert(2,99)
ll.travel()
print('\n---')
ll.insert(-1,12)
ll.travel()
print('\n---')
ll.insert(99,89)
ll.travel()
print('\n---')
ll.remove(12)
ll.travel()
print('\n---')
ll.remove(6)
ll.travel()
print('\n---')
ll.travel()
print(ll.search(3))
输出结果:
True
0
---
True
0
---
100 1 2 3 4 5 6
---
100 1 2 99 3 4 5 6
---
12 100 1 2 99 3 4 5 6
---
12 100 1 2 99 3 4 5 6 89
---
100 1 2 99 3 4 5 6 89
---
100 1 2 99 3 4 5 89
---
100 1 2 99 3 4 5 89
False