[Python-链表]

最近在跟着卡尔老师学算法,所以现在不定时会更新自己所学的内容,毕竟最好的学就是教嘛:)

什么是链表?

链表(Linked List)是一种基础的数据结构,用于组织和存储一系列元素。链表中的元素被组织成节点,每个节点包含数据和一个指向下一个节点的引用(指针或链接),即每个节点包含了两种内容:数据域和指针域。

链表的类型

1.单链表

在单向列表中,节点有数据域data与指针域next,链表的最后一个节点的next指向空。

2.双链表

上面说到单链表只有一个指针域,因此只能向后查找,而双链表具有两个指针域,就可以兼顾向后查找与向前查找了。

3.循环链表

循环链表,顾名思义就是链表的首尾相连,是一个闭环结构。

链表基础功能的实现

1.初始化节点与单向链表

以单链表为例,单链表具有一个数据域和一个指针域用于指向下一个节点,因此可以在python中利用class结构定义节点,如下:

#初始化节点
class Node:
    def __init__(self,data,next):
        self.data=data #数据域
        self.next=next #指针域,通常赋值为null或者另一个Node节点,表示指针指向下一个节点

#初始化单向链表
class LinkedList:
    def __init__(self):
        self.head=None #头节点

在Python中,__init__ 方法是一个特殊的方法,用于在创建类的实例时进行初始化。第一个参数通常被命名为 self,表示类的实例本身。在__init__ 方法内部,可以为该实例设置属性,并不需要在输入参数中定义。

2.在尾部添加节点

思路为:

1.先新建一个节点new_Node,data为输入值,next为null;

2.检测单向链表中有没有节点,如果没有,直接将头节点指向该新建节点即可。如果有,则进入下一步;

3.可以额外建立一个新节点last_Node,用该节点进行遍历,一直到链表末端。遍历过程为将头节点赋值给last_Node,利用while循环不断判断last_Node的next是否为空,当为空时,last_Node就到了链表的最后一个节点位置,此时只需要将next_Node的next指向new_Node即可。

如下图所示:

代码如下:

#添加节点
    def append(self,data):
        new_node = Node(data,next=None) #新建节点,数据域为传入参数data,next赋为None
        #如果当前链表为空,那么链表的头节点为新建节点
        if self.head == None:
            self.head = new_node
            return True 
        #如果不为空,就从链表的头节点开始遍历,直到找到next为None的尾节点
        last_Node = self.head #新建一节点,赋值为链表头节点
        while last_Node.next != None: #当前节点的指针域不指向None时,说明当前节点不为尾节点
            last_Node = last_Node.next
        #循环结束,last_Node为尾节点
        last_Node.next = new_node

好了,现在我们完成了一个添加节点的功能,那么我们该怎么测试一下写的对不对呢?

就再写一下第二个基础功能,打印链表吧。

3.打印链表

打印链表的思路其实就是遍历输出,与上一个基础功能中的步骤三很像,只不过就是在遍历的过程中多加了一个print函数,代码如下:

#输出链表
    def show(self):
        current_node = self.head #新设置一个节点,赋值为头节点
        while current_node : #只要当前节点不为空,就一直输出
            print(current_node.data,end=" ")
            current_node = current_node.next
        print() #这里的print单纯换行作用

这里还要注意一点,在添加节点功能的遍历过程中,while的条件是current_node的next不为空,这样循环在终止时,current_node是刚好到了链表中的最后一个元素就退出循环了,如果在打印过程中还这么写就会略去最后一个元素。因此这里的终止条件采用判断当前节点是否为空。

接下来我们就可以先测试一下我们的代码了,到目前为止的整体代码如下:

#定义节点
class Node:
    def __init__(self,data,next):
        self.data = data
        self.next = next
​
#定义单向链表
class LinkedList:
    def __init__(self):
        self.head = None
    
    def append(self,data):
        new_Node = Node(data,next=None)
        if self.head == None :
            self.head = new_Node
            return True
        
        last_Node = self.head
        while(last_Node.next):
            last_Node = last_Node.next
        
        last_Node.next = new_Node
        return True
    
    def show(self):
        current_node = self.head #新设置一个节点,赋值为头节点
        while current_node : #只要当前节点不为空,就一直输出
            print(current_node.data,end=" ")
            current_node = current_node.next
        print() #这里的print单纯换行作用
​
#新建一个链表
list = LinkedList()
list.append(1)
list.append(2)
list.append(4)
list.append(8)
list.append(16)
list.append(32)
list.show()

结果如下:

1 2 4 8 16 32 

现在已经可以在链表尾部添加节点并打印展示了。

4.在首部添加节点

当然,除了在尾部添加节点外,链表添加节点的方式还有从首部添加以及从链表中间位置添加,下面就先来介绍较为简单的首部添加节点。

