# -*- coding: utf-8 -*-
"""双向循环链表"""
class Node(object):
def __init__(self, item=None, prev=None, next=None):
self.item, self.prev, self.next = item, prev, next
class CirculaDoubleLinkList(object):
def __init__(self, maxsize=None):
node = Node()
node.next, node.prev = node, node
self.root = node
self.maxsize = maxsize
self.length = 0
def __len__(self):
return self.length
def tailnode(self):
return self.root.prev
def headnode(self):
return self.root.next
def append(self, item):
if self.maxsize and self.length >= self.maxsize:
raise Exception("Full")
node = Node(item)
tail_node = self.tailnode()
tail_node.next = node
node.prev = tail_node
node.next = self.root
self.root.prev = node
self.length += 1
def appendleft(self, item):
if self.maxsize and self.length >= self.maxsize:
raise Exception("Full")
node = Node(item)
if self.root.next is self.root: # empty
self.root.next = node
node.prev = self.root
node.next = self.root
self.root.prev = node
else:
headnode = self.headnode()
node.prev = self.root
self.root.next = node
node.next = headnode
headnode.prev = node
self.length += 1
def iter_node(self):
if self.root.next is self.root:
raise Exception("Lins in empty")
curnode = self.root.next
while curnode.next is not self.root:
yield curnode
curnode = curnode.next
yield curnode
def iter_node_reverse(self): # 反向遍历
if self.root.next is self.root:
raise Exception("List is empty")
curnode = self.tailnode()
while curnode.prev is not self.root:
yield curnode
curnode = curnode.prev
yield curnode
def __iter__(self):
for node in self.iter_node():
yield node.item
def remove(self, item): # 删除成功返回1 否则返回-1
prevnode = self.root
for node in self.iter_node():
if node.item == item:
prevnode.next = node.next
node.next.prev = node.prev
del node
self.length -= 1
return 1
else:
prevnode = prevnode.next
return -1
def find(self, item): # 查找元素 找到返回元素下标记 否则返回-1
index = 0
for node in self.iter_node():
if node.item == item:
return index
index += 1
return -1
def pop(self):
if not self.root.next:
raise EmptyError("List is empty")
tail_node = self.tailnode()
tail_node.prev.next = tail_node.next
tail_node.next.prev = tail_node.prev
del tail_node
self.length -= 1
def popleft(self):
if self.root.next is None:
raise Exception("List is empty")
headnode = self.root.next
self.root.next = headnode.next
headnode.next.prev = self.root
del headnode
self.length -= 1
def clear(self):
for node in self.iter_node():
del node
self.length = 0
# 基本方法单测
# def test_list():
# ll = CirculaDoubleLinkList()
#
# ll.append(0)
# ll.append(1)
# ll.append(2)
# assert ll.length == 3
#
# assert [node.item for node in ll.iter_node()] == [0, 1, 2]
# assert [node.item for node in ll.iter_node_reverse()] == [2, 1, 0]
#
# ll.remove(0)
# assert ll.length == 2
# assert list(ll) == [1, 2]
#
# ll.appendleft(0)
# assert ll.length == 3
# assert list(ll) == [0, 1, 2]
#
# ret = ll.find(2)
# assert ret == 2
#
# ll.popleft()
# ret1 = ll.find(0)
# assert ret1 == -1
#
# ll.clear()
# assert ll.length == 0
######################################################
# 定义异常类
######################################################
class FullError(Exception):
pass
class EmptyError(Exception):
pass
######################################################
# 双向循环链表实现双端队列
######################################################
class DoubleQueue(CirculaDoubleLinkList):
def append(self, value):
"""尾端增加元素"""
if len(self) >= self.maxsize:
raise FullError("queue full")
super().append(value)
def appendleft(self, value):
"""头部增加元素、"""
if len(self) >= self.maxsize:
raise FullError("queue full")
super(DoubleQueue, self).appendleft(value)
def pop(self):
if not len(self):
raise EmptyError("queue empty")
tail_node = self.tailnode()
value = tail_node.item
super(DoubleQueue, self).pop()
return value
def popleft(self):
if not len(self):
raise EmptyError("queue empty")
head_node = self.headnode()
value = head_node.item
super().popleft()
return value
def iter_value(self):
return self.iter_node()
# 单测
# def test_double_queue():
# maxsize = 5
# dq = DoubleQueue(maxsize)
# for i in range(maxsize):
# dq.append(i)
#
# assert len(dq) == 5
#
# import pytest
# with pytest.raises(FullError) as full_err:
# dq.append(5)
# assert "full" in str(full_err.value)
#
# with pytest.raises(FullError) as full_err:
# dq.appendleft(6)
# assert "full" in str(full_err.value)
#
# dq.pop()
#
# values = list()
# for node in dq.iter_value():
# values.append(node.item)
# assert values == [0, 1, 2, 3]
#
# dq.popleft()
# values = list()
# for node in dq.iter_value():
# values.append(node.item)
# assert values == [1, 2, 3]
# assert dq.pop() == 3
# assert dq.popleft() == 1
# dq.pop()
#
# with pytest.raises(EmptyError) as empty_err_info:
# dq.pop()
# assert "empty" in str(empty_err_info.value)
############################################################
# 循环双向链表实现 栈 Stack
############################################################
class Stack(DoubleQueue):
def push(self, value):
self.append(value)
def pop(self):
return super().pop()
def __len__(self):
return super(Stack, self).__len__()
def print_stack(self):
stack_values = list()
if self.length:
for node in self.iter_node():
stack_values.append(node.item)
return stack_values
# 循环双向链表实现栈 单测
# def test_stack():
# maxsize = 5
# stack = Stack(maxsize)
# for i in range(maxsize):
# stack.push(i)
#
# values = stack.print_stack()
# assert values == [0, 1, 2, 3, 4]
#
# assert len(stack) == 5
#
# import pytest
# with pytest.raises(FullError) as full_err:
# stack.push(8)
# assert "full" in str(full_err.value)
#
# assert stack.pop() == 4
# assert stack.print_stack() == [0, 1, 2, 3]
#
# for _ in range(stack.length):
# stack.pop()
# assert stack.print_stack() == []
#
# with pytest.raises(EmptyError) as empty_err:
# stack.pop()
# assert "empty" in str(empty_err.value)