单链表的简单变形
为单链表添加一个尾节点,使尾端加入新元素的操作时间为 O(1) 。
class LList1(LList): #继承自LList类,添加了一个新的域名来保存结尾的链接
def __init__(self):
LList.__init__(self)
self._rear = None
#空表的每次操作都会涉及到_rear,尾端的变动操作也会涉及到_rear,_rear中保存的链接永远都是最后一个元素的链接。
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_last(self):
if self._head is None:
raise LinkedListUnderflow('in pop_list')
p = self._head
if p.next is None:
e = p.elem
self._head = None
self._rear = None
return e
while p.next.next is not None:
p = p.next
e = p.next.elem
p.next = None
self._rear = p
return e
循环单链表
链表的最后一个元素的链接域保存第一个元素的链接,为一个环状结构,这种情况下链表对象指向尾元素更合适,可以在 O(1) 时间内查找到表头和表尾。
class LCList:
def __init__(self):
self._rear = None
def is_empty(self):
return self._rear is None
def propend(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): #和前端加入相同,区别在于_rear是否变动
self.propend(elem)
self._rear = self._rear.next
def pop(self): #前端删除
if self._rear in None:
raise LinkedListUnderflow("in pop of CLList")
p = self._rear.next
if self._rear.next is p:
self._rear = None
else:
self._rear.next = p.next
return p.elem
def printall(self):
if self.is_empty():
return
p = self._rear.next
while True:
print p.elem
if p is self._rear: #判断p为尾元素时结束
break
p = p.next
双链表
单链表每次删除元素都需要找到他之前的元素,不能同时支持首尾两端的操作都为
O(1)
,为每个节点再添加一个指向他前面的元素的链接,这样就得到了双链表,可以提高两边的高效操作。
双链表的节点中再添加一个引用域
prev
来保存上一个元素的链接。
当删除一个元素
p
时,把他前后的元素的域链接好就行:
p.prev.next = p.next
p.next.prev = p.prev
当然得考虑一下前后无节点的情况。
当在元素
m.next.prev = p
p.next = m.next
m.next = p
p.prev = m
双链表类
- 节点类
class DLNode(LNode):
def __init__(self, elem, prev=None, next_=None):
LNode.__init__(self, elem, next_)
self.prev = prev
class DLList(LList1):
def __init__(self):
LList1.__init__(self)
#is_empty,find,filter,printall都可以继承
def prepend(self, elem):
p = DLNode(elem, None, self._head) #p作为首端元素插入时,next的值确定为self._head
if self._head is None:
self._head = p
self._rear = p
else:
self._head.prev = p
self._head = p
def append(self, elem):
p = DLNode(elem, self._rear, None)
if self._head is None:
self._head = p
self._rear = p
else:
self._rear.next = p
self._rear = p
# def pop(self):
# if self._head is None:
# raise LinkedListUnderflow("in pop of DLList")
# p = self._head
# if p.next is None: #拿到第一个元素
# self._head = None #改第二个元素的prev
# self._rear = None #改self._head
# else: #分三种情况:空表,只有一个元素的表,含有多个元素的表
# p.next.prev = None
# self._head = p.next
# return p.elem
def pop(self):
if self._head is None:
raise LinkedListUnderflow("in pop 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_last(self):
# if self._head is None:
# raise LinkedListUnderflow("in pop_last of DLList")
# p = self._rear
# if p.prev is None:
# self._head = None
# self._rear = None
# else:
# p.prev.next = None
# self._rear = p.prev
# return p.elem
def pop_last(self):
if self._head is None:
raise LinkedListUnderflow("in pop_last 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