目录
链表
链表是由许多数据项按特定顺序排列而成的线性表。链表的特性是其各个数据项在计算机内存中的位置是不连续且随机存放的。其优点是数据的插入和删除都相当方便,有新数据加入就向系统申请一块内存空间,而数据被删除后,就可以把这块内存空间还给系统,加入和删除都不需要移动大量数据。其缺点是设计数据结构较为麻烦,另外在查找数据时,无法像列表、元组等静态数据结构那样可随机读取数据,必须按序查找到该数据为止。
单向链表
在动态分配内存空间时,最常使用的就是单向链表。一个单向链表节点由两部分组成,一部分是数据元素(数据元素可以是多个),另一部分是指针。数据元素保存业务数据,指针指向下一个元素在内存中的地址。在单向链表中,第一个节点表示头节点。头节点可以不用来保存业务数据,仅仅用来作为链表的表头,最后一个节点的指针为None。
由于单向链表中的所有节点都知道节点本身的下一个节点在哪里,但是对于前一个节点却没有办法知道,因此在单向链表的各种操作中,“链表表头”显得相当重要。只要存在链表头,就可以遍历、操作整个链表。除非必要,否则不可移动链表表头。
建立单向链表
创建单向链表节点
class Node(object):
def __init__(self, value):
self.value = value
self.next = None
每一个单向链表节点就是Node类的一个实例化对象。其中value表示节点的数据部分,根据实际业务数据部分可以是多个,数据类型也是根据实际业务来定。next表示节点的下一个指向节点,默认是空。
头节点
前面说过,单向链表的操作都依赖于头节点,因此找到了头节点就相当于找到了该单向链表。头节点本身的数据结构于其他节点并没有什么区别,它们都是Node类实例化出来的对象。在通常的使用中,为了操作方便和简化,可以将头节点视为单向链表的操作对象,而不是作为存储业务数据的一个节点,即头节点head的数据部分不存储任何值,仅仅指向下一个节点(可以理解为头节点就是火车的车头,车头不会搭载乘客,仅仅是为了控制火车)。
一个链表有且只有一个头节点和0个或多个数据节点,当链表只存在一个头节点而不存在任何数据节点时,该链表是一个空链表(即头节点的next值为None)。
创建单向链表
总结完上面的知识,我们可以创建一个单向链表了。创建一个单向链表本质上就是创建一个头节点。
class LinkedList(object):
def __init__(self):
self.head = Node("head")
通过对LinkedList类实例化得到一个空的单向链表:我们在向上封装一层函数,用来创建一个空的单向链表:
def create() -> LinkedList:
return LinkedList()
链表是否为空
如果一个链表只存在头节点,我们认为该链表是一个空链表。在LinkedList类中定义一个方法empty(),用来判断链表是否为空:
class LinkedList(object):
def __init__(self):
self.head = Node("head")
def empty(self) -> bool:
return self.head.next is None
添加元素
连接两个节点
链表是由若干个节点连接而成的。给列表中添加元素最基本的功能就是连接两个节点。对于两个节点A,B,我们将A.next = B即将A的下一个节点指向了B,也就是说B节点成为了A的下一个节点。
A.next = B
我们在节点Node类里重写__add__方法来连接两个链表,简化代码:
class Node(object):
def __init__(self, value):
self.value = value
self.next = None
def __add__(self, other_node):
self.next = other_node
重写__add__方法后两个节点的连接语法被我们简化了:
a = Node("A")
b = Node("B")
a + b
即直接使用 “+”运算符即可连接两个节点。a + b表示将b节点作为a节点的下一个节点。
插入单个节点
通常便捷的插入方式是将新的节点插入到头节点的下一个位置。如果链表只有头节点,那么将新插入的节点作为头节点的下一个节点即可。如果链表有多个节点,那么需要将头节点的下一个节点指向新节点,同时新节点的下一个节点指向插入前头节点的下一个节点。即:
链表只存在头节点:
插入前,头指针指向None
插入后,头指针指向新节点,新节点作为链表尾部指向None:
链表存在多个节点:
插入前,链表头指针指向着其他节点:
插入后,头指针指向新节点,新节点指向Node1:
下面我们使用代码来实现上面的逻辑图:
linked = create()
# linked list only has head node
newNode = Node("Python")
linked.head.next = newNode
# head -> Python -> [None]
newNode = Node("C")
ptr = linked.head.next
linked.head.next = newNode
newNode.next = ptr
根据上面的逻辑,我们在LinkedList类中封装一个add方法用来表示添加新的节点:
class LinkedList(object):
def __init__(self):
self.head = Node("head")
def empty(self) -> bool:
return self.head.next is None
def add(self, node):
if self.empty():
self.head + node
else:
ptr = self.head.next
self.he