用 class 来模拟 node 和 LinkList
白露不漏身,寒露不漏脚。仲秋时节来到,注意保暖呀!
今天翻到以前学习python时留下的笔记,是在学完类之后,用类来模拟链表时的代码。为了重温知识,也是防止忘记链式结构。因此将其记录下来。
时间真快啊,转眼就毕业一年了,可我依旧在飘零,不知何处是归途,梦中的归宿是否太遥远。
1. LinkList
在计算机领域:
FIFO:全称First in, First out,先进先出。LIFO:全称Last in, First out,后进先出。
FIFO:先入先出队列,这是一种传统的按序执行方法,先进入的指令先完成并引退,之后才执行后面进入的指令。
LIFO:后进先出法是指假定后入库的存货先发出,据此计算发出存货成本的方法。
一个单向链表包含两个值: 当前节点的值和一个指向下一个节点的链接。
一个双向链表有三个整数值: 数值、向后的节点链接、向前的节点链接。
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有多个值,那么应该是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)
以上便是本期所有的内容。