Date:2019-07-07
本博客是基于Goodrich的数据结构与算法python语言实现数据的第五章、第六章、第七章的总结:
下面是原始数据中第五章、第六章、第七章的目录:
第五章-基于数组的序列
5.1 python序列类型
5.2 低层次数组(5.2.1 引用数组 5.2.2 python中的紧凑数组)
5.3 动态数组和摊销(5.3.1 实现动态数组 5.3.2 动态数组的摊销分析 5.3.3 python列表类)
5.4 python序列类型的效率(5.4.1 python的列表和元组类 5.4.2 python的字符串类)
5.5 使用基于数组的序列(5.5.1 为游戏存储高分 5.5.2 为序列排序 5.5.3 简单密码技术)
5.6 多维数据集
第六章 栈、队列和双端队列
6.1 栈(6.1.1 栈的抽象数据类型 6.1.2 简单的基于数组的栈的实现 6.1.3 使用栈实现数据的逆置 6.1.4 括号和HTML标记匹配)
6.2队列 (6.2.1 队列的抽象数据类型 6.2.2 基于数组的队列实现)
6.3 双端队列 (6.3.1 双端队列的抽象数据类型ADT 6.3.2 使用环形数组实现双端队列 6.3.3 python collections模块中的双端队列)
第七章 链表
7.1 单向链表(7.1.1 用单向链表实现栈 7.1.2 用单向链表实现队列)
7.2 循环链表(7.2.1 轮转调度 7.2.2 用循环链表实现队列)
7.3 双向链表(7.3.1 双向链表的基本实现 7.3.2 用双向链表实现双端队列)
7.4 位置列表的抽象数据类型(7.4.1 含位置信息的列表抽象数据类型 7.4.2 双向链表实现)
7.5 位置列表的排序
7.6 案例研究:维护访问频率(7.6.1 使用有序表 7.6.2 启发式动态调整列表)
7.7 基于链表的序列与基于数组的序列
第五章的代码内容:
# 5-1 探索列表长度和底层大小关系的实验
import sys
n = 100
data = []
for k in range(n):
a = len(data)
b = sys.getsizeof(data)
print('length:{0:3d};size in btyes:{1:4d}'.format(a, b))
data.append(None)
实现动态数组DynamicArray类
# 5-3 使用ctypes模块提供的原始数组实现DynamicArray类
import ctypes
class DynamicArray:
def __init__(self):
self._n = 0
self._capacity = 1
self._A = self._make_array(self._capacity)
def __len__(self):
return self._n
def __getitem__(self,k):
if not 0 <= k < self._n:
raise IndexError('invalid index')
return self._A[k]
def append(self, obj):
if self._n == self._capacity:
self._resize(2*self._capacity)
self._A[self._n] = obj
self._n += 1
def _resize(self, c):
B = self._make_array(c)
for k in range(self._n):
B[k] = self._A[k]
self._A = B
self._capacity = c
def _make_array(self, c):
return(c * ctypes.py_object)()
# 5-4 测量python列表类增添操作的摊销花费
from time import time
def compute_average(n):
data = []
start = time()
for k in range(n):
data.append(None)
end = time()
return (end - start)/n
# 5-5 向列表中增添元素(DynamicArray类insert方法的实现)
def insert(self, k, value):
if self._n == self._capacity:
self._resize(2*self._capacity)
for j in range(self._n, k, -1):
self._A[j] = self._A[j-1] # 所有元素向后移动一个位置,为了value放到第k位置上。
self.A[k] = value
self._n += 1
# 5-6 从列表中删除元素(对DynamicArray类的remove方法的一种实现)
def remove(self, value):
for k in range(self._n):
if self._A[k] == value: # 遍历列表,找到value的位置k
for j in range(k, self._n-1): # 从k位置后面的元素,全部向前移动一个位置
self._A[j] = self._A[j+1]
self._A[self._n-1] = None
self._n -= 1
return
raise ValueError('value not found')
"""
以上的insert函数和remove函数证明了,针对列表的插入元素和删除元素的效率不高,最坏的时间效率是O(n),
因为需要将k位置后的元素进行前移动或者向后移动。
"""
例子:
# 例1:为某款视频游戏存储一列高分项目。5-7 一个简单的GameEntry类的python代码。其中包括返回游戏条目对象的姓名和分数的方法,还返回表示该条目的字符串方法
class GameEntry:
def __init__(self, name, score):
self._name = name
self._score = score
def get_name(self):
return self._name
def get_score(self):
return self._score
def __str__(self):
return '({0},{1})'.format(self._name, self._score)
# 例2:5-8 Scoreboard类的python代码,其中包含一系列有序的分数,这些分数代表GameEntry对象
"""
一个scoreboard对象只能存储一定数量的高分,一旦到达存储的极限,新的分数必须严格大于得分板上最低的‘最高分’
"""
class Scoreboard:
def __init__(self, capacity=10):
self._board = [None] * capacity
self._n = 0
def __getitem__(self, k):
return self._board[k]
def __str__(self):
return '\n'.join(str(self._board[j]) for j in range(self._n))
def add(self, entry):
score = entry.get_score()
good = self._n < len(self._board) or score > self._board[-1].get_score() # 要么高分板上还有位置,要么分数大于高分板上最后一个元素
if good:
if self._n < len(self._board):
self._n += 1
j = self._n - 1
while j > 0 and self._board[j-1].get_score() < score:
self._board[j] = self._board[j-1]
j -= 1
self._board[j] = entry
# 例3:5-10 在列表中执行插入排序的python代码
def insertion_sort(A):
for k in range(1, len(A)):
cur = A[k]
j = k
while j > 0 and A[j-1] > cur:
A[j] = A[j - 1]
j -= 1
A[j] = cur
"""
插入排序的嵌套循环在最坏的情况下会导致O(n^2)的运行时间。如果数组最初是反序,则工作量最大。另外,如果初始数组已基本排序或
已经完全排序,则插入排序运行时间为O(n),因为内层循环迭代次数很少或者完全没有迭代
"""
# 例4:5-11 凯撒密码的一个完整python类
class CaesarCipher:
def __init__(self, shift):
encoder = [None] * 26
decoder = [None] * 26
for k in range(26):
encoder[k] = chr((k+shift) % 26 + ord('A'))
decoder[k] = chr((k-shift) % 26 + ord('A'))
self._forward = ''.join(encoder)
self._backward = ''.join(decoder)
def encrypt(self, message):
return self._transform(message, self._forward)
def decrypt(self, secret):
return self._transform(secret, self._backward)
def _transform(self, original, code):
msg = list(original)
for k in range(len(msg)):
if msg[k].isupper():
j = ord(msg[k]) - ord('A')
msg[k] = code[j]
return ''.join(msg)
if __name__ == '__main__':
cipher = CaesarCipher(3)
message = "THE EAGLE IS IN PLAY;MEET AT JOE'S."
coded = cipher.encrypt(message)
print('Secret:', coded)
answer = cipher.decrypt(coded)
print('Message:', answer)
# 例5:三连棋游戏(管理三连棋游戏的完整python类) p144
class TicTacToe:
def __init__(self):
self._board = [['']*3 for j in range(3)]
self._player = 'X'
def mark(self,i,j):
if not (0 <= i <= 2 and 0 <= j <= 2):
raise ValueError('Invalid board position')
if self._board[i][j] != ' ':
raise ValueError('Board position occupied')
if self.winner() is not None:
raise ValueError('Game is already complete')
self._board[i][j] = self._player
if self._player == 'X':
self._player = 'O'
else:
self._player = 'X'
def _is_win(self,mark):
"""Check whether the board configuration is a win for the given player."""
board = self._board # local variable for shorthand
return (mark == board[0][0] == board[0][1] == board[0][2] or # row 0
mark == board[1][0] == board[1][1] == board[1][2] or # row 1
mark == board[2][0] == board[2][1] == board[2][2] or # row 2
mark == board[0][0] == board[1][0] == board[2][0] or # column 0
mark == board[0][1] == board[1][1] == board[2][1] or # column 1
mark == board[0][2] == board[1][2] == board[2][2] or # column 2
mark == board[0][0] == board[1][1] == board[2][2] or # diagonal
mark == board[0][2] == board[1][1] == board[2][0]) # rev diag
def winner(self):
"""Return mark of winning player, or None to indicate a tie."""
for mark in 'XO':
if self._is_win(mark):
return mark
return None
def __str__(self):
"""Return string representation of current game board."""
rows = ['|'.join(self._board[r]) for r in range(3)]
return '\n-----\n'.join(rows)
if __name__ == '__main__':
game = TicTacToe()
# X moves: # O moves:
game.mark(1, 1);
game.mark(0, 2)
game.mark(2, 2);
game.mark(0, 0)
game.mark(0, 1);
game.mark(2, 1)
game.mark(1, 2);
game.mark(1, 0)
game.mark(2, 0)
print(game)
winner = game.winner()
if winner is None:
print('Tie')
else:
print(winner, 'wins')
例4结果:
Secret: WKH HDJOH LV LQ SODB;PHHW DW MRH'V.
Message: THE EAGLE IS IN PLAY;MEET AT JOE'S.
例5结果:
第六章:主要是关于利用数组以及其中的python列表实现栈、队列和双端队列
# 本章内容是利用python列表实现栈和队列,以及使用环形数组实现双端队列。
# 6-1 Empty异常类的定义
class Empty(Exception):
pass
# 6-2 用python列表作为一个存储实现一个栈:将栈顶定位到数组/列表的末端
class ArrayStack:
def __init__(self):
self._data = []
def __len__(self): # 计算栈的长度
return len(self._data)
def is_empty(self): # 判断栈是否为空
return len(self._data) == 0
def push(self,e): # 向栈中增添元素e
self._data.append(e)
def top(self): # 返回栈顶元素
if self.is_empty():
raise Empty('Stack is empty')
return self._data[-1]
def pop(self): # 删除栈顶元素
if self.is_empty():
raise Empty('Stack is Empty')
return self._data.pop()
# 例1:使用栈实现数据的逆置 6-3 一个实现一个文件中各行的逆置函数
def reverse_file(filename):
S = ArrayStack()
origional = open(filename) # 打开原始文件,并将其写入S栈中,注意删除了每一行的换行符,为了统一标准(最后一行一般是没有换行符的)
for line in origional:
S.push(line.rstrip('\n'))
origional.close()
output = open(filename, 'w')
while not S.is_empty():
output.write(S.pop()+'\n')
output.close()
# 例2:分隔符的匹配算法"({[" and ")}]"。6-4 在算术表达式中分隔符匹配算法的函数实现
def is_matched(exper):
lefty = '({['
righty = ')}]'
S = ArrayStack()
for c in exper:
if c in lefty:
S.push(c)
elif c in righty:
if S.is_empty():
return False
if righty.index(c) != lefty.index(S.pop()):
return False
return S.is_empty()
# 例3:标记语言的标签匹配 6-5 测试一个HTML文本是否有匹配标签的函数
def is_matched_html(raw):
S = ArrayStack()
j = raw.find('<')
while j != -1:
k = raw.find('>',j+1)
if k == -1:
return False
tag = raw[j+1:k]
if not tag.startswith('/'):
S.push(tag)
else:
if S.is_empty():
return False
if tag[1:] != S.pop():
return False
j = raw.find('<',k+1)
return S.is_empty()
此处附上一般的HTML格式:
# 6-6 基于数组的队列的实现
class ArrayQueue:
DEFAULT_CAPACITY = 10
def __init__(self):
self._data = [None] * ArrayQueue.DEFAULT_CAPACITY # 此处定义了3个实例变量
self._size = 0
self._front = 0
def __len__(self): # 计算队列的长度
return self._size
def is_empty(self): # 判断队列是否为空
return self._size == 0
def first(self): # 返回队列的首尾元素
if self.is_empty():
raise Empty('Queue is empty')
return self._data[self._front]
def dequeue(self): # 删除队列的元素,注意3个实例变量的改变
if self.is_empty():
raise Empty('Queue is empty')
answer = self._data[self._front]
self._data[self._front] = None
self._front = (self._front + 1) % len(self._data)
self._size -= 1
return answer
def enqueue(self,e):
if self._size == len(self._data):
self._resize(2*len(self._data))
avail = (self._front + self._size) % len(self._data)
self._data[avail] = e
self._size += 1
def _resize(self, cap):
old = self._data
self._data = [None] * cap
walk = self._front
for k in range(self._size):
self._data[k] = old[walk]
walk = (1+walk) % len(old)
self._front = 0
# 自行实现:使用环形数组实现双端队列
第七章: 引入另一种线性表:链表;然后基于单向链表的栈、队列实现和基于双向链表的双向队列的实现。
虽然数组和链表都是数据结构中的线性表,但是他们有着一些不同,最明显的就是:数组对于索引、查找很快,但对于插入和删除效率不高;链表对于索引、查找效率不高,但对于插入和删除相当高效。他们两者的具体联系与区别可以参考我的另一篇博客:
数组和链表的区别
涉及基于单向链表得到的栈、单向队列;基于循环链表实现循环队列;基于双向链表生成的双端队列;以及几个例子。
class Empty(Exception):
pass
# 7-5 单向链表实现栈ADT
class LinkedStack:
"""LIFO Stack implementation using a singly linked list for storage."""
# -------------------------- nested _Node class --------------------------
class _Node:
"""Lightweight, nonpublic class for storing a singly linked node."""
__slots__ = '_element', '_next' # streamline memory usage
def __init__(self, element, next): # initialize node's fields
self._element = element # reference to user's element
self._next = next # reference to next node
# ------------------------------- stack methods -------------------------------
def __init__(self):
"""Create an empty stack."""
self._head = None
self._size = 0
def __len__(self): # 返回现有栈的长度
return self._size
def is_empty(self): # 判断现有栈是否为空
return self._size == 0
def push(self, e): # 在栈顶端插入元素
self._head = self._Node(e, self._head)
self._size += 1
def top(self): # 返回栈顶端元素
if self.is_empty():
raise Empty('Stack is empty')
return self._head._element
def pop(self): # 删除栈顶端元素
if self.is_empty():
raise Empty('Stack is empty')
answer = self._head._element
self._head = self._head._next
self._size -= 1
return answer
# 7-7 用单向链表实现队列ADT
class LinkedQueue:
class _Node:
"""Lightweight, nonpublic class for storing a singly linked node."""
__slots__ = '_element', '_next' # streamline memory usage
def __init__(self, element, next): # initialize node's fields
self._element = element # reference to user's element
self._next = next # reference to next node
# ------------------------------- queue methods -------------------------------
def __init__(self):
"""Create an empty queue."""
self._head = None
self._tail = None
self._size = 0
def __len__(self): # 计算队列的长度
return self._size
def is_empty(self): # 判断队列是否为空
return self._size == 0
def first(self): # 返回队列的第一个元素
if self.is_empty():
raise Empty('Queue is empty')
return self._head._element
def dequeue(self): # 删除队列首元素。首先需要判断是否为空,删除首元素后仍需判断是否为空(如为空,tail=None)
if self.is_empty():
raise Empty('Queue is empty')
answer = self._head._element
self._head = self._head._next
self._size -= 1
if self.is_empty():
self.tail = None
return answer
def enqueue(self,e):
newest = self._Node(e,None)
if self.is_empty():
self._head = newest
else:
self.tail._next = newest
self.tail = newest
self._size += 1
# 7-9 用循环链表实现循环队列类 (训练队列不需要队首标识,仅仅tail即可)
class CircularQueue:
class _Node:
"""Lightweight, nonpublic class for storing a singly linked node."""
__slots__ = '_element', '_next' # streamline memory usage
def __init__(self, element, next): # initialize node's fields
self._element = element # reference to user's element
self._next = next # reference to next node
def __init__(self):
self._tail = None
self._size = 0
def __len__(self): # 计算循环队列的长度
return self._size
def is_empty(self): # 判断循环队列是否为空
return self._size == 0
def first(self): # 返回循环队列的首位元素(tail后的元素)
if self.is_empty():
raise Empty('Queue is empty')
head = self._tail._next
return head._element
def dequeue(self): # 删除循环队列首位元素(tail后的元素),并返回删除的原首位元素的值
if self.is_empty():
raise Empty('Queue is empty')
oldhead = self._tail._next
if self._size == 1:
self._tail = None
else:
self._tail._next = oldhead._next
self._size -= 1
return oldhead._element
def enqueue(self, e): # 在循环队列的末尾增添元素,需要:该元素的后置元素设置;tail后置元素的更新;tail标记更新
newest = self._Node(e, None)
if self.is_empty():
newest._next =newest
else:
newest._next = self._tail._next
self._tail._next = newest
self._tail = newest
self._size += 1
def rotate(self):
if self._size > 0:
self._tail = self._tail._next
# 7-12 基于双向链表的基类
class _DoublyLinkedBase:
"""A base class providing a doubly linked list representation."""
#-------------------------- nested _Node class --------------------------
# nested _Node class
class _Node:
"""Lightweight, nonpublic class for storing a doubly linked node."""
__slots__ = '_element', '_prev', '_next' # streamline memory
def __init__(self, element, prev, next): # initialize node's fields
self._element = element # user's element
self._prev = prev # previous node reference
self._next = next # next node reference
#-------------------------- list constructor --------------------------
def __init__(self):
self._header = self._Node(None, None, None) # 头哨兵
self._tailer = self._Node(None, None, None) # 尾哨兵
self._header._next = self._tailer
self._tailer._prev = self._header
self._size = 0 # 只有头哨兵和尾哨兵,中间没有任何元素
#-------------------------- public accessors --------------------------
def __len__(self): # 计算长度
return self._size
def is_empty(self): # 判断是否为空
return self._size == 0
# -------------------------- nonpublic utilities --------------------------
def _insert_between(self,e,predecessor,successor): # 私有程序
newsest = self._Node(e,predecessor,successor)
predecessor._next = newsest
successor._prev = newsest
self._size += 1
return newsest
def _delete_between(self,node): # 私有程序
predecessor = node._prev
successor = node._next
predecessor._next = successor
successor._prev = predecessor
self._size -= 1
element = node._element
node._prev = node._next = node._element = None
return element
# 7-13 继承双向链表基类实现双端队列
from .doubly_linked_base import _DoublyLinkedBase
from ..exceptions import Empty
class LinkedDeque(_DoublyLinkedBase): # note the use of inheritance
"""Double-ended queue implementation based on a doubly linked list."""
def first(self):
"""Return (but do not remove) the element at the front of the deque.
Raise Empty exception if the deque is empty.
"""
if self.is_empty():
raise Empty("Deque is empty")
return self._header._next._element # real item just after header
def last(self):
"""Return (but do not remove) the element at the back of the deque.
Raise Empty exception if the deque is empty.
"""
if self.is_empty():
raise Empty("Deque is empty")
return self._trailer._prev._element # real item just before trailer
def insert_first(self, e):
"""Add an element to the front of the deque."""
self._insert_between(e, self._header, self._header._next) # after header
def insert_last(self, e):
"""Add an element to the back of the deque."""
self._insert_between(e, self._trailer._prev, self._trailer) # before trailer
def delete_first(self):
"""Remove and return the element from the front of the deque.
Raise Empty exception if the deque is empty.
"""
if self.is_empty():
raise Empty("Deque is empty")
return self._delete_node(self._header._next) # use inherited method
def delete_last(self):
"""Remove and return the element from the back of the deque.
Raise Empty exception if the deque is empty.
"""
if self.is_empty():
raise Empty("Deque is empty")
return self._delete_node(self._trailer._prev) # use inherited method
# 7-14 基于双向链表的positionalList类的实现
from .doubly_linked_base import _DoublyLinkedBase
class PositionalList(_DoublyLinkedBase):
"""A sequential container of elements allowing positional access."""
# -------------------------- nested Position class --------------------------
class Position:
"""An abstraction representing the location of a single element.
Note that two position instaces may represent the same inherent
location in the list. Therefore, users should always rely on
syntax 'p == q' rather than 'p is q' when testing equivalence of
positions.
"""
def __init__(self, container, node):
"""Constructor should not be invoked by user."""
self._container = container
self._node = node
def element(self):
"""Return the element stored at this Position."""
return self._node._element
def __eq__(self, other):
"""Return True if other is a Position representing the same location."""
return type(other) is type(self) and other._node is self._node
def __ne__(self, other):
"""Return True if other does not represent the same location."""
return not (self == other) # opposite of __eq__
# ------------------------------- utility methods -------------------------------
def _validate(self, p):
"""Return position's node, or raise appropriate error if invalid."""
if not isinstance(p, self.Position):
raise TypeError('p must be proper Position type')
if p._container is not self:
raise ValueError('p does not belong to this container')
if p._node._next is None: # convention for deprecated nodes
raise ValueError('p is no longer valid')
return p._node
def _make_position(self, node):
"""Return Position instance for given node (or None if sentinel)."""
if node is self._header or node is self._trailer:
return None # boundary violation
else:
return self.Position(self, node) # legitimate position
# ------------------------------- accessors -------------------------------
def first(self):
"""Return the first Position in the list (or None if list is empty)."""
return self._make_position(self._header._next)
def last(self):
"""Return the last Position in the list (or None if list is empty)."""
return self._make_position(self._trailer._prev)
def before(self, p):
"""Return the Position just before Position p (or None if p is first)."""
node = self._validate(p)
return self._make_position(node._prev)
def after(self, p):
"""Return the Position just after Position p (or None if p is last)."""
node = self._validate(p)
return self._make_position(node._next)
def __iter__(self):
"""Generate a forward iteration of the elements of the list."""
cursor = self.first()
while cursor is not None:
yield cursor.element()
cursor = self.after(cursor)
# ------------------------------- mutators -------------------------------
# override inherited version to return Position, rather than Node
def _insert_between(self, e, predecessor, successor):
"""Add element between existing nodes and return new Position."""
node = super()._insert_between(e, predecessor, successor)
return self._make_position(node)
def add_first(self, e):
"""Insert element e at the front of the list and return new Position."""
return self._insert_between(e, self._header, self._header._next)
def add_last(self, e):
"""Insert element e at the back of the list and return new Position."""
return self._insert_between(e, self._trailer._prev, self._trailer)
def add_before(self, p, e):
"""Insert element e into list before Position p and return new Position."""
original = self._validate(p)
return self._insert_between(e, original._prev, original)
def add_after(self, p, e):
"""Insert element e into list after Position p and return new Position."""
original = self._validate(p)
return self._insert_between(e, original, original._next)
def delete(self, p):
"""Remove and return the element at Position p."""
original = self._validate(p)
return self._delete_node(original) # inherited method returns element
def replace(self, p, e):
"""Replace the element at Position p with e.
Return the element formerly at Position p.
"""
original = self._validate(p)
old_value = original._element # temporarily store old element
original._element = e # replace with new element
return old_value # return the old element value
# 例1:位置列表的排序 # 7-17 在位置列表中执行插入排序的python代码
def insertion_sort(L):
"""Sort PositionalList of comparable elements into nondecreasing order."""
if len(L) > 1: # otherwise, no need to sort it
marker = L.first()
while marker != L.last():
pivot = L.after(marker) # next item to place
value = pivot.element()
if value > marker.element(): # pivot is already sorted
marker = pivot # pivot becomes new marker
else: # must relocate pivot
walk = marker # find leftmost item greater than value
while walk != L.first() and L.before(walk).element() > value:
walk = L.before(walk)
L.delete(pivot)
L.add_before(walk, value) # reinsert value before walk
# 例子2:利用positionalList类作为存储实现一个收藏夹的列表 # 7-18 FavoritesLise类
from .positional_list import PositionalList
class FavoritesList:
"""List of elements ordered from most frequently accessed to least."""
# ------------------------------ nested _Item class ------------------------------
class _Item:
__slots__ = '_value', '_count' # streamline memory usage
def __init__(self, e):
self._value = e # the user's element
self._count = 0 # access count initially zero
# ------------------------------- nonpublic utilities -------------------------------
def _find_position(self, e):
"""Search for element e and return its Position (or None if not found)."""
walk = self._data.first()
while walk is not None and walk.element()._value != e:
walk = self._data.after(walk)
return walk
def _move_up(self, p):
"""Move item at Position p earlier in the list based on access count."""
if p != self._data.first(): # consider moving...
cnt = p.element()._count
walk = self._data.before(p)
if cnt > walk.element()._count: # must shift forward
while (walk != self._data.first() and
cnt > self._data.before(walk).element()._count):
walk = self._data.before(walk)
self._data.add_before(walk, self._data.delete(p)) # delete/reinsert
# ------------------------------- public methods -------------------------------
def __init__(self):
"""Create an empty list of favorites."""
self._data = PositionalList() # will be list of _Item instances
def __len__(self):
"""Return number of entries on favorites list."""
return len(self._data)
def is_empty(self):
"""Return True if list is empty."""
return len(self._data) == 0
def access(self, e):
"""Access element e, thereby increasing its access count."""
p = self._find_position(e) # try to locate existing element
if p is None:
p = self._data.add_last(self._Item(e)) # if new, place at end
p.element()._count += 1 # always increment count
self._move_up(p) # consider moving forward
def remove(self, e):
"""Remove element e from the list of favorites."""
p = self._find_position(e) # try to locate existing element
if p is not None:
self._data.delete(p) # delete, if found
def top(self, k):
"""Generate sequence of top k elements in terms of access count."""
if not 1 <= k <= len(self):
raise ValueError('Illegal value for k')
walk = self._data.first()
for j in range(k):
item = walk.element() # element of list is _Item
yield item._value # report user's element
walk = self._data.after(walk)
def __repr__(self):
"""Create string representation of the favorites list."""
return ', '.join('({0}:{1})'.format(i._value, i._count) for i in self._data)
if __name__ == '__main__':
fav = FavoritesList()
for c in 'hello. this is a test of mtf': # well, not the mtf part...
fav.access(c)
k = min(5, len(fav))
print('Top {0}) {1:25} {2}'.format(k, [x for x in fav.top(k)], fav))
# 例子3:启发式动态调整列表,启发式算法尝试利用访问的局部性,就是在访问序列中采用movie-to-front启发式
# 7-20 FavoritesListMTF类实现mtf启发式,继承了FavoritesList和PositionalList
from .favorites_list import FavoritesList
from .positional_list import PositionalList
class FavoritesListMTF(FavoritesList):
"""List of elements ordered with move-to-front heuristic."""
# we override _move_up to provide move-to-front semantics
def _move_up(self, p):
"""Move accessed item at Position p to front of list."""
if p != self._data.first():
self._data.add_first(self._data.delete(p)) # delete/reinsert
# we override top because list is no longer sorted
def top(self, k):
"""Generate sequence of top k elements in terms of access count."""
if not 1 <= k <= len(self):
raise ValueError('Illegal value for k')
# we begin by making a copy of the original list
temp = PositionalList()
for item in self._data: # positional lists support iteration
temp.add_last(item)
# we repeatedly find, report, and remove element with largest count
for j in range(k):
# find and report next highest from temp
highPos = temp.first()
walk = temp.after(highPos)
while walk is not None:
if walk.element()._count > highPos.element()._count:
highPos = walk
walk = temp.after(walk)
# we have found the element with highest count
yield highPos.element()._value # report element to user
temp.delete(highPos) # remove from temp list
if __name__ == '__main__':
fav = FavoritesListMTF()
for c in 'hello. this is a test of mtf':
fav.access(c)
k = min(5, len(fav))
print('Top {0}) {1:25} {2}'.format(k, [x for x in fav.top(k)], fav))