python数据结构 —— 链表(上)
1.初识链表
(1)链表有什么用呢?
当在一个复杂的系统运行的情况下,空闲的内存空间可能散落在内存各处,而存储数组的内存空间必须是连续的。当内存无法提供如此大的连续空间时候,此时链表的优势就体现出来—>链表的各个节点可以分散存储在内存各处,它们的内存地址无须连续
(2)链表是什么?
a.一种线性数据结构
b.每个元素是一个节点对象
c.各个节点通过“引用”相连接
【引用:记录下一个节点的内存地址,通过它可以从当前节点访问到下一个节点】
(3)一些基础概念
a.头结点:链表的首个节点;尾结点:最后一个节点,尾结点指向的是None为空
b.初见代码:
head = {
"value":11,
"next":{
"value":3,
"next":{
"value":23,
"next":{
"value":7,
"next":None
}
}
}
}
print(head['next']['next']['value'])
上图的链表相当于
运行上面的代码,执行print语句相当于找head的next的next的value,最终打印输出23
2.创建链表的构造函数
- 首先定义Node类,初始化各个节点对象
class Node:
def __init__(self,value):
self.value = value
self.next = None
这里涉及了一个关于“类”的定义,关于这个定义我是在"python面向对象"这个板块的的学习中接触到,这里只做简单理解不进行详细展开。
类是用来描述相同的属性和方法的对象的集合,定义了集合中每个对象所共有的属性和方法。在上面中看到的self
是类的实例。在我理解看来实例可以是一个小人,比如说你想要它的身高为172,那你传入的外界参数172要赋给这个小人就需要self.height = height
的语句将外界的参数实例化。
- 接着,进行链表的初始化
class LinkedList:
def __init__(self,value):
new_node = Node(value)
self.head = new_node
self.tail = new_node
self.length = 1
创建一个新节点(通过Node类进行创建),让头节点和尾结点都是这个新创建的结点,链表长度为1
- 例子
my_linked_list = LinkedList(4)
print(my_linked_list.head.value)
创建长度为1,只有一个节点值为4的链表
3.打印链表
def print_list(self):
temp = self.head
while temp is not None:
print(temp.value)
temp = temp.next
相当于是有一个名为temp
名字的节点一个一个往后读取节点中的数
- 调用
my_linked_list.print_list()
4.append —— 将一个节点附加到链表末尾
def append(self,value):
new_node = Node(value)
if self.head is None:
self.head = new_node
self.tail = new_node
else:
self.tail.next = new_node
self.tail = new_node
self.length += 1
return True
所有新节点的创建都调用Node这个类进行调用
先看这个链表是不是空的,如果是空的,则我创建的这个新节点是这个链表中的唯一节点,直接让首节点和尾节点是这个节点即可。如果这个链表不是空的,让新节点是尾结点的下一个节点,然后这个新的节点成为尾节点,这样就完成链表的append。
my_linked_list.append(2)
上面代码将一个值为2的节点添加到链表后面
5.pop —— 删除最后一个元素,并将tail退回指向当前的第一个元素
def pop(self):
if self.length == 0:
return None
temp = self.head
pre = self.head
while(temp.next):
pre = temp
temp = temp.next
self.tail = pre
self.tail.next = None
self.length -= 1
if self.length == 0:
self.head = None
self.tail = None
return temp
首先是判断链表长度是否为0,如果不为0,则让temp
和pre
都是头节点
当temp.next
是有值的时候,执行while语句
一直到temp.next
是空时候
用self.tail.next = None
直接让后面的结点删去,最后记得self.length-=1
看到整个代码可能会疑惑为什么有两句if self.length == 0
?第一句是删除前判断链表是否长度为零,如果长度不为零可以执行后面的一系列操作。第二句是执行完一系列操作之后判断链表长度是否为零,之所以需要判断是因为需要返回删除的值(也就是temp
节点的值)。
- 完整代码示例
class Node:
def __init__(self,value):
self.value = value
self.next = None
class LinkedList:
def __init__(self,value):
new_node = Node(value)
self.head = new_node
self.tail = new_node
self.length = 1
def print_list(self):
temp = self.head
while temp is not None:
print(temp.value)
temp = temp.next
def append(self,value):
new_node = Node(value)
if self.length == 0:
self.head = new_node
self.tail = new_node
else:
self.tail.next = new_node
self.tail = new_node
self.length += 1
def pop(self):
if self.length == 0:
return None
temp = self.head
pre = self.head
while(temp.next):
pre = temp
temp = temp.next
self.tail = pre
self.tail.next = None
self.length -= 1
if self.length == 0:
self.head = None
self.tail = None
return temp.value
my_linked_list = LinkedList(1)
my_linked_list.append(2)
my_linked_list.print_list()
#执行pop
# 2 items -- Return 2 Node
print(my_linked_list.pop())
# 1 items -- Return 1 Node
print(my_linked_list.pop())
# 0 items -- Return None
print(my_linked_list.pop())
下面是代码运行的结果
1
2
2
1
None