用python手把手教你实现单向链表

2023-11-28 21:26:54 浏览数 (1)

用python手把手教你实现单向链表

简介

  • 选题 - 用python手把手教你实现单向链表
  • 详细说明 链表在python中使用类(相当于C中的结构)实现链表,实现方法也同C语言一样,但是python中没有指针的概念,并且实践中还有其他大大小小的问题,希望可以看到大佬的实践步骤

在互换选题中想尝试着做一下这道题,之前在写C的项目经常有用到单链的相关的一些东西,在做动态扩展或者入参时参数不定长,通常用单链来操作相关内容,在python还没有考虑相关的或者说尝试过一些相关的东西。看到这道选题,还是比较有兴趣尝试的。

思路

拿到选题的时候第一反应是:在python中有一个原生库用来兼容或者引用c库,就是 ctypes ,使用ctypes来实现相关功能,后来考虑一下,拿 ctypes 来实现单链其实没有什么意义或者说绕了远路。就需要考虑另一个种方式来实现单链。

单链在C中的表现形式常常为

代码语言:c复制
struct node{
    void* value;
    node* next;
}

关键点为 node*,指针成员。指针的本质来说就是地址的相关操作,所以只需要考虑在python中可不可以获取到变量或者说对象的地址,让我们可以根据地址来索引到操作对象的值,然后思路就很明确了,其中有2个关键点

  1. 获取操作对象的地址
  2. 根据地址获取操作对象或者操作对象的值

第一个关键点:在python中每一个对象有一个基本属性 id(),id(object)既可以获取对象的地址。

第二个关键点:python中没有相关方法根据地址获取操作对象的值,可以变动一下,自己做一个字典或者相关容器map之类的来保存 id还有 obj,做一个地址索引或者说一对一索引表。

代码实现

根据上述思路,第一步先实现索引表,这里我选择的是字典。

地址字典

在关于单链的实现中,字典具有全局唯一的属性,但是在全局中可能随时进行增删等相关操作,这里就需要考虑 单例模式来实现字典。

地址的类型为int,所以在字典元素key入参时,需要校验id类型是否为int类型。

字典要实现关于item的增删功能。即代码如下:

代码语言:python代码运行次数:0复制
class IdList:
    #实现单例模式
    _instance = None
    def __new__(cls):
        if not cls._instance:
            cls._instance = super().__new__(cls)
            return cls._instance

    def __init__(self):
        self.id_list = {}
     #增加元素   
    def add_item(self, item):
        self.id_list[id(item)] = item
	#获取元素
    def get_item(self, item_id):
        if item_id in self.id_list:
            return self.id_list.get(item_id)
        else:
            return "null"
    #删除元素
    def del_item_id(self, item_id):
        self.id_list.pop(item_id)
    
    def clean(self):
        self.id_list.clear()

第二步,实现单链节点

单链Node

在链表中,单链节点的表现形式通俗意义上是 以及下一个节点的地址,即单个节点要有如下属性:

1. 值的设置与获取 2. 地址的设置与获取,且当地址有效时地址类型必须为int类型

在python中,因为增加了地址字典,所以又有一个新增特性

  1. node同步到地址字典

即代码实现如下:

代码语言:python代码运行次数:0复制
class LinkList:
    def __init__(self):
        #初始化默认为空,可以随意自定义
        self.item_value = "null";
        self.item_id = "null";
    #设置值
    def set_value(self, item_value):
        self.item_value = item_value
	#设置关联地址字典
    def set_list(self, item_list):
        self.id_list = item_list
	#设置下一节点地址
    def set_id(self, item_id):
        #校验地址类型
        if not isinstance(item_id, int):
            return
        if self.id_list.get_item(item_id) == "null":
            return
        self.item_id = item_id
	#获取下一节点地址
    def get_id(self):
        return self.item_id
    #获取值
    def get_value(self):
        return self.item_value

剩下的就是具体功能特性的实现以及测试

测试

有了上诉的基础属性之后,就可以着手进行单链的实现与测试了。

单链不管在任何场景中,使用的功能特性基本为增加节点删除节点插入节点修改指定节点值 所以基本围绕着这几个功能特性来实现相关代码即可。

代码demo如下:

  • 增加节点
代码语言:python代码运行次数:0复制
def add_node(node_value):
    node = LinkList()
    node.set_value(node_value)
    node.set_list(id_list)
    id_list.add_item(node)
    if nodes.get_id() == "null":
        nodes.set_id(id(node))
        return
    buf_node = nodes
    while buf_node.get_id() != "null":
        buf_node = id_list.get_item(buf_node.get_id())
        if buf_node.get_id() == "null":
            buf_node.set_id(id(node))
            break
  • 删除节点

