Python:链表构造与链表元素增删 【算法村E1链表笔记(青铜)】

前言

在几乎绝大多数的算法课中,链表都是放在第一节课的:链表非常基础而重要,对于后续理解、运用其他数据结构,或者学习算法来说,它都是很好的敲门砖。本篇文章,讲解如何在python中构造一个单链表,以及单链表的增加与删除操作。

(本文参考图片部分来自“Hello 算法”,这是一本Github上的开源书,也是非常优秀的学习材料,本文的行文风格和部分知识点也是来源于此;另外部分图片来自“编程导航算法村”,本文大部分知识点和思想过程来源于此)


目录

Python中如何构造一个链表

遍历链表(用于获取长度、查找目标值)

Python中增加链表元素

在链表首部增加元素

在链表中间增加元素

在链表尾部增加元素

总结

Python中删除链表元素

在链表首部删除元素

在链表中间删除元素

在链表尾部删除元素

总结

完整代码


Python中如何构造一个链表

(一个链表的结构如图所示)

链表(LinkedList)由节点(Node)顺序连接组成,每个节点包含一个值(Value)和指向下一个节点的指针(Pointer)或者叫引用(Reference)。

链表存在头节点(head),而且通常情况下,“头节点head”和“链表head”都是可以被接受的称呼。

链表的尾节点指向的是“空”,在Python中记为None。

链表定义方式:

class ListNode:
    """链表节点类"""
    def __init__(self,val:int):
        self.val = val   #节点值
        self.next = None # 指向下一节点的指针(引用)
    
    def get_data(self):
        return self.val
    
    def set_data(self,val):
        self.val = val
        
    def get_next(self):
        return self.next
    
    def set_next(self,next):
        self.next = next

在这样最正式的定义方式下,我们定义了链表节点类,并且使用四个set、get函数,来定义或获取每个节点的值以及节点之间的指向关系。

然而,在力扣(LeetCode)上的算法题中,还经常以另一种方式来创建链表:

class ListNode:
    def __init__(self,val=0,next=None):
        self.val = val
        self.next = next
# 创建实例
listnoode = ListNode(1)

这种定义方式下能直接使用listnode.val和listnode.next进行操作,虽然违背了面向对象的设计要求,但无疑更加精简和方便。

在定义完链表之后,我们进行初始化链表操作。

例如,问我们初始化链表1 -> 3 -> 2 -> 5 -> 4。

# 初始化各个节点 
n0 = ListNode(1)
n1 = ListNode(3)
n2 = ListNode(2)
n3 = ListNode(5)
n4 = ListNode(4)
# 构建引用指向
n0.next = n1
n1.next = n2
n2.next = n3
n3.next = n4

以上,我们成功实现了对链表的定义(创建)初始化这两个操作。


遍历链表(用于获取长度、查找目标值)

核心代码就是"head = head.next",可以理解成一个指针在不断向后移动。

第一种,遍历获取链表长度(就是节点的总个数)

def length(self):
    """链表长度"""
    # cur初始时指向头节点
    cur = self._head
    count = 0
    # 尾节点指向None,当未到达尾部时
    while cur != None:
        count += 1
        # 将cur后移一个节点
        cur = cur.next
    return count

(顺便一提,cur,pre,pos,target,count,temp,fast/slow(或fa/sl、f/s),res/ans,等都是常见变量名(因为大家都很偷懒(bushi,大意分别为:现在指针、前一指针、目标数、位置、计数、临时变量、快指针/慢指针、结果/答案,前两个在本文中就分别表示:现在的节点、前一个节点)

第二种,遍历链表,查找目标值:

def find(head: ListNode, target: int) -> int:
    """在链表中查找值为 target 的首个节点"""
    index = 0
    while head:
        if head.val == target:
            return index
        head = head.next
        index += 1
    return -1

Python中增加链表元素

当我们需要在链表的 第N个元素后面 插入一个新的节点,我们该如何做呢?

在链表首部增加元素

当我们需要在表头直接插入一个元素的时候,我们可以直接创建一个新节点(newNode),让新节点指向原有的头节点head即可。

为了方便后续操作,我们一般还将“修改后”的头节点head变为我们插入的这个新节点newNode。

在链表中间增加元素

 在中间增加元素较为复杂,因为我们需要先遍历找到正确的位置,随后进行修改。

而修改的过程同样有坑。

如下图,如果我们直接让(15)指向新节点(new),会导致原有的链表直接断开,因为新节点(new)的后面是一个None,而不是原来存在的(7)->(40)。

而且,由于此时原本的链表head已经被你修改过,Python会自动“帮你”回收掉“不需要”的原先后半截链表,甚至无法再改回最初的链表了。

因此,我们应该先创建一个指向关系,将新节点new和后续的(7)连接,再将(15)指向(new),如此我们总算让回收机制正确地帮助了我们(

image.png

在链表尾部增加元素

与首部相似,我们只需要让尾节点(40)指向新节点(new)即可(因为在定义的时候,我们让任何新节点new的nex都t默认为None)

image.png

总结

代码如下:

# 头部添加
def add(self, item):
    """头部添加元素"""
    node = Node(item)
    node.next = self._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):
    """指定位置添加元素"""
    if pos < 0:
        self.add(item)
    elif pos >= self.length():
        self.append(item)
    else:
        node = Node(item)
        pre = self._head
        count = 0
        while count < (pos-1):
            count += 1
            pre = pre.next
        node.next = pre.next
        node = pre.next

Python中删除链表元素

当我们知道怎样增加链表元素,那么删除也是类似的。

在链表首部删除元素

与增加相反:当插入元素时,我们让新节点newNode.next=head,创造了一个指向关系;当删除时,我们舍去一层指向关系,让head.next等于head,即让(15)变成这个链表新的头节点。

image.png

在链表中间删除元素

在中间删除也是同样的较为复杂,因为我们仍然需要先遍历、再操作。

为了同样避免链条断开的风险。我们在删除操作中需要先遍历到要删除元素之前,这个先前节点的指针指向next的next,即直接跳过要被删除的元素。

核心代码:cur.next=cur.next.next

image.png

在链表尾部删除元素

同样需要遍历,不过这次的遍历是遍历到最后一个元素之前,即倒数第二个元素,让倒数第二个元素的next变为None即可。

image.png

总结

代码如下:

def remove(self, item):
    """删除节点"""

    cur = self._head
    pre = None

    while cur != None:

        if cur.item == item:
            if pre is None:
                self._head = cur
            else:
                pre.next = cur.n

        else:
            pre = cur
            cur = cur.next

完整代码

class Node(object):
    """单链表节点"""

    def __init__(self, item):
        # _item存放数据元素
        self.item = item
        # _next是下一个节点的标识
        self.next = None

    def is_empty(self):
        """判断链表是否为空"""
        return self._head == None

    def length(self):
        """链表长度"""
        cur = self._head
        count = 0
        while cur != None:
            count += 1
            cur = cur.next
        return count

    # 头部添加
    def add(self, item):
        """头部添加元素"""
        node = Node(item)
        node.next = self._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):
        """指定位置添加元素"""
        if pos < 0:
            self.add(item)
        elif pos >= self.length():
            self.append(item)
        else:
            node = Node(item)
            pre = self._head
            count = 0
            while count < (pos-1):
                count += 1
                pre = pre.next
            node.next = pre.next
            node = pre.next

    # 删除结点
    def remove(self, item):
        """删除节点"""
        cur = self._head
        pre = None
        while cur != None:
            if cur.item == item:
                if pre is None:
                    self._head = cur.next
                else:
                    pre.next = cur.next
            else:
                pre = cur
                cur = cur.next

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值