图解+编写链表之:python模拟单向链表

(一)链表概念:

线性结构有顺序表和链表两种存储方式。链表( Linked list )是一种常见的线性结构,也是基础数据结构,不会按线性的顺序存储数据,而是在每⼀个节点里存到下⼀个节点的指针 (Pointer)。 所以链表结构不需要一块连续的内存空间 ,它通过 ” 指针 ” 将一组零散的内存块串联起来使用。由节点(Node)组成,根据节点以及连接方式的不同,分为单向链表、单向循环链表、双向链表、双向循环链表。本文用python模拟单项链表展示其工作原理。

(二) 相关类:

SingleNode: 表示节点类

SingleLinkedList:表示(单向)链表类

(三)相关方法:

is empty():判断链表是否为空

length():查看链表长度

travel():遍历整个链表

add():链表头部添加元素

append():链表尾部添加元素

insert():中间指定位置添加元素

remove():删除节点

search():查找节点是否存在

(四)实现步骤:

1:定义类和初始化类的属性
# 1. 定义SingleNode类, 表示节点类.
class SingleNode:
    # 初始化节点的信息.
    def __init__(self,item):
        # 元素域, 数值域: 存储具体数据的.
        self.item = item
        # 链接域, 地址域: 存储下个节点的地址的.
        self.next = None
# 2. 定义SingleLinkedList类, 表示: (单向)链表
class SingleLinkedList:
    # 2.1 初始化链表
    def __init__(self,node = None):
        # head(默认)指向 链表中的第1个节点.
        self.head = node

2:实现  is empty()、length()、travel()、add()、append()  相关方法
# 2.2 完成功能: is_empty(), 判断列表是否为空
    def is_empty(self):
        # 思路: 判断头结点是否为空.
        # 写法1: if.else
        # if self.head == None:
        #     return True
        # else:
        #     return False

        # 写法2: 三目运算符
        # return True if self.head == None else False

        # 写法3: 最终版
        return self.head == None

    # 2.3 完成功能: length(self) 链表长度
    def length(self):
        # 1. 定义 cur(current单词)变量, 记录: 当前的节点, 初值为: 头结点.
        cur = self.head
        # 2. 定义计数器, 记录: 节点个数.
        count = 0
        # 3. 循环实现, 判断cur(当前节点)是否为None, 如果不是, 就一直循环.
        while cur is not None:
            # 4. 进这里, 说明是1个非空节点, 计数器 + 1
            count += 1
            # 5. 判断当前节点后, cur指向下1个节点.
            cur = cur.next
        # 6. 返回结果.
        return count

    # 2.4 完成功能: travel(self) 遍历整个链表
    def travel(self):
        # 1. 定义 cur变量, 用于记录: 链表中的每个节点信息. 初值: head(头结点)
        cur = self.head

        # 2. 判断当前节点是否为空, 不为空, 就一直循环.
        while cur is not None:
            # 3. 不为空, 就说明有节点信息, 打印即可.
            print(cur.item)
            # 4. cur指向下1个节点.
            cur = cur.next

    # 2.5 完成功能: add(self, item) 链表头部添加元素
    def add(self,item):
        # 1. 根据内容(元素值), 创建节点
        new_node = SingleNode(item)
        # 2. 设置新节点的(地址域)为 self.head(之前的头结点)
        new_node.next = self.head
        # 3. 更新head属性值, 因为head是指向(新的)头结点
        self.head = new_node

    # 2.6 完成功能: append(self, item) 链表尾部添加元素
    def append(self,item):
        # 1. 根据内容(元素值), 创建节点
        new_node = SingleNode(item)
        # 2. 判断链表是否为空, 为空, 则: 用head直接指向新节点(充当头部节点)即可.
        if self.head == None:
               # 新节点就是头部节点
               self.head = new_node
        else:
            # 3. 走这里, 说明链表不为空, 我们就获取链表的最后1个节点.
            # 3.1 创建cur变量, 默认指向头部节点.
            cur = self.head
            # 3.2 逐个判断, 只要当前节点的地址域不为None, 就一直获取.
            while cur.next is not None:
                # 更新当前节点
                cur = cur.next
            # 3.3 走到这里, 循环结束, 说明获取的节点就是最后1个节点(它的地址域为None)
            # 设置它(最后1个节点)的地址域为: 新的节点即可.
            cur.next = new_node
3:实现insert()指定位置添加元素功能

