Python 数据结构——链表(一)

单链表

其实可以简单的理解为数组,但只要用的好,实际功能是远远大于数组的,再此次文章中,我们暂且可以简单理解为数组,但不要被误导,两者实际上还有很多的不同(比如说数组的随机访问时间复杂度为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()

这就是本期文章的全部内容了,希望对你有帮助,在评论区留下自己的观点给博主提提建议。

当然,最重要的是,自己试试看吧,你会做的更好

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值