单向链表简称单链表,是链表中最简单的一种形式,单链表的每个节点包含两个域(首位相连的两部分内容),一个信息域(或叫元素域,用来存放具体数据)和一个链接域。这个链接域中存放的链接指向链表中的下一个节点,而最后一个节点的链接域则指向一个空值(None)。而每个单链表都有一个隐式的head节点(self.__head),这个head节点不存放具体数据因而没有信息域,也无法从外部访问,只有一个链接域用来指向第一个存放数据的链表节点(也就是平常所说的显式的头节点)。
单链表类主要包含以下基本操作:
- is_empty() 链表是否为空
- length() 链表长度
- travel() 遍历整个链表
- add(item) 链表头部添加元素
- append(item) 链表尾部添加元素
- insert(pos, item) 指定位置添加元素
- remove(item) 删除单链表中与item相等的第一个节点(和列表中的remove操作相似)
- search(item) 查找节点是否存在
先定义一个节点的类对象:
class Node():
def __init__(self, item):
self.item = item
self.next = None
现在可以开始写单链表类了:
class SingleLinkedList():
#定义一个单向链表的类对象
#先定义一个head!!!
def __init__(self, node = None):
self.__head = node
def is_empty(self):
#链表是否为空
return self.__head == None
def length(self):
#链表长度
cur = self.__head
count = 0
while cur != None:
cur = cur.next
count += 1
return count
def travel(self):
#遍历整个链表
cur = self.__head
if cur == None:
print("None")
else:
while cur != None:
print(str(cur.item), end = " ")
cur = cur.next
def add(self, item):
#头插法:在链表头部添加元素
node = Node(item) #引入要插入的新节点
node.next = self.__head #先把新节点的next指向原来的头节点(必须)
self.__head = node #再使self.__head指向新插入的节点(注意和上一步的顺序)
def append(self, item):
#尾插法:在链表尾部添加元素
node = Node(item)
if self.is_empty():
self.__head = node
else:
cur = self.__head
# while cur != None:
# cur = cur.next
# cur = node
while cur.next != None:
cur = cur.next
cur.next = node
def insert(self, pos, item):
node = Node(item) #先引入要添加的外部定义好的节点
if pos <= 0: #考虑特殊情况
self.add(item)
elif pos >= self.length():
self.append(item)
else:
pre_cur = self.__head #定义一个游标,先停留在头节点位置
count = 0 #定义计数器
while count < (pos - 1): #确定循环条件,因为要插入值是在定义的位置前面,所以要-1且不能有等号
count += 1
pre_cur = pre_cur.next #移动游标到要插入的位置
node.next = pre_cur.next #跟头插法一样先操作新插节点的next,使其指向下一个节点
pre_cur.next = node #再把插入位置的上一个节点的next指到新插节点头部
def remove(self, item):
#删除从头节点开始的第一个相同的节点
cur = self.__head #首先定义一个游标指向头节点
pre_cur = None #再定义一个位于cur前一位的pre_cur游标,此时cur指向头节点因此pre_cur是None
while cur != None: #当cur为None时说明要么这是空链表要么循环已经到链表末端了
if cur.item == item: #判断cur当前所指的item是否和要删除的item相同
if pre_cur == None: #考虑特殊情况,如果pre游标为None说明cur指向的是第一个节点
self.__head = cur.next #那就另self.__head直接指向cur.next
else:
pre_cur.next = cur.next #否则另此时非空的pre_cur.next指向cur.next
break
else:
pre_cur = cur #游标逐个后移,注意顺序
cur = cur.next
def search(self, item): #这是一个可以优化的search方法
#查找节点是否存在
node = Node(item)
cur = self.__head
if cur == None:
return False
else:
while cur.item != node.item:
cur = cur.next
if cur == None:
return False
return True
开始测试:
if __name__ == "__main__":
#定义单链表sll
sll = SingleLinkedList()
#测试尾插法
sll.append(0)
sll.append(1)
sll.append(2)
sll.append(3)
#测试insert,注意每插入一个新的元素,后面的元素下标都变了
sll.insert(0, -0.5)
sll.insert(1, 555)
sll.insert(3, 555)
sll.insert(6, 2.5)
#测试头插法
sll.add(-1)
sll.add(-2)
#测空
print("链表sll是否为空?\n" + str(sll.is_empty()) + "\n")
#测长
print("链表sll长度?\n" + str(sll.length()) + "\n")
#遍历打印
print("遍历链表sll:")
sll.travel()
print("\n")
#测试remove中间节点,结束后打印
sll.remove(555)
print("遍历链表sll:")
sll.travel()
print("\n")
#测试remove头节点,并打印
sll.remove(-2)
print("遍历链表sll:")
sll.travel()
print("\n")
#测试remove尾节点并打印
sll.remove(3)
print("遍历链表sll:")
sll.travel()
print("\n")
#测试remove一个不存在的节点
sll.remove(123456)
print("遍历链表sll:")
sll.travel()
print("\n")
#测试search,返回True或False
print(str(sll.search(555)) + "\n")
print(str(sll.search(-1)) + "\n")
print(str(sll.search(123456)) + "\n")
运行一下看看结果是否如期?
链表sll是否为空?
False
链表sll长度?
10
遍历链表sll:
-2 -1 -0.5 555 0 555 1 2 2.5 3
遍历链表sll:
-2 -1 -0.5 0 555 1 2 2.5 3
遍历链表sll:
-1 -0.5 0 555 1 2 2.5 3
遍历链表sll:
-1 -0.5 0 555 1 2 2.5
遍历链表sll:
-1 -0.5 0 555 1 2 2.5
True
True
False
经测试未发现问题,至此单向链表的类对象就初步完成啦。