前言
链表:一组数据项的集合,其中每个数据项都是一个节点的一部分,每个节点还包含指向下一个节点的链接
链表的数据结构:
而对于其中每一个节点:
每一个节点有两个域,左边叫值域,用于存放用户数据,右边叫指针域,一般是存储着到下一个节点的指针
head节点:
头节点,特殊的一个节点,永远指向第一个节点
tail节点:
尾节点,也是特殊的一个节点,永远指向最后一个节点。tail.next = None
而由abcd四个节点组成了一个链表,每一个节点都有data和next,尾节点的next指向None
链表中的元素都会有两个属性,一个是元素的值,另一个是指针,指针标记了下一个元素的地址,每一个数据都会保存下一个数据的内存的地址,通过此地址可以找到下一个数据,任意位置插入和删除元素效率较高,时间复杂度为O(1)
需要访问某个位置的数据,需要从第一个数据开始找起,依次往后遍历,直到找到待查询的位置,故可能在查找某个元素时,时间复杂度为O(N)
优点:
- 任意位置插入和删除元素速度快,时间复杂度为O(1)
- 内存利用率高,不会浪费内存
缺点:
随机访问效率低 时间复杂度为O(N)
python的单链表实现
单链表也就是刚才所讲的链表结构,也是最基础的链表
class Node():
def __init__(self, value):
# 该节点的值
self._value = value
# 指向下一个节点
self._next = None
class LinkedList():
def __init__(self, head=None):
# 头节点
self._head = head
# 检查该链表是否为空,为空则返回 True,否则返回 False
def isEmpty(self):
return self._head == None
# 返回链表节点的数量
def length(self):
if self.isEmpty():
return 0
else:
cur = self._head
count = 1
while cur._next != None:
count += 1
cur = cur._next
return count
# 遍历所有节点
def travel(self):
if self.isEmpty():
print("The linkedlist is empty!")
else:
cur = self._head
values = []
while cur != None:
values.append(cur._value)
cur = cur._next
print(values)
# 头部添加节点
def add(self, value):
node = Node(value)
node._next = self._head
self._head = node
# 尾部添加节点
def append(self, value):
node = Node(value)
if self.isEmpty():
self._head = node
else:
cur = self._head
while cur._next != None:
cur = cur._next
cur._next = node
# 插入节点
def insert(self, pos, value):
if pos <= 0:
self.add(value)
elif pos > (self.length()-1):
self.append(value)
else:
node = Node(value)
cur = self._head
index = 0
while index < (pos-1):
index += 1
cur = cur._next
node._next = cur._next
cur._next = node
# 删除等于某个值的全部节点
def remove(self, value):
pre = None
cur = self._head
while cur != None:
if cur._value == value:
if pre == None:
self._head = self._head._next
cur = self._head
continue
else:
pre._next = cur._next
cur = cur._next
continue
pre, cur = cur, cur._next
# 删除某个索引对应的节点
def delete(self, index):
if index < 0 or index > (self.length()-1):
print("The input index is out of range!")
elif index == 0:
self._head = self._head._next
else:
count = 1
pre, cur = self._head, self._head._next
while count<index:
count += 1
pre, cur = cur, cur._next
pre._next = cur._next
# 根据值返回节点的索引
def searchbyvalue(self, value):
count = 0
cur = self._head
index = []
while cur != None:
if cur._value == value:
index.append(count)
count += 1
cur = cur._next
if not index:
return False
else:
return index
# 根据索引返回节点的值
def searchbyindex(self, index):
count = 0
cur = self._head
if index < 0 or index > (self.length()-1):
print("The input index is out of range")
else:
while count < index:
count += 1
cur = cur._next
return cur._value
双向链表
双向链表双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。 所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点
python的双向链表实现
class Node(object):
"""双向链表的结点"""
def __init__(self, item):
# item存放数据元素
self.item = item
# next 指向下一个节点的标识
self.next = None
# prev 指向上一结点
self.prev = None
class BilateralLinkList(object):
"""双向链表"""
def __init__(self):
self._head = None
# 判断链表是否为空
def is_empty(self):
return self._head is None
# 链表长度
def length(self):
# 初始指针指向head
cur = self._head
count = 0
# 指针指向None 表示到达尾部
while cur is not None:
count += 1
# 指针下移
cur = cur.next
return count
# 遍历链表
def items(self):
# 获取head指针
cur = self._head
# 循环遍历
while cur is not None:
# 返回生成器
yield cur.item
# 指针下移
cur = cur.next
# 向链表头部添加元素
def add(self, item):
node = Node(item)
if self.is_empty():
# 头部结点指针修改为新结点
self._head = node
else:
# 新结点指针指向原头部结点
node.next = self._head
# 原头部 prev 指向 新结点
self._head.prev = node
# head 指向新结点
self._head = node
# 尾部添加元素
def append(self, item):
node = Node(item)
if self.is_empty(): # 链表无元素
# 头部结点指针修改为新结点
self._head = node
else: # 链表有元素
# 移动到尾部
cur = self._head
while cur.next is not None:
cur = cur.next
# 新结点上一级指针指向旧尾部
node.prev = cur
# 旧尾部指向新结点
cur.next = node
# 指定位置插入元素
def insert(self, index, item):
if index <= 0:
self.add(item)
elif index > self.length() - 1:
self.append(item)
else:
node = Node(item)
cur = self._head
for i in range(index):
cur = cur.next
# 新结点的向下指针指向当前结点
node.next = cur
# 新结点的向上指针指向当前结点的上一结点
node.prev = cur.prev
# 当前上一结点的向下指针指向node
cur.prev.next = node
# 当前结点的向上指针指向新结点
cur.prev = node
# 删除结点
def remove(self, item):
if self.is_empty():
return
cur = self._head
# 删除元素在第一个结点
if cur.item == item:
# 只有一个元素
if cur.next is None:
self._head = None
return True
else:
# head 指向下一结点
self._head = cur.next
# 下一结点的向上指针指向None
cur.next.prev = None
return True
# 移动指针查找元素
while cur.next is not None:
if cur.item == item:
# 上一结点向下指针指向下一结点
cur.prev.next = cur.next
# 下一结点向上指针指向上一结点
cur.next.prev = cur.prev
return True
cur = cur.next
# 删除元素在最后一个
if cur.item == item:
# 上一结点向下指针指向None
cur.prev.next = None
return True
# 查找元素是否存在
def find(self, item):
return item in self.items()
循环链表
在单链表基础上,将头尾链接,组成循环
python的循环链表实现
class Node(object):
"""节点"""
def __init__(self, item):
self.item = item
self.next = None
class SinCycLinkedlist(object):
"""单向循环链表"""
def __init__(self):
self.__head = None
# 判断链表是否为空
def is_empty(self):
return self.__head == None
# 返回链表的长度
def length(self):
# 如果链表为空,返回长度0
if self.is_empty():
return 0
count = 1
cur = self.__head
while cur.next != self.__head:
count += 1
cur = cur.next
return count
# 遍历链表
def travel(self):
if self.is_empty():
return
cur = self.__head
print cur.item,
while cur.next != self.__head:
cur = cur.next
print cur.item,
print ""
# 头部添加节点
def add(self, item):
node = Node(item)
if self.is_empty():
self.__head = node
node.next = self.__head
else:
#添加的节点指向_head
node.next = self.__head
# 移到链表尾部,将尾部节点的next指向node
cur = self.__head
while cur.next != self.__head:
cur = cur.next
cur.next = node
#_head指向添加node的
self.__head = node
# 尾部添加节点
def append(self, item):
node = Node(item)
if self.is_empty():
self.__head = node
node.next = self.__head
else:
# 移到链表尾部
cur = self.__head
while cur.next != self.__head:
cur = cur.next
# 将尾节点指向node
cur.next = node
# 将node指向头节点_head
node.next = self.__head
# 在指定位置添加节点
def insert(self, pos, item):
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):
count += 1
cur = cur.next
node.next = cur.next
cur.next = node
# 删除一个节点
def remove(self, item):
# 若链表为空,则直接返回
if self.is_empty():
return
# 将cur指向头节点
cur = self.__head
pre = None
while cur.next != self.__head:
if cur.item == item:
# 先判断此结点是否是头节点
if cur == self.__head:
# 头节点的情况
# 找尾节点
rear = self.__head
while rear.next != self.__head:
rear = rear.next
self.__head = cur.next
rear.next = self.__head
else:
# 中间节点
pre.next = cur.next
return
else:
pre = cur
cur = cur.next
# 退出循环,cur指向尾节点
if cur.item == item:
if cur == self.__head:
# 链表只有一个节点
self.__head = None
else:
# pre.next = cur.next
pre.next = self.__head
# 查找节点是否存在
def search(self, item):
if self.is_empty():
return False
cur = self.__head
if cur.item == item:
return True
while cur.next != self.__head:
cur = cur.next
if cur.item == item:
return True
return False
双向循环链表
顾名思义,双向循环链表就是将双向链表的头尾相连,构成循环
python的双向循环链表实现
# 1.节点构造
class Node(object):
def __init__(self, elem):
self.elem = elem
self.next = None
self.prev = None
class DoubleCircleLinkedList(object):
# 2.成员构造
def __init__(self, node=None):
self._head = node
# 3.返回大小
def length(self):
if self.is_empty():
return 0
else:
cur = self._head.next
n = 1
while cur != self._head:
cur = cur.next
n += 1
return n
# 4.判空
def is_empty(self):
return self._head is None
# 5.增
def addFirst(self, elem):
node = Node(elem)
if self.is_empty(): # 链表为空
node.next = node
node.prev = node
self._head = node
else:
node.next = self._head
node.prev = self._head.prev
self._head.prev.next = node
self._head.prev = node
self._head = node
def addLast(self, elem):
if self.is_empty():
self.addFirst(elem)
else:
node = Node(elem)
cur = self._head.next
while cur.next != self._head:
cur = cur.next
cur.next = node
node.prev = cur
node.next = self._head
self._head.prev = node
def add(self, pos, elem):
if pos <= 0:
self.addFirst(elem)
elif pos >= self.length():
self.addLast(elem)
else:
cur = self._head.next
n = 1
while cur.next != self._head:
if n == pos:
break
cur = cur.next
n += 1
node = Node(elem)
node.prev = cur.prev
cur.prev.next = node
node.next = cur
cur.prev = node
# 6.删
def remove(self, elem):
if self.is_empty():
return
else:
if self._head.elem == elem:
if self.length == 1:
self._head = Node
else:
self._head.prev.next = self._head.next
self._head.next.prev = self._head.prev
self._head = self._head.next
cur = self._head.next
while cur != self._head:
if cur.elem == elem:
cur.prev.next = cur.next
cur.next.prev = cur.prev
cur = cur.next
# 7.查
def travel(self):
cur = self._head
while cur.next != self._head:
print(cur.elem, end=' ')
cur = cur.next
print(cur.elem)
def search(self, elem):
if self.is_empty():
return False
else:
cur = self._head.next
if self._head.elem == elem:
return True
else:
while cur != self._head:
if cur.elem == elem:
return True
else:
cur = cur.next
return False
静态链表
使用静态链表存储数据,需要预先申请足够大的一整块内存空间,也就是说,静态链表存储数据元素的个数从其创建的那一刻就已经确定,后期无法更改。
不仅如此,静态链表是在固定大小的存储空间内随机存储各个数据元素,这就造成了静态链表中需要使用另一条链表(通常称为"备用链表")来记录空间存储空间的位置,以便后期分配给新添加元素使用。
这意味着,如果你选择使用静态链表存储数据,你需要通过操控两条链表,一条是存储数据,另一条是记录空闲空间的位置。
而使用动态链表存储数据,不需要预先申请内存空间,而是在需要的时候才向内存申请。也就是说,动态链表存储数据元素的个数是不限的,想存多少就存多少。
同时,使用动态链表的整个过程,你也只需操控一条存储数据的链表。当表中添加或删除数据元素时,你只需要通过 malloc 或 free 函数来申请或释放空间即可,实现起来比较简单。
python的静态链表实现
class Node:
def __init__(self, next, val=None):
self.val = val # 值
self.next = next # 游标。最后一个元素的游标必须是 0
class SLinkList:
# 分配线性表长度、定义线性表
def __init__(self, size=7):
self.size = size
self.link = [Node((i + 1) % self.size) for i in range(self.size)]
# 线性表清空
def clearSLL(self):
self.__init__()
# 线性表是否为空
def isEmpty(self):
return False if self.link[self.size - 1].next else True
# 查找空位置
def findEmpty(self):
ind = self.size
for i in range(1, self.size - 1):
if self.link[i].val is None:
ind = i
break
return ind
# 指定位置插入元素
def insert(self, ind, ele):
sua = -1
# 前一个元素
pre = self.size - 1
# 插入元素的位置(第一个空位置)
insertLoc = self.link[0].next
# 条件判断
if ind < 1 or ind >= pre or insertLoc >= self.size:
return 0
# 第一个元素的索引
for i in range(1, self.size - 1):
index = self.link[pre].next
if i == ind:
self.link[pre].next = insertLoc
# 元素插入
self.link[insertLoc].val = ele
self.link[insertLoc].next = index
# 首位元素
self.link[0].next = self.findEmpty()
sua = 1
break
if self.link[index].val is None:
break
pre = index
return sua
# 查找线性表某位置的元素
def getByIndex(self, ind):
if ind < 1 or ind >= self.size - 1:
return -1
index = self.link[self.size - 1].next
if index == 0:
return -1
for i in range(1, ind):
index = self.link[index].next
return self.link[index].val
# 查找线性表的元素所在位置
def locateElement(self, ele):
index = self.link[self.size - 1].next
ind = -1
if index == 0:
return ind
for i in range(1, self.size - 1):
if self.link[index].val == ele:
ind = i
break
if self.link[index].val is None:
break
index = self.link[index].next
return ind
# 删除线性表指定位置的元素
def deleteElement(self, ind):
sua = -1
# 前一个索引
pre = self.size - 1
for i in range(1, self.size - 1):
index = self.link[pre].next
# 当前位置是个空位置
if self.link[index].val is None:
break
# 已经遍历到第i个位置
if i == ind:
self.link[pre].next = self.link[index].next
self.link[index].val = None
# 删除元素的游标指向备用链表
self.link[index].next = self.link[0].next
# 首位元素
self.link[0].next = index
sua = 1
break
pre = index
return sua
# 按照线性表排序线性表遍历
def travelLink(self):
print("*" * 50)
index = self.link[self.size - 1].next
while self.link[index].val:
print(
f"value = {self.link[index].val} next = {self.link[index].next}"
)
index = self.link[index].next
print("*" * 50)
# 按照索引遍历
def traversingByIndex(self):
print("*" * 50)
for i in range(self.size):
print(
f"index = {i}, value = {self.link[i].val} next = {self.link[i].next}"
)
print("*" * 50)