图解:

 # 2.7 完成功能: insert(self, pos, item) 指定位置添加元素
    def insert(self,pos,item):                                  # pos表示添加的位置
        # 1. 判断添加位置, 如果是 小于等于0的, 就在首部添加.
        if pos <= 0:
            self.add(item)
        # 2. 如果添加位置, 大于等于 链表的长度, 就在链表尾部添加.
        elif pos >= self.length():
            self.append(item)
        # 3. 走这里, 说明是在链表的中间添加, 正常写逻辑即可.
        else:
            # 4. 创建新节点.
            new_node = SingleNode(item)
            # 5. 创建cur变量, 用于指向: 插入位置前的那个节点. 默认: 头结点
            cur = self.head
            # 6. 定义count变量, 用于: 计数, 获取插入位置前的值.
            count = 0
            # 7. 循环判断, 获取插入位置前的那个元素.
            while count < pos -1:
                cur = cur.next
                # 计数器 + 1
                count += 1
            # 走到这里, cur记录的就是: 插入位置前的那个元素.
            # 8. 设置新节点的地址域为: 当前节点的地址域
            new_node.next = cur.next
            # 9. 设置当前节点的地址域为: 新的节点.
            cur.next = new_node
4:实现remove()删除节点功能

1)图解删除的是头部节点

2)图解删除的是中间节点

# 2.8 完成功能: remove(self, item) 删除节点
    def remove(self,item):
        # 1. 定义变量cur, 从头结点开始, 逐个查找, 获取到: 被删除的节点.
        cur = self.head
        # 2. 定义变量pre, 表示: 被删除的节点的 前置节点.
        pre = None
        # 3. 只要cur不为空, 我们就一直遍历, 获取每个节点.
        while cur is not None:
            # 4. 判断当前节点的数值域 是否和 要删除的内容(元素值) 相同.
            # 4.1 如果相同, 说明要被删除, 我们还需判断, 要删除的节点是否是 头部节点.
            if cur.item == item:
                # 4.1.1 如果是头部节点, 直接用 head 指向 cur.next即可
                if cur == self.head:
                    self.head = cur.next
                # 4.1.2 如果不是头部节点, 我们用 pre变量来记录 当前节点的地址域(下个节点)
                else:
                    pre.next = cur.next
                # 核心细节: 删除元素后, 循环终止.
                break
                # return

            else:
                # 4.2 如果不同, 说明当前节点不是要被删除的节点, 我们继续判断下1个节点.
                pre = cur                         # 当前节点(检验过) 充当前置节点.
                cur = cur.next                    # 我们继续判断下1个节点.
5:完成search()查询功能
  # 2.9 完成功能: search(self, item) 查找节点是否存在
    def search(self,item):
        # 1. 定义变量cur, 记录每个节点, 初值为: 头部节点.
        cur = self.head

        # 2. 如果cur节点不为空, 我们就一直遍历.
        while cur is not None:
            # 3. 判断当前节点的item值, 是否和要查找的item值一致.
            if cur.item == item:
                # 走这里, 匹配上了,
                return True
            # 4. 走这里, 说明没有匹配上, 我们继续判断下一个节点.
            else:
                cur = cur.next
        # 5. 整个循环结束, 走到这里, 说明没有找到.
        return False
6:main方法中测试
# 3. 在main方法中测试
if __name__ == '__main__':

    # 3.1 创建单个节点.
    sn1 = SingleNode('孙悟空')
    print(sn1.item)     # 当前节点的: 元素域值
    print(sn1.next)     # 当前节点的: 地址域值
    print('-'*30)

    # 3.2 创建链表.
    linked_list = SingleLinkedList(sn1)
    print(f'目前的头节点是:{linked_list.head}')

    # 3.3 判断链表是否为空.
    print(linked_list.is_empty())
    # 3.4 打印链表的长度(元素个数)
    print(f'链表的长度为:{linked_list.length()}')
    print('-' * 30)

    # 3.6 演示添加, 在: 链表头部添加.
    # linked_list.add('虚竹')
    # linked_list.add('段誉')

    # 3.7 演示添加, 在: 链表尾部添加.
    linked_list.append('唐僧')
    linked_list.append('猪八戒')
    linked_list.travel()
    print(f'链表的长度为:{linked_list.length()}')
    print('-' * 30)

    # 3.8 演示添加, 在: 链表中间添加(插入元素).
    # 本来是: 乔峰, 虚竹, 段誉, 添加后是: 乔峰, 虚竹, 夯哥, 段誉
    linked_list.insert(2,'沙和尚')
    # 3.9 演示 删除.


    # 3.10 最后, 再次打印链表内容.
    linked_list.travel()
    print('-' * 30)

    # 3.11 演示 查找.
    print(linked_list.search('唐僧'))
    print(linked_list.search('白骨精'))

  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值