python中linklist理解

用 class 来模拟 node LinkList

白露不漏身,寒露不漏脚。仲秋时节来到,注意保暖呀!

今天翻到以前学习python时留下的笔记,是在学完类之后,用类来模拟链表时的代码。为了重温知识,也是防止忘记链式结构。因此将其记录下来。


时间真快啊,转眼就毕业一年了,可我依旧在飘零,不知何处是归途,梦中的归宿是否太遥远。



1. LinkList


在计算机领域:

FIFO:全称First in, First out,先进先出。LIFO:全称Last in, First out,后进先出。
FIFO:先入先出队列,这是一种传统的按序执行方法,先进入的指令先完成并引退,之后才执行后面进入的指令。
LIFO:后进先出法是指假定后入库的存货先发出,据此计算发出存货成本的方法。

概念详见: Linkedlist

一个单向链表包含两个值: 当前节点的值和一个指向下一个节点的链接。


一个双向链表有三个整数值: 数值、向后的节点链接、向前的节点链接。

Java LinkedList(链表) 类似于 ArrayList,是一种常用的数据容器。 与 ArrayList 相比,LinkedList 的增加和删除的操作效率更高,而查找和修改的操作效率较低。

我们先来操作单向列表

2. node

#先建立节点,从上面知道,节点应该有当前节点的值与下一个节点的链接
class node():
    #这里可以完善一下,对于只有一个数据的情况,给它一个初始值None
    def __init__(self,now_value,next_node_link=None):
        self.value=now_value
        #为了方便与便于理解,我们的下一个node的link,也就是地址,直接用下一个node的value来表示
        self.link=next_node_link 
    #这个控制print
    def __str__(self):
        return str(self.value)
    #这个控制node直接查看
    def __repr__(self):
        return 'node('+str(self.value)+','+str(self. Link)+')'

链表

#试试建立的节点
exam_node=node(18,None)
print(exam_node.value,exam_node.link)
exam_node2=node(18,node(34))
print(exam_node2.value,exam_node2.link)
#print(node(12))
print(node(12).link)
#假如我只有一个数据,我不想输入None,这样太麻烦,我们发现有问题,继续改进
exam_node2=node(18)
print(exam_node2.value,exam_node2.link)
exam_node2=node(18,346)
print(exam_node2.value,exam_node2.link)
print(exam_node2)
#我有多个数据
exam_node3=node(12,node(23,node(23,45)))
#这样不好查看,我们重置__str__与__repr__
print(exam_node3.value,exam_node3.link)
exam_node3
print(exam_node3)

上面便是LinkList中的基本元素node的class模拟,下面我们用node来生成LinkList

3. LinkList

#节点建立好了,就开始linklist吧,注意:linklist有头有尾,后进入的是头;
                                    #LinkList储存是乱序的
class d_l():
    
    '''为什么我们定义的是数组,因为如果整数或其他一个元素的话,
           那么就是节点node,而不需要LinkList来储存了
    '''
    def __init__(self,list_value=None):
         
        #没有元素传入,那么第一个元素也就是头是空的,这个头就是一个node
        #也就是初始化
        self.head=None
        
        '''self.head=node(None,null),但我们用值来代替地址,所以null应该是None,那么:
                    self.head=node(None,None),由我们建立的node特性可知:
                             self.head=node(None)=None
        '''
        if list_value != None:
            for value in list_value:
                
                 ##初始化里面是没有add方法的,需要我们自己建立
                 self.add(value)               
                 #print(self.head)
            #通过这个(输入只有一个元素的list:exam_list=[99])输出可以看到,
                #self.head其实就是我们输入的值
                     #即self.head=node.value 
            #这也是我们在node里面定义的print(node)-->return str(node.value).
    
    #建立添加
    def add(self,value):
        #把新加入的元素作为头文件
        self.head=node(value,self.head)
        #通过这个print,我们可以知道self.head本质上就是一个node
        #print(self.head.value,self.head.link)
        
        
    #想看内部结构,打印一下
    def __str__(self):
        if self.head==None:
            return "d_l is Empty!"
        
        '''从头开始打印,数学上有种解法叫定一移一,在这里也适用,
               通过移动头文件来确定其余元素位置
        '''
        print_text=self.head
        #定义空字符串
        print_str=""
        
        '''当node的指向不为空时,说明后面还有元素,当为空时,
               说明已经到最后了,但不包括最后的元素
        '''
        while print_text.link !=None:
            print_str+=str(print_text.value)+"-=>"
            #移动头node
            print_text=print_text.link
        #返回要打印的字符串,并且加上最后一个node的value
        return print_str+str(print_text.value)
    
    #定义清空函数
    def clear(self):
        self.head=None 
        
    #定义删除函数
    def remove(self,remove_value):
        #这个其实不好写,list里面重复的元素应该怎么删除?
        #先假定list里面的元素互不重复,那么:
        
           #如果是空,显示为空
        if self.head==None:
            return "This is a EMPTY LinkList!"
        
        #要删除的元素在头,或者linklist只有一个node的情况
        elif self.head.value==remove_value:
            #只有一个元素
            if self.head.link==None:
                self.head=None
                
            #要删除的元素是头node的值
            else:
                self.head=self.head.link
            return "已删除-=<{}>=-".format(remove_value)
        #要删除的node既不在头,元素也不止一个的情况
        else:
            
            #把头文件的值复制下来,头文件不能随便乱移动
            map_node=self.head
            
            #如果要删除的元素在linklist的尾,遍历不到,提前确认
            if map_node.link==None and map_node.link.value==remove_value:
                map_node.link=None
                return "已删除-=<{}>=-".format(remove_value)
            
            #要删除的node在中间,我们用 X->X+1->X+2 的这种数学方法来找
            while map_node.link !=None:
                #测试是否为下一个node
                #return map_node.link
                
                #确认输入的与要linklist中的值是否一致
                if map_node.link.value==remove_value:
                    map_node.link=map_node.link.link
                    return "已删除-=<{}>=-".format(remove_value)
                
                #不一致,则移动到下一个节点
                map_node=map_node.link
                
    #定义本身查看规则
    def __repr__(self):
        return "d_l("+str(self)+")"

