单链表及基本操作
概念补充:后继结点,即后一个邻结点
- 创建一个节点
# 单链表及节点定义代码
# 节点中需要保存它的数据和下一个链接地址
class Node(object):
"""节点"""
def __init__(self, elem):
self.elem = elem+
self.next = None # 先不指向任何区域
- 创建一个链表
class SingleLinkList(object):
"""单链表"""
# 链表中必须存在一个(对象)属性,指向第一个节点
# 设置默认参数为空,为让顾客没输入第一个节点时也可以运行
def __init__(self, node):
self.__head = None
- 一些链表相关操作:
宗旨:不要先打断原有链表,先对待操作的新节点进行操作
① 判断是否为空链表
# 链表是否为空(对具体对象的操作是对象方法而不是类方法)
def is_empty(self):
"""链表是否为空"""
return self.__head == None
② 计算链表长度
def length(self):
"""链表长度(节点数目)"""
# cur游标用来移动遍历节点
cur = self.__head # 建立cur游标=起始节点
# count记录数量
count = 0 # 若设置为1则还需要额外考虑空链表情况
while cur != None:
count += 1
cur = cur.next
return count
③ 遍历整个链表
def travel(self):
"""遍历整个链表(需要定义一个游标cur来记录当前位置)"""
cur = self.__head
while cur != None:
print(cur.elem, end="")
cur = cur.next
④ 在链表头部插入节点:
def add(self, item):
"""链表头部添加元素(放入节点),头插法"""
node = Node(item) # 待插入的新节点
# 注意这里指的不是node节点的下一节点,而是其next区域
node.next = self.__head # 让新节点的next区域等于原head区域(插入图片)
def add(self, item):
"""链表头部添加元素(放入节点),头插法"""
node = Node(item) # 待插入的新节点
# 注意这里指的不是node节点的下一节点,而是其next区域
node.next = self.__head # 让新节点的next区域等于原head区域(插入图片)
self.__head = node
原有节点指向新节点
⑤ 在链表尾部插入节点:
def append(self, item):
"""链表尾部添加元素(放入节点),尾插法"""
node = Node(item)
if self.is_empty():
self.__head = node
else:
cur = self.__head # 若为空链表则
while cur.next != None:
cur = cur.next
cur.next = node
⑥ 指定位置添加元素
def insert(self, pos, item):
"""指定位置添加元素(在哪个位置、添加哪个节点)
:param pos从0开始
"""
if pos <= 0:
self.add(item)
elif pos > (self.length()-1):
self.append(item)
else:
count = 0
pre = self.__head # 定义一个游标
while count < (pos-1):
count += 1
pre = pre.next
# 当循环退出后,pre指向pos-1位置
node = Node(item)
node.next = pre.next
pre.next = node
⑦ 查找节点是否存在
def search(self, item):
"""查找节点是否存在"""
cur = self.__head
while cur != None:
if cur.elem == item:
return True
else:
cur = cur.next
return False
⑧删除节点
有两种情况:两个游标和一个游标
两个游标的情况:
def remove(self, item):
"""删除节点(删掉元素集而不是位置)"""
cur = self.__head
pre = None
while cur != None:
if cur.elem == item:
# 先判断此节点是否是头节点
# 头节点
if cur == self.__head:
self.__head = cur.next
else:
pre.next = cur.next # 验证删头/尾节点是否能够删除
break # 否则进入死循环
else:
# 保持pre游标始终在cur游标前面
pre = cur
cur = cur.next
return False
补充说明:
self.__head指的是其指向的100node
总体及运行结果:
# 单链表及节点定义代码
# 节点中需要保存它的数据和下一个链接地址
class Node(object):
"""节点"""
def __init__(self, elem):
self.elem = elem
self.next = None # 先不指向任何区域
class SingleLinkList(object):
"""单链表"""
# 链表中必须存在一个(对象)属性,指向第一个节点
# 设置默认参数为空,为让顾客没输入第一个节点时也可以运行
def __init__(self, node):
self.__head = None
# 链表是否为空(对具体对象的操作是对象方法而不是类方法)
def is_empty(self):
"""链表是否为空"""
return self.__head == None
def length(self):
"""链表长度(节点数目)"""
# cur游标用来移动遍历节点
cur = self.__head # 建立cur游标=起始节点
# count记录数量
count = 0 # 若设置为1则还需要额外考虑空链表情况
while cur != None:
count += 1
cur = cur.next
return count
def travel(self):
"""遍历整个链表(需要定义一个游标cur来记录当前位置)"""
cur = self.__head
while cur != None:
print(cur.elem, end="")
cur = cur.next
print("") # 遍历后换行
def add(self, item):
"""链表头部添加元素(放入节点),头插法"""
node = Node(item) # 待插入的新结点
# 注意这里指的不是node节点的下一节点,而是其next区域
node.next = self.__head # 让新节点的next区域等于原head区域(插入图片)
self.__head = node
def append(self, item):
"""链表尾部添加元素(放入节点),尾插法"""
node = Node(item)
if self.is_empty():
self.__head = node
else:
cur = self.__head # 若为空链表则
while cur.next != None:
cur = cur.next
cur.next = node
def insert(self, pos, item):
"""指定位置添加元素(在哪个位置、添加哪个节点)
:param pos从0开始
"""
if pos <= 0:
self.add(item)
elif pos > (self.length()-1):
self.append(item)
else:
count = 0
pre = self.__head # 定义一个游标
while count < (pos-1):
count += 1
pre = pre.next
# 当循环退出后,pre指向pos-1位置
node = Node(item)
node.next = pre.next
pre.next = node
def remove(self, item):
"""删除节点(删掉元素集而不是位置)"""
cur = self.__head
pre = None
while cur != None: # 往后移动的调件
if cur.elem == item:
# 先判断此节点是否是头节点
# 头节点
if cur == self.__head:
self.__head = cur.next
else:
pre.next = cur.next # 验证删头/尾节点是否能够删除
break # 否则进入死循环
else:
# 保持pre游标始终在cur游标前面
pre = cur
cur = cur.next
return False
def search(self, item):
"""查找节点是否存在"""
cur = self.__head
while cur != None:
if cur.elem == item:
return True
else:
cur = cur.next
return False
"""
node = Node(100)
single_obj = SingleLinkList(node)
single_obj.travel()
"""
if __name__ == "__main__":
ll = SingleLinkList(1)
print((ll.is_empty()))
print((ll.length()))
ll.append(1)
print((ll.is_empty()))
print(ll.length())
ll.append(2)
ll.append(3)
ll.append(4)
ll.add(8)
ll.insert(-1, 9) # 小于0都视为从头开始,9、8、1、2、3、4
ll.travel()
ll.insert(3, 100) # 索引计数从0开始,9、8、1、100、2、3、4
ll.travel()
ll.insert(10, 200) # 9、8、1、100、2、3、4、200
ll.travel()
ll.remove(100)
ll.travel()
ll.remove(9)
ll.travel()
ll.remove(200)
ll.travel()
True
0
False
1
981234
981100234
981100234200
981234200
81234200
81234
链表与顺序表的对比
双向链表基本操作
双向链表:
引入概念:前驱结点、后继结点
基本操作
① 结点创建
class Node(object):
"""结点"""
def __init__(self, item):
self.elem = item
self.next = None
self.prev = None
② 链表创建
class DoubleLinkList(object): # 不涉及pre游标的也可以直接继承自单链表
def __init__(self, node):
self.__head = None
③判断链表是否为空
def is_empty(self):
"""链表是否为空"""
return self.__head == None
④ 链表长度计算
def length(self):
"""链表长度(节点数目)"""
# cur游标用来移动遍历节点
cur = self.__head # 建立cur游标=起始节点
# count记录数量
count = 0 # 若设置为1则还需要额外考虑空链表情况
while cur != None:
count += 1
cur = cur.next
return count
⑤ 遍历
def travel(self):
"""遍历整个链表(需要定义一个游标cur来记录当前位置)"""
cur = self.__head
while cur != None:
print(cur.elem, end="")
cur = cur.next
print("") # 遍历后换行
⑥ 头部添加元素
def add(self, item):
"""链表头部添加元素(放入节点),头插法"""
node = Node(item) # 待插入的新节点
# 注意这里指的不是node节点的下一节点,而是其next区域
node.next = self.__head # 让新节点的next区域等于原head区域(插入图片)
self.__head = node
node.next.prev = node # 顺序不唯一
⑦ 尾部添加元素
def append(self, item):
"""链表尾部添加元素(放入节点),尾插法"""
node = Node(item)
if self.is_empty():
self.__head = node
else:
cur = self.__head # 若为空链表则
while cur.next != None:
cur = cur.next
cur.next = node
node.prev = cur
⑧ 指定位置添加元素(结点)
操作方法举例(两种):
def insert(self, pos, item):
"""指定位置添加元素(在哪个位置、添加哪个节点)
:param pos从0开始
"""
if pos <= 0:
self.add(item)
elif pos > (self.length()-1):
self.append(item)
else:
cur = self.__head
count = 0
while count < pos:
count += 1
cur = cur.next
# 当循环退出后,pre指向pos位置
node = Node(item)
node.next = cur
node.prev = cur.prev
cur.prev.next = node
cur.prev = node
⑨ 删除结点
def remove(self, item):
"""删除节点(删掉元素集而不是位置)"""
cur = self.__head
while cur != None:
if cur.elem == item:
# 先判断此节点是否是头节点
# 头节点
if cur == self.__head:
self.__head = cur.next
if cur.next != None:
# 判断链表是否只有一个结点
cur.next.prev = None # 若是,则cur.next是None,没有prev
else:
cur.prev.next = cur.next
if cur.next:
cur.next.prev = cur.prev
break # 否则进入死循环
else:
cur = cur.next
⑩ 查找结点是否存在
def search(self, item):
"""查找节点是否存在"""
cur = self.__head
while cur != None:
if cur.elem == item:
return True
else:
cur = cur.next
return False
运算结果:
if __name__ == "__main__":
dll = DoubleLinkList(1)
print((dll.is_empty()))
print((dll.length()))
dll.append(1)
print((dll.is_empty()))
print(dll.length())
dll.append(2)
dll.append(3)
dll.append(4)
dll.add(8)
dll.insert(-1, 9)
dll.travel()
dll.insert(3, 100)
dll.travel()
dll.insert(10, 200)
dll.travel()
dll.remove(100)
dll.travel()
dll.remove(9)
dll.travel()
dll.remove(200)
True
0
False
1
981234
981100234
981100234200
981234200
81234200
81234
单向循环链表
一. 遍历和求长度
单向循环链表:尾结点指针区next指向头结点
二. 添加元素
(宗旨:尽量先动要插入的结点,不先动原有结点)
1.在头部添加元素:
1.将node插入头部
node.next = self.__head (self.__head指的是100结点,此操作让400的next指向100)
self.__head = node (让head指向400)
注意:
1)上述顺序不能颠倒,否则后部分链表会丢失
2)这里self.__head是一个 “前部分为空+next” 结点,本身的意思就是“next”形式的
3)self.__head是真实存在的结点
2.让尾部指向头部
由于需要找到尾结点,所以需要有一个遍历的过程。有两种方法:先遍历找到尾结点再插入头结点 or 先插入再遍历
方法一:先插入后遍历(不太好理解)
要遍历,就先设计游标cur:
1)由于终止条件原来是:cur.next = self.__head ,所以找到 “cur.next = node.next”也就找到了尾结点( 即都指向100结点)
方法2:先遍历找到尾结点再插入
1)当 cur.next = self.__head 则找到了尾结点,所以
while cur.next != self.__head
cur = cur.next
2)然后
node.next = self.__head
self.__head = node
cur.next = node # 使尾结点指向node,
# 或者写成cur.next = self.__head
3)检查特殊情况(空链表、、)
空链表:若判断为空,则让head指向添加的结点,并让它再指向自身
if self.is_empty():
self.__head = node
node.next = node
else
只有一个结点:
原代码依然可行,不用修改
2.在尾部添加元素
- 将node插入尾部
两种方法
# 先动node
node.next = cur.next
cur.next = node
或者
# 先动链表
cur.next = node
node.next = self.__head