1. 顺序表
1.1将表中元素顺序地存放在一块连续的存储区域里,元素间的顺序关系由它们的存储顺序自然地表示
1.2 如果表的元素大小不统一,顺序表的存储方式:将实际数据元素另行存储,在顺序表各单元位置保存对相应元素的引用信息(链接)。
1.3 不修改表的结构的操作只有两种模式,直接访问(O(1))、基于一个整型变量,按下标循环检查和处理(O(n))
1.4 Python中list存储空间分配的实现策略:在建立空表时,系统分配一块能容纳8个元素的存储区,区满换一块4倍大的存储区,若表已经很大,则换存储区时容量加倍。
顺序表:
最重要的优势是O(1)时间的定位元素访问。很多简单操作的效率也比较高。
最重要的麻烦是加入/删除等操作的效率问题。这类操作改变表中元素序列的结构,是典型的变动操作。这是由于元素在顺序表的存储区里连续排列。
只有特殊的尾端插入/删除操作具有O(1)的时间复杂度。但插入操作复杂度还受到元素存储区固定大小的限制。通过适当的(加倍)存储区扩充策略,一系列尾端插入可以达到O(1)的平均复杂度。
顺序表的优点和缺点都在于元素存储的集中方式和连续性。如果程序里需要巨大的线性表,采用顺序表实现就需要巨大块的连续存储空间,这也可能造成存储管理方面的困难。
2. 链接表
优点:
表结构是通过链接起来的结点形成的,结点之间的顺序由链接关系决定,链接可以修改,表的结构很容易调整和修改。
不需要修改结点里的数据元素或移动它们,只通过修改结点之间的链接,就能灵活的修改表的结构和数据排列方式。
整个表由小的存储块组成,容易安排和管理。
缺点:
定位访问需要线性时间,这是相对顺序表相比的最大劣势。
简单单链表的尾端操作需要线性时间。
要找到当前元素的前一元素,必须从头开始扫描结点。这种操作应尽量避免。双链表可以解决这个问题,但每个结点要付出更高的存储代价。
为存储一个元素需要多用一个链接域。双链表需要增加两个链表域。
Python自定义单链表:
class LNode:
def __init__(self, elem, next_=None):
self.elem = elem
self.next = next_
class LinkedListUnderflow(ValueError):
pass
class LList:
@staticmethod
def is_duplicate(elem, current):
if len(current) == 0:
return False
for e in current:
if elem == e:
return True
def __init__(self, elem=[]):
if len(elem) == 0:
self._head = None
self.num = 0
return
p = LNode(0)
self._head = p
for e in elem:
p.next = LNode(e)
p = p.next
self._head = self._head.next
self.num = len(elem)
def is_empty(self):
return self._head is None
def __len__(self):
return self.num
def prepend(self, elem): # 在表头插入数据
self._head = LNode(elem, self._head)
self.num += 1
def pop(self): # 删除表头节点并返回这个节点的数据
if self._head is None:
raise LinkedListUnderflow("inpop")
e = self._head.elem
self._head = self._head.next
self.num -= 1
return e
def append(self, elem): # 节点末尾附加
self.num += 1
if self._head is None:
self._head = LNode(elem)
return
p = self._head
while p.next is not None:
p = p.next
p.next = LNode(elem)
def pop_last(self): # 删除最后节点
if self._head is None:
raise LinkedListUnderflow("inpop_last")
p = self._head
self.num -= 1
if p.next is None:
e = p.elem
self._head = None
return e
while p.next.next is not None:
p = p.next
e = p.next.elem
p.next = None
return e
def elements(self): # 生成器方法
p = self._head
while p is not None:
yield p.elem
p = p.next
def __add__(self, other): # 两链表相加
if not isinstance(other, LList):
raise LinkedListUnderflow("TypeError")
else:
if self._head is None:
self._head = other._head
else:
p = self._head
while p.next is not None:
p = p.next
p.next = other._head
self.num += other.num
return self
def insert(self, index, elem): # 指定索引插入操作
count = 0
if index >= self.num or index< 0:
raise IndexError
p = LNode(elem)
self.num += 1
if index == 0:
p.next = self._head
self._head = p
else:
e = self._head
while count < index - 1:
count += 1
e = e.next
p.next = e.next
e.next = p
def __delitem__(self, key): # 删除指定索引元素
if key >= self.num or key <0:
raise IndexError
p = self._head
if key == 0:
self._head = p.next
else:
count = 0
while count < key - 1:
count += 1
p = p.next
if key == self.num - 1:
p.next = None
else:
p.next = p.next.next
self.num -= 1
def del_minimal(self): # 删除最小元素
if self._head is None:
raise LinkedListUnderflow
p = self._head
if p.next is None:
self._head = None
min_value = self._head.elem
while p.next is not None:
if p.elem < min_value:
min_value = p.elem
p = p.next
self.del_elem(min_value)
def del_elem(self, elem): # 删除指定元素
if self._head is None:
return
p = self._head
if p.next is None:
if p.elem == elem:
self._head = None
self.num -= 1
while p.next is not None:
if p.next.elem == elem:
p.next = p.next.next
self.num -= 1
else:
p = p.next
if self._head.elem == elem:
self._head = self._head.next
self.num -= 1
def del_if(self, pred): # 删除满足pred谓词条件的元素
if self._head is None:
return
p = self._head
if p.next is None:
if pred(p.elem):
self._head = None
while p.next is not None:
if pred(p.next.elem):
p.next = p.next.next
self.num -=1
else:
p = p.next
if pred(self._head.elem):
self._head = self._head.next
self.num -= 1
def del_duplicate(self): # 删除重复的元素
if self._head is None or self._head.nextis None:
return
p = self._head
current = [p.elem]
while p.next is not None:
if LList.is_duplicate(p.next.elem,current):
p.next = p.next.next
self.num -= 1
else:
current.append(p.next.elem)
p = p.next
def interleaving(self, another): # 交错变动
if not isinstance(another, LList):
raise LinkedListUnderflow
self.num += another.num
if self._head is None:
self._head = another._head
return
if another._head is None:
return
p = self._head
e = another._head
result = LList()
result._head = LNode(p.elem)
q = result._head
q.next = LNode(e.elem)
q = q.next
while p.next is not None or e.nextis not None:
if p.next is not None:
q.next =LNode(p.next.elem)
q = q.next
p = p.next
if e.next is not None:
q.next =LNode(e.next.elem)
q = q.next
e = e.next
self._head = result._head
class LCList: # 循环单链表类
def __init__(self, elem=[]):
self._rear = None
for e in elem:
self.append(e)
def is_empty(self):
return self._rear is None
def prepend(self, elem): # 前端插入
p = LNode(elem)
if self._rear is None:
p.next = p
self._rear = p
else:
p.next = self._rear.next
self._rear.next = p
def append(self, elem): # 尾端插入
self.prepend(elem)
self._rear = self._rear.next
def pop(self): # 前端弹出
if self._rear is None:
raise LinkedListUnderflow("inpop of CLList")
p = self._rear.next
if self.rear is p:
self._rear = None
else:
self._rear.next = p.next
return p.elem