概念
单向链表也称单链表,是链表中最简单的形式,每个节点包含两个域(两个属性),一个元素域和一个链接域,其中,链接域指向下一个节点的地址,而最后一个节点的链接域指向的是一个空值。
节点的实现
以Python代码实现,
class SingleNode:
"""单链表节点"""
def __init__(self, item):
self.item = item
self.next = None
item和next分别表示节点的元素域和链接域。
单链表的操作
实现单链表需要对如下操作进行实现,
方法 | 作用 |
---|---|
is_empty() | 判断链表是否为空 |
length() | 链表长度 |
travel() | 遍历链表 |
add(item) | 链表头部添加元素 |
append(item) | 链表尾部添加元素 |
insert(pos, item) | 指定位置插入元素 |
remove(item) | 删除节点 |
search(item) | 查找节点是否存在 |
单链表实现
使用Python实现单链表,
class SingleLinkList:
def __init__(self, node=None):
"""
param node: SingleNode类对象,默认为None
"""
self.__head = node
if node is None:
self.__count = 0
else:
self.__count = 1
def is_empty(self):
"""判断链表是否为空"""
return self.__head is None
def length(self):
"""获取链表长度(元素个数)"""
return self.__count
def travel(self):
"""遍历链表"""
cur = self.__head
while cur is not None:
yield cur.item
cur = cur.next
def add(self, item):
"""在链表的头部添加元素"""
n = SingleNode(item)
n.next = self.__head
self.__head = n
self.__count += 1
def append(self, item):
"""链表末尾添加元素"""
n = SingleNode(item)
# 注意此处需要判断
if is_empty():
self.__head = n
else:
cur = self.__head
while cur.next is not None:
cur = cur.next
cur.next = n
self.__count += 1
def insert(self, item, pos):
"""在指定位置添加元素"""
# 如果位置小于0,默认在头部添加元素
if pos <= 0:
self.add(item)
# 如果位置大于当前链表长度,则在尾部添加
elif pos > self.__count:
self.append(item)
else:
cur = self.__head
count = 0
while count < (pos - 1):
count += 1
cur = cur.next
n = SingleNode(item)
n.next = cur.next
cur.next = n
def remove(self, item):
"""删除节点"""
cur = self.__head
pre = None
while cur != None:
if cur.item == item:
# 判断是否为头结点
if cur == self.__head:
self.__head = cur.next
else:
pre.next = cur.next
break
else:
pre = cur
cur = cur.next
def search(item):
"""查找节点是否存在"""
cur = self.__head
while cur is not None:
if cur.item = item
return True
else:
cur = cur.next
return False
在对链表功能实现的时候,一定要注意几个特殊情况,
- 链表是否为空链表
- 操作元素时链表头部元素
- 链表的头部元素是否为空
单向链表与顺序表对比
空间对比
链表由于增加了节点的指针域,所以空间开销较大,但是对存储空间使用要比顺序表灵活。
时间对比
链表相较于顺序表最大的不同是失去了顺序表随机读取的优点。
各种元素操作时间复杂度对比,
操作 | 链表 | 顺序表 |
---|---|---|
访问元素 | O(n) | O(1) |
在头部插入/删除元素 | O(1) | O(n) |
在尾部插入/删除元素 | O(n) | O(1) |
在中间插入/删除元素 | O(n) | O(n) |
虽然插入元素的过程时间复杂度都是O(n),但是链表和顺序表进行的操作是完全不同的。
链表主要耗时的操作室遍历查找。而删除和插入本身的复杂度是O(1)。
顺序表查找很快,注意好事的操作是拷贝覆盖。除了元素在尾部的特殊情况外,顺序表进行插入和删除操作是需要对操作点之后的所有元素进行前后位移操作,只能通过拷贝和覆盖的方法进行。