其他链表相关文章:Python链表中环的问题:三种方法判断是否有环,找到入环节点,…
下一篇:Python实现单向链表(下):整合式实现增删改查操作
链表简介
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
链表和数组区别:链表不需要一系列连续的内存
链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:
- 一个是存储数据元素的数据域
(在下面代码中用data存储); - 另一个是存储下一个结点地址的指针域
(在下面代码中用next存储)
链表优点
-
链表最明显的好处就是,常规数组排列关联项目的方式可能不同于这些数据项目在记忆体或磁盘上顺序,数据的存取往往要在不同的排列顺序中转换。链表允许插入和移除表上任意位置上的节点,但是不允许随机存取。
-
链表克服了数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。
链表缺点
- 失去了数组随机读取的优点
- 链表由于增加了结点的指针域,空间开销比较大。
单向链表
结点的指向是单向的,从前一个结点指向后一个结点
碎碎念:是节点还是结点?
转自:《【数据结构】节点和结点,到底怎么区分?》
一篇文章彻底把区别说清楚了,感激涕零
节点呢,被认为是一个实体,有处理能力,比如,网络上的一台计算机;而结点则只是一个交叉点,像“结绳记事”,打个结,做个标记,仅此而已,还有就是,要记住:一般算法中点的都是结点。
大体思路
需要写两个类:
- Node类:用于创建结点,并将结点以(人类)能看懂的字符串形式输出,而不是显示内存地址
- LinkedList类:用于将各结点连成链表,并实现对链表进行操作的一些方法
代码
创建Node类:
class Node:
def __init__(self, data, next=None):
self.data = data # 数据,当前结点的元素
self.next = None # 指针,指向下一个结点
def __repr__(self): # 把结点表示为一个字符串
return "NodeValue({})".format(self.data)
调用测试:
n = Node(1)
print(n) # 因为写了__repr__方法,所以输出的是Node(1),而不是内存地址
创建LinkedList类:
准备工作:初始化方法 & 打印字符串方法
想要达到的输出效果类似于:
NodeValue(1) --> NodeValue(3) --> NodeValue(4) --> END
class LinkedList:
def __init__(self):
self.head = None # 初始化头结点
## 打印链表
def __repr__(self):
cursor = self.head
string_repr = ""
while cursor:
string_repr += f"{cursor} --> "
cursor = cursor.next
return string_repr + "END"
「查」:方法
1. is_empty() 判断链表是否为空
def is_empty(self):
return self.head == None
2. length() 返回链表长度
def length(self):
if self.head is None:
return 0
cursor = self.head
count = 0
while cursor:
count += 1
cursor = cursor.next
return count
3. exist(data) 判断结点是否存在
def exist(self, data):
"""
:return: True or False
:rtype: Boolean
"""
cursor = self.head
while cursor:
if cursor.data == data:
return True
else:
cursor = cursor.next
return False
4. travel() 遍历整个链表
def travel(self):
if self.head is None:
return None
cursor = self.head
while cursor:
print(cursor)
cursor = cursor.next
5. getitem(index) 根据索引,得到链表中该位置的值
def getitem(self, index):
current = self.head
if current is None:
raise IndexError("This is an empty linked list.")
for i in range(1, index):
# 目标超过链表范围
if current.next is None:
raise IndexError("Index out of range")
current = current.next
return current
6. search(data) 返回该结点出现的左数第一个的位置,不存在返回-1
def search(self, data):
if self.exist(data) == False:
return -1
else:
cursor = self.head
count = 0
while cursor:
count += 1
if cursor.data == data:
return count
else:
cursor = cursor.next
「增」:方法
7. insert_head(data) 在链表头部添加元素
def insert_head(self, data):
new_node = Node(data) # 创建一个新结点
if self.head: # 如果已存在头部结点
# 让新创建的结点的next指向原本的头结点
# 也就是说,新结点成为了原本的头结点的上一个结点
new_node.next = self.head
self.head = new_node # 重置头结点
8. append(data) 在链表尾部添加元素
def append(self, data):
if self.head is None:
# 如果链表目前为空,则在头结点添加该元素
self.insert_head(data)
else:
cursor = self.head
while cursor.next: # 遍历链表
cursor = cursor.next
# 创建一个新结点添加到链表尾部
cursor.next = Node(data)
9. insert(pos, data) 在链表中的指定位置添加元素
def insert(self, pos, data):
"""
:param pos: 要插入结点的位置,从0开始。
pos > 0,代表是从左开始数的位置
pos = 0,代表在头部添加
pos < 0,代表是从右开始数的位置,倒数从-1开始
也就是说 链表长度 + 倒数下标 = 正数下标
:type pos: int
:param data: 要插入的结点值
:type data: int
"""
if pos > 0:
if self.head is None:
# 如果链表目前为空,则在头结点添加该元素
self.insert_head(data)
else:
new_node = Node(data) # 创建一个新结点
# 通过循环,得到新结点的上一个结点
pre = self.head
count = 0
while count < (pos-1):
count += 1
pre = pre.next
# 让新结点指向原本该位置的结点
new_node.next = pre.next
# 让上一个结点指向新结点
pre.next = new_node
elif pos == 0:
self.insert_head(data)
elif pos < 0:
if self.head is None:
# 如果链表目前为空,则在头结点添加该元素
self.insert_head(data)
else:
new_node = Node(data)
# 通过循环,得到新结点正数顺序的上一个结点
leftpos = self.length() + pos
pre = self.head
count = 0
while count < (leftpos - 1):
count += 1
pre = pre.next
# 让新结点指向原本该位置的结点
new_node.next = pre.next
# 让上一个结点指向新结点
pre.next = new_node
「删」:方法
10. delete_head() 删除头结点
def delete_head(self):
temp = self.head
if self.head:
self.head = temp.next
temp.next = None
11. delete_tail() 删除尾结点
cursor = self.head
if self.head:
if self.head.next is None:
self.head = None
else:
while cursor.next.next:
cursor = cursor.next
cursor.next, cursor = None, cursor.next
elif self.head == None:
return "This is an empty linked list."
12. remove(data) 删除结点,若存在值相等的结点,仅删除左起第一个
def remove(self, data):
"""
:return: 返回删除结点后的链表;若传入的数据在链表中不存在,则返回原链表
"""
if self.exist(data) == False:
return self
else:
pre = self.head
cursor = pre.next
count = 0
while cursor:
if cursor.data == data:
# 删除,也就是让该结点的上一结点直接连到该结点的下一结点
pre.next = cursor.next
cursor.next = None
return self
else:
pre = pre.next
cursor = cursor.next
13. removeall(data) 删除结点,若存在值相等的结点,删除所有
def removeall(self, data):
"""
:return: 返回删除结点后的链表;若传入的数据在链表中不存在,则返回原链表
"""
while self.exist(data):
self.remove(data)
return self
「改」:方法
14. setitem(index, data) 根据索引,为链表中该位置的值重新赋值
def setitem(self, index, data):
current = self.head
if current is None:
raise IndexError("This is an empty linked list.")
for i in range(1, index):
# 目标超过链表范围
if current.next is None:
raise IndexError("Index out of range")
current = current.next
current.data = data
其他方法
15. linklist(object) 传入对象,一次性将序列中的所有元素构建成一个链表
def linklist(self, object):
self.head = Node(object[0])
temp = self.head
for i in object[1:]:
node = Node(i)
# 将上一个结点指向下一个结点
temp.next = node
temp = temp.next
下一篇:Python实现单向链表(下):整合式实现增删改查操作
-
Info
- Author: Shanshan Yan
- Wechat: shanshan700224
- Copyright: All rights reserved