在删除节点中,有2个特殊点需要注意一下,删除第一个节点还有删除最后一个节点

代码语言:python代码运行次数:0复制
def del_node(node_index):
    last_id = id(nodes)
    last_node = nodes
    buf_node = nodes
    
    if node_index == 0 and buf_node.get_id() != "null":
        buf_value = buf_node.get_value()
        buf_node = id_list.get_item(buf_node.get_id())
        nodes.set_value(buf_value)
        nodes.set_id(buf_node.get_id())
        id_list.del_item_id(last_id)
        return
    
    index = 0
    while buf_node.get_id() != "null":
        if index == node_index:
            if buf_node.get_id() != "null":
                last_node.set_id(buf_node.get_id())
            else:
                last_node.set_id("null")
            id_list.del_item_id(last_id)
            return
        last_id = buf_node.get_id()
        last_node = buf_node
        buf_node = id_list.get_item(buf_node.get_id())
        index  = 1
  • 插入节点

在插入节点中,有一个特殊点需要注意,插入节点为第一个节点

代码语言:python代码运行次数:0复制
def insert_node(node_index, node_value):
    node = LinkList()
    node.set_value(node_value)
    node.set_list(id_list)
    id_list.add_item(node)

    last_id = id(nodes)
    last_node = nodes
    buf_node = nodes
    
    if node_index == 0:
        buf_value = nodes.get_value()
        buf_id = nodes.get_id()
        nodes.set_value(node.get_value())
        nodes.set_id(id(node))
        node.set_id(buf_id)
        node.set_value(buf_value)
        print("insert node sucess!")
        return
    
    index = 0
    while buf_node.get_id() != "null":
        if index == node_index:
            last_node.set_id(id(node))
            node.set_id(last_id)
            print("insert node sucess!")
            return
        last_id = buf_node.get_id()
        last_node = buf_node
        buf_node = id_list.get_item(buf_node.get_id())
        index  = 1
  • 修改指定节点值
代码语言:python代码运行次数:0复制
def modify_node(node_index, node_value):
    buf_node = nodes
    index = 0
    while buf_node.get_id() != "null":
        if index == node_index:
            buf_node.set_value(node_value)
            print("node_index value modify sucess!")
            return
        buf_node = id_list.get_item(buf_node.get_id())
        index  = 1
    print("node_index value is error!")

测试场景如下:

代码语言:python代码运行次数:0复制
#test -- add node
add_node("2")
add_node("3")
add_node("4")
print_nodes()
#test -- del node
del_node(0)
print_nodes()
#test -- add node
add_node("何其不顾四月天")
add_node("单链表")
print_nodes()
#test -- modify node value
modify_node(0, "云 社区")
modify_node(1, "互换选题活动")
modify_node(2, "测试演示")
print_nodes()
#test -- insert node
insert_node(0, "insert test")
print_nodes()
insert_node(2, "insert test 1")
print_nodes()

测试结果输出为:

代码语言:shell复制
-------------
0 1
1 2
2 3
3 4
-------------
0 1
1 3
2 4
-------------
0 1
1 3
2 4
3 何其不顾四月天
4 单链表
node_index value modify sucess!
node_index value modify sucess!
node_index value modify sucess!
-------------
0 云 社区
1 互换选题活动
2 测试演示
3 何其不顾四月天
4 单链表
insert node sucess!
-------------
0 insert test
1 云 社区
2 互换选题活动
3 测试演示
4 何其不顾四月天
5 单链表
insert node sucess!
-------------
0 insert test
1 云 社区
2 insert test 1
3 互换选题活动
4 测试演示
5 何其不顾四月天
6 单链表

附言

在实际的工程代码中,我所实现的是一个很基础的demo,在具体的功能特性中,也可以单独封一个实现类,继续向上层抽象,提升代码的复用。也可以我的代码为模板继续实现各种链表结果,因为链表的本质还是对上下节点的地址索引,双向链表再增加一个地址属性既可。

我的基本思路如上,如果有其它的看法或者更好的实现方法可以留言或者邮件沟通。

附录-代码

其中有两个代码文件:

文件一:link_list.py

代码语言:python代码运行次数:0复制
'''
Author: 何其不顾四月天
Date: 2023-11-28 10:11:43
LastEditors: 何其不顾四月天
LastEditTime: 2023-11-28 12:32:19
FilePath: pythonlink_list.py
Description: python生成单链表

Copyright (c) 2023 by 779508400@qq.com. 
'''
import os

