一、前言
链式存储作为一种重要的数据存储方式有着极强的数据组织能力、灵活型和动态性,在众多数据结构中应用非常广泛。所谓链式存储结构,就是采用分散的存储空间分别存储每一组数据再通过地址链接的形式将全部数据组织到一起,这在C/C++语言中非常容易实现,因为他们有一个非常强大的工具——指针。指针虽然强大但也常常是劝退C语言入门者的一大杀器,作为最易入门的语言,python在程序员层面放弃了类似于指针的相关操作和地址的相关概念,没有了指针,我们该如何实现链式存储结构呢?
我个人认为,python作为一款不需要编程者显示地定义数据类型的编程语言,我们可以利用其面向对象的特性及其数据类型的灵活性和多样性,更加简单的实现链式存储结构。在这里,我以最基础的链式存储结构——单链表简单做一下介绍。
二、简单可行性分析
我们类比C语言中实现链式结构的方式来尝试在python中能否实现。
在C语言中,我们使用结构体来定义链表中的节点类型,每一个节点中包含一个数据域用来存储数据和一个地址域用来链接下一个节点。
typedef
而在python中,“类”可以实现类似于C语言结构体的功能,因此我们定义一个节点类。同样的,类中包含两个属性,一个是用来存储数据的数据域和一个用来存储下一个节点的节点域。
class
接下来我们手动链接几个节点来试一试这种类定义的可行性。
# 这里初始化三个LinkListNode类对象,其中head_node为头节点
head_node = LinkListNode()
node1 = LinkListNode()
node2 = LinkListNode()
# 这里我们依次将三个节点对象链接在一起
head_node.next = node1
node1.next = node2
# 为了验证链接是否成功,我们将node2的数据域改为10,并通过头节点来访问它
node2.data = 10
data = head_node.next.next.data
print(data)
可以看到,我们成功的通过头节点访问到了第三个节点并打印了其数据域的值。也就是说,我们通过上述定义类方式,实现了节点的链接,也就是在python中实现链式存储结构是完全可行的。
三、链表的几个常用操作的实现
因为没有单独定义头节点的类,所以头节点对象同样拥有数据域,我利用该数据域来存储链表的长度,并在某些功能里加以利用。
- 判断链表是否为空
def if_empty(head):
if head.next is None:
return True
else:
return False
由于头节点的数据域存储链表的长度,所以下面这种方法也是完全可行的
def if_empty(head):
if head.data == 0:
return True
else:
return False
2.遍历链表
def traversal(head):
if head.next is None:
print("Error! LinkList is empty!")
else:
node = head.next
while node is not None:
print(node.data, end=' ')
node = node.next
3.在任意位置添加一个数据域值为data的节点
def add_node(head, data, location=-1):
# 检查添加的位置是否合法,其中-1代表表尾
if location > head.data + 1 or (location <= 0 and location != -1):
print("Input position exception, add failed!")
else:
node = LinkListNode()
pre_node = head
node.data = data
order = 1
if 1 <= location <= head.data:
# 如果添加的节点位置不在表尾,需要改动两个节点的next值
while order != location:
pre_node = pre_node.next
order += 1
node.next = pre_node.next
pre_node.next = node
else:
# 如果添加的节点位于表尾,只需要改变尾节点的next值
pre_node = head
while pre_node.next is not None:
pre_node = pre_node.next
pre_node.next = node
head.data += 1
4.删除任意位置的节点
def pop_node(head, location=-1):
# 检删除的位置是否合法,-1代表表尾
if location > head.data or (location <= 0 and location != -1):
print("Input position exception, pop failed!")
else:
pre_node = head
order = 1
if 1 <= location < head.data:
# 如果删除的节点位置不在表尾,需要改动两个节点的next值
while order != location:
pre_node = pre_node.next
order += 1
data = pre_node.next.data
pre_node.next = pre_node.next.next
else:
# 如果删除的节点位于表尾,只需要改变尾节点的next值
# 这里要注意,如果直接将表尾节点置为None,python会理解为新建一个值为Node的变量
# 所以只能找到前驱节点,然后将前驱节点的next置为Node
pre_node = head
while pre_node.next.next is not None:
pre_node = pre_node.next
data = pre_node.next.data
pre_node.next = None
head.data -= 1
return data
其他的功能,例如访问某个节点的数据域,都可以用相关代码实现,这里就不在赘述。
四、总结
这里只展示了单链表的相关操作,但是如上文定义节点类时注释中所说,通过更改类中属性的定义,完全可以实现双链表、循环链表、二叉链表等所有常用的链式存储结构。另外也可以更改本文中展示的单链表中增加节点和删除节点等操作来实现栈和队列。
个人理解,如有错误,请及时指出!谢谢!