数组是常用的数据结构,但是有其局限性:
编译期需要确定元素大小
数组在内存中是连续的,插入或者删除需要移动数组中其他数据
数组适合处理确定长度的,对于插入或者删除不敏感的数据。如果数据是频繁变化的,就需要选择其他数据结构了。本文介绍链表。
链表是一种在存储单元上非连续、非顺序的存储结构。数据元素的逻辑顺序是通过链表中的指针链接次序实现。链表由一系列的节点组成,节点可以在运行时动态生成,因此链表的长度没有逻辑上的限制,有限制的是堆的大小。在单向链表中。每个节点包含两部分:数据域与指针域。数据域存储数据元素,指针域存储下一结点的指针。
单向链表是最简单的形式,每个节点是包含两个域:信息域(元素域)和链接域。链接指向链表中的下一个节点,最后一个节点的链接域则指向一个空值。
head 是头指针,保存首地址,item 存储数据,next 指向下一节点地址。
链表失去了序列的随机读取优点,同时链表增加了指针域,空间开销也较大,但它对存储空间的使用要相对灵活。
节点数据结构为数据元素item与指针next。
class Node(object):
"""单链表的结点"""
def __init__(self, item):
self.item = item
self.next = None
class SingleLinkList(object):
"""单链表"""
def __init__(self):
self._head = None
列表创建:
link_list = SingleLinkList()
# 创建节点
node1 = Node(1)
node2 = Node(2)
# 将节点添加到链表
link_list._head = node1
# 将第一个节点的next指针指向下一节点
node1.next = node2
# 访问链表
print(link_list._head.item) # 访问第一个节点数据
print(link_list._head.next.item) # 访问第二个节点数据
is_empty() 链表是否为空
length() 链表长度 ( o(n) )
items() 获取链表数据迭代器
add(item)链表头部添加元素 ( o(1) )
append(item) 链表尾部添加元素 ( o(1) )
insert(pos, item) 指定位置添加元素 ( o(n) )
remove(item) 删除节点 ( o(n) )
find(item) 查找元素是否存在 ( o(n) )
class singleLinkList(object):
def __init__(self, Node=None):
self._head = Node
def is_empty(self):
return self._head == None
def length(self):
cur = self._head
cnt = 0
while cur != None:
cnt += 1
cur = cur.next
return cnt
def travel(self):
cur = self._head
while cur != None:
print(cur.item, end=' ')
cur = cur.next
def add(self, val):
"插入头节点"
node = Node(val)
node.next = self._head
self._head = node
def append(self, val):
"插入尾节点"
node = Node(val)
if self.is_empty():
self._head = node
else:
cur = self._head
while cur.next != None:
cur = cur.next # 到当前尾节点
cur.next = node
def insert(self, pos, val):
"""在指定位置插入结点"""
if pos <= 0:
self.add(val)
elif pos >= self.length() - 1:
self.append(val) # append 在链表尾部加节点
else:
node = Node(item) # 定义节点?
cnt = 1
cur = self._head
pre = None
while cnt != pos:
pre = cur
cur = cur.next
cnt += 1
cur = node
cur.next = pre.next
pre.next = cur
def remove(self, val):
"移除指定元素"
if self.is_empty():
print("Empty linklist, Error!")
else:
cur = self._head
pre = None
while cur.item != val:
pre = cur
cur = cur.next
pre.next = cur.next
print("delete successfully")
del cur
def search(self, val):
"遍历查找某个值"
cur = self._head
cnt = 1
while cur.item != val:
cur = cur.next
cnt += 1
return cnt # 返回位置
双向链表在节点中增加一个指针域指向节点的前驱节点。因此每个节点有两个链接:一个指向前一个节点,而另一个链接指向下一个节点。头结点没有前驱结点、尾节点没有后驱结点(或者指向空值)。
class Node(object):
"""双向链表节点"""
def __init__(self, item):
# item 存放数据元素
self.item = item
# next 指向下一个节点
self.next = None
# pre 指向上一结点
self.pre = 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 travel(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
# 原头节点pre指针指向新节点
self._head.pre = 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.pre = 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.pre = cur.pre
# 当前上一节点的向下指针指向node
cur.pre.next = node
# 当前节点的向上指针指向新结点
cur.pre = 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.pre = None
return True
# 移动指针查找元素
while cur.next is not None:
if cur.item == item:
# 上一结点向下指针指向下一结点
cur.pre.next = cur.next
# 下一结点向上指针指向上一结点
cur.next.pre = cur.pre
return True
cur = cur.next
# 删除元素在最后一个
if cur.item == item:
# 上一结点向下指针指向None
cur.pre.next = None
return True
def find(self, item):
"""查找元素是否存在"""
return item in self.items()
常用操作:
is_empty(),判断链表是否为空 ,o(n)
length(),返回链表长度,o(n)
travel(),遍历链表,o(n)
add(item),在头部添加一个结点,o(1)
append(item),在尾部添加一个结点,o(1)
insert(position,item),在指定位置添加结点,o(n)
remove(item),删除值为item的第一个结点,o(n)
search(item),查找结点是否存在,o(n)
当单向链表的尾节点不指向None,而是指向头结点的时候,那么就构成了一个单向循环链表。
单循环链表中一些操作的时间复杂度:
is_empty(),判断链表是否为空 ,o(n)
length(),返回链表长度,o(n)
travel(),遍历链表,o(n)
add(item),在头部添加一个结点,o(n)
append(item),在尾部添加一个结点,o(1)
insert(position,item),在指定位置添加结点,o(n)
remove(item),删除值为item的第一个结点,o(n)
search(item),查找结点是否存在,o(n)
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
# 若头节点的元素就是要查找的元素item
if cur.item == item:
# 如果链表不止一个节点
if cur.next != self._head:
# 先找到尾节点,将尾节点的next指向第二个节点
while cur.next != self._head:
cur = cur.next
# cur指向了尾节点
cur.next = self._head.next
self._head = self._head.next
else:
# 链表只有一个节点
self._head = None
else:
pre = self._head
# 第一个节点不是要删除的
while cur.next != self._head:
# 找到了要删除的元素
if cur.item == item:
# 删除
pre.next = cur.next
return
else:
pre = cur
cur = cur.next
# cur 指向尾节点
if cur.item == item:
# 尾部删除
pre.next = cur.next
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
原文参考:
https://zhuanlan.zhihu.com/p/52878334
https://blog.csdn.net/qq_38851184/article/details/105750984