单链表
其实可以简单的理解为数组,但只要用的好,实际功能是远远大于数组的,再此次文章中,我们暂且可以简单理解为数组,但不要被误导,两者实际上还有很多的不同(比如说数组的随机访问时间复杂度为O(1)而单链表为O(n)等等等等)
举个简单的链表
list = [ 1, 2, 3, 4, 5] // 我们可以将其画出来,就像这样
1 -> 2 -> 3 -> 4 -> 5 //这里的每个数组就是链表的节点并通过 " -> " 串在了一起
意思也就是说,我们只要能将一些零零散散的节点像烤串一样串在一起,那么就是实现了一个简单的链表
算法逻辑
第一步(节点)
节点中需要存放数据,并且要利用指针访问
class node:
def __init__(self,data):
self.data = data
self.next = None
第二步(连接链表)
链表的链接与节点数据的存放是辩证统一的,两者缺一不可。
一个最基础的链表,至少具有插入元素和输出元素的功能,不过在此我也会实现链表的一些其他功能(随机访问,随机插入,排序等等等等)
链表功能
插入节点
表尾插入
意思就是说,我们将从头开始遍历链表(链表头号元素不为空的时候),持续遍历到不存在下一个节点为止,当程序发现不存在下一个节点时,在此处插入新的节点
def insert(self,data):
new_node = node(data)
if self.head == None:
self.head = new_node
else:
current = self.head
while current.next:
current = current.next
current.next = new_node
随机插入
和上述方法类似,也会从头开始遍历链表,但不会一直遍历到表尾(除非插入位置的值大于链表的长度),当遍历链表直至num的位置时插入新的节点
num = 我们需要插入元素的位置,并在此位置的左侧插入新的节点
def rand_insert(self,num,data):#在左侧插入
new_node = node(data)
if self.head == None:
self.head = new_node
else:
current = self.head
count = 0
while current.next and count < num:
current = current.next
count += 1
if current.next:
new_node.next = current.next
current.next = new_node
else:
current.next = new_node
这里着重说明一些核心代码
new_node.next = current.next
这一行将新节点的下一个节点指向当前节点的下一个节点。这样做的目的是在当前节点和它的下一个节点之间插入新节点,使得新节点成为当前节点的下一个节点。
current.next = new_node
这一行将当前节点的下一个节点更新为新节点。这样,新节点就被正确地插入到了链表中
输出链表
或许看到这里你也已经明白怎么输出链表了,还是跟上述插入节点一样,从表头开始遍历链表,每遍历完一个节点就输出这个节点的值即可
def display(self):
if self.head == None:
return
else:
current = self.head
while current.next:
print(current.data,end = "->")
current = current.next
print(current.data)
删除节点
有链表的插入那么也就有节点的删除,这里将通过访问链表中节点的位置来删除节点,就跟数组类似,访问到目标节点时停止遍历,使指向该节点的指针指向下一个节点,从而“跳过”此节点直接访问下一个节点
def delete(self,num):
if self.head == None:
return
else:
current = self.head
count = 0
if num == 0:
self.head = current.next
while count < num - 1:
current = current.next
count += 1
current.next = current.next.next
返回链表长度
无需多元,从头开始遍历,设定一个计数器count使每遍历完一个节点进行count += 1 的操作,最后返回的count的值即为链表的长度
def len(self):
if self.head == None:
return
else:
current = self.head
count = 1
while current.next:
current = current.next
count += 1
return count
随机访问
位置访问
跟数组一样,在下表上写上链表中元素的位置,程序就会给你返回此位置元素的值,原理还是跟上述方法一样,从头开始遍历,直至遍历到num时停止并返回此时遍历到的元素的值即可
num = 需要访问的元素的位置
def value(self,num):
if self.head == None:
return
else:
current = self.head
count = 0
while count < num:
current = current.next
count += 1
return current.data
查找元素
给定一个数,查看链表中是否有这个数。
一般情况下我们可以通过遍历链表来实现,这是最无脑且有效的办法,但如果题目中有一些特殊情况,比如已排序的链表之类的话,那么我们可以用二分查找等方式降低程序的时间复杂的
不过遍历链表查找元素的时间复杂度也不高,为O(n)
num = 我们要查找的元素的值
def get(self,num):
if self.head == None:
return
else:
for i in range(self.len()):
if self.value(i) == num:
print(f"找到元素{num},其位置为{i}")
return
print("链表中不存再该元素")
链表的排序
就跟数组的排序一样,根据链表中节点的值或者一些其他要求进行排序,这里以冒泡排序为例,不过冒泡排序是一个时间复杂度相对较高O(n**2)的排序方式,也是最简单通俗易懂的排序方式,在此不会多讲,博主会在下一期文章中专门讲11中不同的排序方式。
链表排序的底层逻辑就是节点内数据的交换,至于怎么交换,那么就取决于使用了什么样的排序方式了
def bubble_sort(self):
if self.head == None:
return
else:
swapped = True
while swapped:
swapped = False
current = self.head
while current.next:
if current.data > current.next.data:
current.data, current.next.data = current.next.data, current.data
swapped = True
current = current.next
完整代码
class node:
def __init__(self,data):
self.data = data
self.next = None
class linked_list:
def __init__(self):
self.head = None
def insert(self,data):
new_node = node(data)
if self.head == None:
self.head = new_node
else:
current = self.head
while current.next:
current = current.next
current.next = new_node
def display(self):
if self.head == None:
return
else:
current = self.head
while current.next:
print(current.data,end = "->")
current = current.next
print(current.data)
def len(self):
if self.head == None:
return
else:
current = self.head
count = 1
while current.next:
current = current.next
count += 1
return count
def value(self,num):
if self.head == None:
return
else:
current = self.head
count = 0
while count < num:
current = current.next
count += 1
return current.data
def rand_insert(self,num,data):#在左侧插入
new_node = node(data)
if self.head == None:
self.head = new_node
else:
current = self.head
count = 0
while current.next and count < num:
current = current.next
count += 1
if current.next:
new_node.next = current.next #这一行将新节点的下一个节点指向当前节点的下一个节点。这样做的目的是在当前节点和它的下一个节点之间插入新节点,使得新节点成为当前节点的下一个节点。
current.next = new_node #这一行将当前节点的下一个节点更新为新节点。这样,新节点就被正确地插入到了链表中。
else:
current.next = new_node
def get(self,num):
if self.head == None:
return
else:
for i in range(self.len()):
if self.value(i) == num:
print(f"找到元素{num},其位置为{i}")
return
print("链表中不存再该元素")
def delete(self,num):
if self.head == None:
return
else:
current = self.head
count = 0
if num == 0:
self.head = current.next
while count < num - 1:
current = current.next
count += 1
current.next = current.next.next
def bubble_sort(self):
if self.head == None:
return
else:
swapped = True
while swapped:
swapped = False
current = self.head
while current.next:
if current.data > current.next.data:
current.data, current.next.data = current.next.data, current.data
swapped = True
current = current.next
list = linked_list()
list.insert(5)
list.insert(4)
list.insert(3)
list.insert(2)
list.insert(1)
print("链表初始化为:")
list.display()
num = 4
list.delete(num)
print(f"删除第{num + 1}节点后")
list.display()
print("长度为:",list.len())
print("此位置元素值为:",list.value(1))
list.get(2)
list.display()
list.rand_insert(1,9999)#在左侧插入
list.display()
list.bubble_sort()
print("排序后的链表为:")
list.display()
这就是本期文章的全部内容了,希望对你有帮助,在评论区留下自己的观点给博主提提建议。
当然,最重要的是,自己试试看吧,你会做的更好