思路为,新建一个节点new_Node,将其next指向头节点。只是这样就可以了吗?当然不对,还要将代表该链表起始位置的头节点换成新节点才可以,这样新添加的节点才能作为新链表的头节点,否则打印还是从原本的头节点开始打印的。如下图所示:

明显,代码应写为如下:

def append_head(self,data):
        new_Node = Node(data,next=None) #新设插入节点
        new_Node.next = self.head #将新节点的next赋值为头节点
        self.head = new_Node #头节点更新为新节点
5.在链表中插入节点

在链表中插入节点,需要将原链表中的两个节点的连接打破,然后两个节点分别作为新节点的头与尾,如下所示:

因此,实现的时候要同时记录下两个节点的位置,设当前节点为current_Node,前一节点为pre_Node,那么只需要再设置一个变量用于计算位置,就可以准确找到需要插入的点了。找到之后,将pre_Node的next指向new_Node,将new_Node的next指向current_Node即可。代码实现如下:

#在第index个节点前插入新节点
    def append_mid(self,data,index):
        new_Node = Node(data,next=None) #需要插入的节点
        current_Node = self.head #遍历节点,从头节点开始
        pre_Node = None #前一节点,先设为None
        cnt = 1 #计数,用于测量位置
        
        if index <= 0:
            print("index应大于等于1")
            return False
​
        #特殊情况,当需要在首部插入元素时
        if index == 1:
            self.append_head(data)
            return True
        #开始遍历,找到需要插入节点的位置
        while cnt < index and current_Node:
            pre_Node = current_Node #将前一节点赋值为current_Node
            current_Node = current_Node.next #将当前节点赋为下一节点
            cnt += 1 #位置加一
            
        pre_Node.next = new_Node 
        new_Node.next = current_Node
        return True

测试代码:

#定义节点
class Node:
    def __init__(self,data,next):
        self.data = data
        self.next = next
​
#定义单向链表
class LinkedList:
    def __init__(self):
        self.head = None
    
    def append(self,data):
        new_Node = Node(data,next=None)
        if self.head == None :
            self.head = new_Node
            return True
        
        last_Node = self.head
        while(last_Node.next):
            last_Node = last_Node.next
        
        last_Node.next = new_Node
        return True
    
    def append_head(self,data):
        new_Node = Node(data,next=None)
        new_Node.next = self.head
        self.head = new_Node
    
    def append_mid(self,data,index):
        new_Node = Node(data,next=None)
        current_node = self.head
        pre_Node = None
        cnt = 1
​
        if index == 1:
            self.append_head(data)
            return False
​
        while cnt < index and current_node:
            pre_Node = current_node
            current_node = current_node.next
            cnt += 1
        
        pre_Node.next = new_Node
        new_Node.next = current_node
    
    def show(self):
        current_node = self.head #新设置一个节点,赋值为头节点
        while current_node : #只要当前节点不为空,就一直输出
            print(current_node.data,end=" ")
            current_node = current_node.next
        print() #这里的print单纯换行作用
​
#新建一个链表
list = LinkedList()
list.append(1)
list.append(2)
list.append(4)
list.append(8)
list.append(16)
list.append(32)
list.show()
list.append_head(0)
list.show()
list.append_mid(5,3)
list.show()

测试结果:

1 2 4 8 16 32 
0 1 2 4 8 16 32
0 1 5 2 4 8 16 32

到目前为止,我们已经成功实现了单向链表的添加节点操作与打印操作,下面再来学习一下如何删除链表中的节点。

5.删除链表中的某个节点

插入节点是将前一节点与后一节点的连接打碎,然后将前一节点的next指向新建的节点,将新建节点的next指向后一节点的过程。那么我们反过来想,删除节点是怎么操作呢?也是将三个节点之间的连接打碎,然后将前一节点的next跳过中间节点,直接指向下一节点即可,如下所示:

那么我们很容易想到,在代码实现中,我们同样需要用一个计数器来测量位置,用一个current_Node节点来遍历链表,以此找到需要删除的节点位置,同时还需要一个pre_Node节点来记录前一节点的位置。这样找到需要删除的节点后,只需要将pre_Node的next指向当前节点current_Node的next节点即可。

代码实现如下:

#删除某位的节点,index从1开始,表示第几个位置的节点
    def delete_Node(self,index):
        if index < 1:
            print("无效输入")
            return False
        current_Node = self.head #作为遍历节点
        pre_Node = None
        cnt = 1 #计数器,计量位置
        if index == 1:
            self.head = self.head.next
            return True
        while cnt < index :
            cnt += 1
            if current_Node.next:
                pre_Node = current_Node
                current_Node = current_Node.next
            else:
                return False #这里代表index已经超过了链表的长度,需要删除的节点不存在
        pre_Node.next = current_Node.next
        return True

至此,python中链表的基本操作差不多就结束了,下面就要开始学习力扣上链表的相关题目了,欢迎大家批评指正!

  • 24
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值