class IdList:
    _instance = None
    def __new__(cls):
        if not cls._instance:
            cls._instance = super().__new__(cls)
            return cls._instance

    def __init__(self):
        self.id_list = {}
        
    def add_item(self, item):
        self.id_list[id(item)] = item

    def get_item(self, item_id):
        if item_id in self.id_list:
            return self.id_list.get(item_id)
        else:
            return "null"
    
    def del_item_id(self, item_id):
        self.id_list.pop(item_id)
    
    def clean(self):
        self.id_list.clear()

class LinkList:
    def __init__(self):
        self.item_value = "null";
        self.item_id = "null";
        
    def set_value(self, item_value):
        self.item_value = item_value

    def set_list(self, item_list):
        self.id_list = item_list

    def set_id(self, item_id):
        if not isinstance(item_id, int):
            return
        if self.id_list.get_item(item_id) == "null":
            return
        self.item_id = item_id

    def get_id(self):
        return self.item_id
    
    def get_value(self):
        return self.item_value

文件二:test.py

代码语言:python代码运行次数:0复制
from link_list import *
#item字典初始化
id_list = IdList()
#创建节点
nodes = LinkList()
nodes.set_value("1")
nodes.set_list(id_list)
#字典添加元素
id_list.add_item(nodes)

def add_node(node_value):
    node = LinkList()
    node.set_value(node_value)
    node.set_list(id_list)
    id_list.add_item(node)
    if nodes.get_id() == "null":
        nodes.set_id(id(node))
        return
    buf_node = nodes
    while buf_node.get_id() != "null":
        buf_node = id_list.get_item(buf_node.get_id())
        if buf_node.get_id() == "null":
            buf_node.set_id(id(node))
            break

def del_node(node_index):
    last_id = id(nodes)
    last_node = nodes
    buf_node = nodes
    
    if node_index == 0 and buf_node.get_id() != "null":
        buf_value = buf_node.get_value()
        buf_node = id_list.get_item(buf_node.get_id())
        nodes.set_value(buf_value)
        nodes.set_id(buf_node.get_id())
        id_list.del_item_id(last_id)
        return
    
    index = 0
    while buf_node.get_id() != "null":
        if index == node_index:
            if buf_node.get_id() != "null":
                last_node.set_id(buf_node.get_id())
            else:
                last_node.set_id("null")
            id_list.del_item_id(last_id)
            return
        last_id = buf_node.get_id()
        last_node = buf_node
        buf_node = id_list.get_item(buf_node.get_id())
        index  = 1

def insert_node(node_index, node_value):
    node = LinkList()
    node.set_value(node_value)
    node.set_list(id_list)
    id_list.add_item(node)

    last_id = id(nodes)
    last_node = nodes
    buf_node = nodes
    
    if node_index == 0:
        buf_value = nodes.get_value()
        buf_id = nodes.get_id()
        nodes.set_value(node.get_value())
        nodes.set_id(id(node))
        node.set_id(buf_id)
        node.set_value(buf_value)
        print("insert node sucess!")
        return
    
    index = 0
    while buf_node.get_id() != "null":
        if index == node_index:
            last_node.set_id(id(node))
            node.set_id(last_id)
            print("insert node sucess!")
            return
        last_id = buf_node.get_id()
        last_node = buf_node
        buf_node = id_list.get_item(buf_node.get_id())
        index  = 1

def modify_node(node_index, node_value):
    buf_node = nodes
    index = 0
    while buf_node.get_id() != "null":
        if index == node_index:
            buf_node.set_value(node_value)
            print("node_index value modify sucess!")
            return
        buf_node = id_list.get_item(buf_node.get_id())
        index  = 1
    print("node_index value is error!")

def print_nodes():
    buf_node = nodes
    index = 0
    print("-------------")
    print(index, buf_node.get_value())
    while buf_node.get_id() != "null":
        index  = 1
        buf_node = id_list.get_item(buf_node.get_id())
        print(index, buf_node.get_value())

#test -- add node
add_node("2")
add_node("3")
add_node("4")
print_nodes()
#test -- del node
del_node(0)
print_nodes()
#test -- add node
add_node("何其不顾四月天")
add_node("单链表")
print_nodes()
#test -- modify node value
modify_node(0, "云 社区")
modify_node(1, "互换选题活动")
modify_node(2, "测试演示")
print_nodes()
#test -- insert node
insert_node(0, "insert test")
print_nodes()
insert_node(2, "insert test 1")
print_nodes()

0 人点赞