线性表的基本需要和链接表
线性表定义:一些元素的序列,维持着元素之间的一种线性关系实现线性表的基本需要:
能够找到表中的首元素
从表中的任一元素出发,可以找到它之后的下一个元素。
当然,表元素保存在连续的存储区(顺序表)能够满足需求,其中元素间的顺序关联是隐式的,但要满足这两个需求,并不一定需要连续存储元素,实现线性表的另一种常用方式是基于链接结构,用链接关系显式表示元素之间的顺序关联,这样的线性表称为链接表或链表。链表的基本想法:
表中元素分别存储在独立的存储块里
保证从任一结点可找到与之相关的下一个结点
在前一个结点用链接的方式显式记录与下一个结点的关联
1. 单链表的实现
结点class LNode:
def __init__(self, elem, next_=None):
self.elem = elem
self.next = next_
单链表的相关操作实现class LList:
def __init__(self):
self._head = None
def is_empty(self):
return self._head is None
def prepend(self, elem): # 前端添加
self._head = LNode(elem, self._head)
def prepop(self): # 前端删除
if self._head is None:
raise LinkedListUnderflow('in prepop')
e = self._head.elem
self._head = self._head.next
return e
def append(self, elem): # 尾部添加
if self._head is None:
self._head = LNode(elem)
return
p = self._head
while p.next:
p = p.next
p.next = LNode(elem)
def pop(self): # 尾部删除
if self._head is None:
raise LinkedListUnderflow("in pop")
p = self._head
if not p.next: # 表中只有一个元素
e = p.elem
self._head = None
return e
while p.next.next:
p = p.next
e = p.next.elem
p.next = None
return e
def for_each(self, proc): # proc 为某个操作
p = self._head
while p:
proc(p.elem)
p = p.next
2. 有尾结点的单链表class LList1(LList):
def __init__(self):
super().__init__()
self._rear = None
def prepend(self, elem):
if self._head is None:
self._head = LNode(elem, self._head)
self._rear = self._head
else:
self._head = LNode(elem, self._head)
def append(self, elem):
if self._head is None:
self._head = LNode(elem, self._head)
self._rear = self._head
else:
self._rear.next = LNode(elem)
self._rear = self._rear.next
def pop(self):
if self._head is None:
raise LinkedListUnderflow("in pop")
p = self._head
if p.next is None: # 表中只有一个元素
e = p.elem
self._head = None
return e
while p.next.next:
p = p.next
e = p.next.elem
p.next = None
self._rear = p
return e
3. 循环单链表class LCList:
"""docstring for LCList"""
def __init__(self):
self._rear = None
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("in pop of CLList")
p = self._rear.next
if self._rear is p:
self._rear = None
else:
self._rear.next = p.next
return p.elem
def print_all(self):
if self.is_empty():
return
p = self._rear.next
while True:
print(p.elem)
if p is self._rear:
break
p = p.next
4. 双链表
结点class DLNode(LNode):
def __init__(self, elem, prev=None, next_=None):
super().__init__(elem, next_)
self.prev = prev
实现:class DLList(LList1):
def __init__(self):
super().__init__()
def prepend(self, elem):
p = DLNode(elem)
if self._head is None:
self._rear = p
else:
p.next = self._head
self._head.prev = p
self._head = p
def append(self, elem):
p = DLNode(elem)
if self._head is None:
self._head = p
else:
p.prev = self._rear
self._rear.next = p
self._rear = p
def prepop(self):
if self._head is None:
raise LinkedListUnderflow("in prepop of DLList")
e = self._head.elem
self._head = self._head.next
if self._head is not None:
self._head.prev = None
return e
def pop(self):
if self._head is None:
raise LinkedListUnderflow('in pop of DLList')
e = self._rear.elem
self._rear = self._rear.prev
if self._rear is None:
self._head = None
else:
self._rear.next = None
return e