链表

add方法构建,即d_l(list)=node(value_n,node(value_n-1,node(value_n-3,...,node(value_0,null))))。

node(value_n,value_n-1)-->node(value_n-1,value_n-2)-->node(value_n-2,value_n-3)-->...-->node(value_0,null)。用下一个的值来代替其地址。

linklist_shenshang

linklist有多个值,那么应该是head->node(value_1,address_2)->node(value_2,address_3)->...->node(value_n,[None])

可以看到头node一直变化,如果头文件不动,只添加,像这样:head->node(value_1,address_2?),每次还得判断下一个值在不在,在的话才能指向,这样很浪费时间与空间。

综上所述,把新加入的元素作为头文件,或者说移动头文件是最高效的。


下面来测试一下上面定义的类。

#1.生成一个链表实例
d_ll=d_l([1,2,3,4,5,0,99,78,45]) 
print(d_ll)
#output:45-=>78-=>99-=>0-=>5-=>4-=>3-=>2-=>1

#2.给列表输入一个元素,看看什么情况。
d_ll2=d_l([90])
print(d_ll2)
#output:90

#3.生成第三个链表为空,试试。
d_ll3=d_l()
print(d_ll3)
#output:d_l is Empty!

#4.试试定义的清空函数,用前面生成的d_l1来试试
d_ll.clear()
print(d_ll)
#output:d_l is Empty!

#5.重新生成一个新链表,
d_l2=d_l([1,2,3,4,5,0,99,78,45])
print(d_l2)
#output:45-=>78-=>99-=>0-=>5-=>4-=>3-=>2-=>1
#6.测试删除元素的函数,
d_l2.remove(99)#output:'已删除-=<99>=-'
print(d_l2)
#output:45-=>78-=>0-=>5-=>4-=>3-=>2-=>1
d_l2
#output:d_l(45-=>78-=>0-=>5-=>4-=>3-=>2-=>1)

以上便是本期所有的内容。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
在单链表的实现,`PNode`和`Linklist`是两个不同的概念。 `PNode`通常是用来表示链表的节点(Node)的指针类型,也可以称为链表节点指针。每个节点包含数据域和指针域,`PNode`指向一个具体的节点。 `Linklist`是链表List)的类型,通常是一个结构体或者一个指针类型。它包含一个指向链表首节点的指针(通常称为头指针或者头节点),作为整个链表的入口。 下面是一个示例代码,演示了`PNode`和`Linklist`的使用: ```c #include <stdio.h> #include <stdlib.h> // 定义单链表的节点结构体 struct Node { int data; struct Node* next; }; // 定义链表的类型 typedef struct Node* Linklist; // 初始化链表 void initialize(Linklist* llist) { *llist = NULL; } // 在链表末尾插入节点 void insertAtEnd(Linklist* llist, int data) { struct Node* newNode = (struct Node*)malloc(sizeof(struct Node)); newNode->data = data; newNode->next = NULL; if (*llist == NULL) { *llist = newNode; } else { struct Node* current = *llist; while (current->next != NULL) { current = current->next; } current->next = newNode; } } // 打印链表 void printList(Linklist llist) { struct Node* current = llist; while (current != NULL) { printf("%d ", current->data); current = current->next; } printf("\n"); } int main() { Linklist llist; initialize(&llist); insertAtEnd(&llist, 1); insertAtEnd(&llist, 2); insertAtEnd(&llist, 3); printf("Linked List: "); printList(llist); return 0; } ``` 在上述示例,`struct Node*`被定义为`PNode`,它是指向链表节点的指针类型。而`typedef struct Node* Linklist`将`struct Node*`定义为`Linklist`,它是链表的类型。 这样,我们可以使用`PNode`来表示链表节点的指针,使用`Linklist`来表示整个链表的类型。在函数,我们可以通过传递`Linklist*`类型的参数来修改链表的头指针,实现对链表的操作。 需要注意的是,这里的命名约定可能会有所不同,不同的开发者可能会使用不同的名称来表示链表节点指针和链表类型。重要的是理解它们之间的关系和用法。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落寞红颜玉玫瑰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值