用数组array实现栈、队列与用链表linked_list实现栈、队列及相应的应用基于python语言(from Goodrich)

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))


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值