文章目录
一、链表介绍
1.为什么需要链表?
动态数组(顺序表)的构建底层依托静态数组,需要预先知道数据大小来申请连续的存储空间,而在进行扩容resize
时又需要进行数据的搬迁,可能会造成内存空间的大量浪费;并且在插入与删除时需要移动大量的元素,所以使用起来并不是很灵活。
链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。链表是真正的动态数据结构。
2.什么是链表?
链表(Linked list)是一种常见的基础数据结构,它不像数组一样连续存储数据,而是在每一个节点(数据存储单元)里存放下一个节点的位置信息(即地址)。
优点:真正的动态,不需要处理固定容量的问题
缺点:丧失了随机访问的能力
3.数组与链表对比
数组连续存储数据,数组最好索引有语义的情况,最大的优点是支持快速查询。
链表通过在每一个节点(数据存储单元)里存放下一个节点的位置信息(即地址)来充分利用计算机内存空间。链表不适合用于索引有语义的情况,最大的优点是动态。
二、单链表
1.什么是单链表?
单向链表也叫单链表,是链表中最简单的一种形式,它的每个节点包含两个域,一个信息域(元素域)和一个链接域。这个链接指向链表中的下一个节点,而最后一个节点的链接域则指向一个空值。
表元素域elem用来存放具体的数据。
链接域next用来存放下一个节点的位置(python中的标识)
变量p指向链表的头节点(首节点)的位置,从p出发能找到表中的任意节点。
2.单链表python实现
下面单链表要实现如下功能:添加、删除、查询、更新、包含
- is_empty() 链表是否为空
- length() 链表长度
- add(item) 链表头部添加元素
- append(item) 链表尾部添加元素
- insert(pos, item) 指定位置添加元素
- remove(item) 删除节点
- removeIndex(index)删除某一索引的元素
- search(item) 查找节点是否存在(包含)
- get(index)查询某一索引的元素(查询)
- setter(elem)更新某一索引的元素为elem(更新)
2.1 节点的实现
class _Node:
def __init__(self, e=None):
self.e = e
self.next = None
def __str__(self):
return str(self.e)
def __repr__(self):
return self.__str__()
class SingleLinkList(object):
'''单链表'''
def __init__(self, node=None): # 默认参数为None
self.__head = node
2.2 is_empty() 链表是否为空
def is_empty(self):
'''is_empty() 链表是否为空'''
return self.__head is None
2.3 length() 链表长度
def length(self):
'''链表长度'''
# cur游标 用来遍历节点
# count 记录数量
cur = self.__head
count = 0
while cur != None:
count += 1
cur = cur.next
return count
2.4 add(item) 链表头部添加元素
def add(self,item):
'''链表头部添加元素,"头插法"'''
node = Node(item)
node.next = self.__head
self.__head = node
2.5 append(item) 链表尾部添加元素
def append(self,item):
#创建节点
node = Node(item)
#判断链表是否为空
if self.is_empty():
self.__head = node
else:
cur = self.__head
while cur.next != None:
cur = cur.next
#循环退出时,cur指向最后一个节点
cur.next = node
2.6 insert(pos, item) 指定位置添加元素
def insert(self,pos,item):
'''指定位置添加元素
:param pos 从0开始
'''
if pos <= 0:
self.add(item)
elif pos >(self.length()-1): #没有等号
self.append(item)
else:
node = Node(item)
cur = self.__head
count = 0 #记录移动到哪个位置
while count < (pos-1): #当循环退出后,cur指向pos-1位置
count += 1
cur = cur.next
node.next = cur.next
cur.next = node
2.7 remove(item) 删除节点
def remove(self,item):
'''删除节点'''
cur = self.__head
pre = None
count =0 #用来返回删除的值的下标
while cur != None: #循环内所有点都照顾到
count += 1
if cur.elem == item:
#判断此节点是否是头节点
if cur == self.__head:
self.__head = cur.next
else:
pre.next = cur.next #删除的是最后一个节点,此时pre.next = None,满足
return count
else:
pre = cur
cur = cur.next
2.8 removeIndex(index)删除某一索引的元素
def removeIndex(self,index):
if index < 0 and index >= self.length():
raise Exception('removeindex failed. illegal index')
curr = self.__head
per = None
for i in range(index):
per = curr
curr = curr.next
e = curr.elem
per.next = curr.next
return e
2.9 search(item) 查找节点是否存在
def search(self,item):
'''查找节点是否存在'''
cur = self.__head
while cur != None: #若为while cur.next != None:则最后一个节点比较不了
if cur.elem == item:
return True
#return是结束函数执行并返回值
else:
cur = cur.next
return False
2.10 get(index)查询某一节点的元素
def get(self, index):
if index < 0 and index >= self.length():
raise Exception('get filled. Illegal index!')
cur = self.__head
for i in range(index):
cur = cur.next
return cur.elem
2.11 setter(elem)更新某一索引的元素为elem
def setter(self, index, elem):
"""
更新某一索引的元素为elem
"""
if index < 0 and index >= self.length():
raise Exception('get filled. Illegal index!')
cur = self.__head
for i in range(index):
cur = cur.next
cur.elem = elem
2.12 全部代码
这里的全部代码与上面的代码有些许不同,上面是self._head = 头节点
,下面是self._head.next = 下一节点
,下面更通用一点!
# 定义节点
class Node:
def __init__(self, e=None):
self.e = e
self.next = None
def __str__(self):
return str(self.e)
def __repr__(self):
return self.__str__()
# 定义单链表
class LinkList:
def __init__(self):
# 初始化虚拟头结点
self._head = Node()
self.size = 0
# 判断链表是否为空
def is_empty(self):
return self.size == 0
# 判断链表的长度
def get_size(self):
return self.size
# 链表头部添加元素
def add_first(self, elem):
# 初始化节点
node = Node(elem)
node.next = self._head.next
self._head.next = node
self.size += 1
# 往链表尾部添加元素
def add_last(self, elem):
# 初始化节点
node = Node(elem)
# 判断链表是否为空
if self._head.next is None:
self._head.next = node
self.size += 1
# 如果链表非空,则进行遍历,直到找到链表尾部
cur = self._head.next
pre = self._head
while cur:
pre = cur
cur = cur.next
# 当循环结束时,pre指向链表末尾,cur指向None
pre.next = node
node.next = None
self.size += 1
# 往链表指定位置添加元素
def add(self, index, elem):
# 往头部添加
if index <= 0:
self.add_first(elem)
# 往尾部添加
elif index >= self.size:
self.add_last(elem)
# 往中间添加,基本思路是先找到插入位置的前一个元素,就可以解决这个问题
else:
node = Node(elem)
cur = self._head.next
for _ in range(index):
cur = cur.next
# 当循环结束时,cur指针指向的是要插入位置的前一个位置
node.next = cur.next
cur.next = node
self.size += 1
# 从链表指定位置删除元素
def remove(self, index):
if index < 0 or index >= self.size:
raise Exception('Remove failed! illegal index')
pre = self._head
cur = self._head.next
for _ in range(index):
pre = cur
cur = cur.next
# 循环结束时,cur指针指向指定位置,pre指针指向前面一个位置
tmp = cur
pre.next = cur.next
self.size -= 1
return tmp.e
# 从链表头部位置删除元素
def remove_first(self):
return self.remove(0)
# 从链表尾部删除元素
def remove_last(self):
return self.remove(self.size - 1)
# 对链表某一位置的元素重新赋值
def setter(self