Python实现 《算法导论 第三版》中的算法 第10章 基本数据结构

文章目录

      • 第10章 基本数据结构
        • 10.1 栈和队列
        • 10.2 链表

第10章 基本数据结构

10.1 栈和队列

栈和队列都是一种动态集合。栈实现后进先出(last-in, first-out, LIFO)的策略:最后进入的元素被最先删除。队列实现先进先出(first-in, first-out, FIFO)的策略:最先进入的元素被最先删除。

下面实现了书中的栈,包括:

  • P129:STACK-EMPTY,判断链表是否为空,见stack_empty
  • P129:PUSH,压入元素,见push
  • P130:POP,弹出元素,见pop
  • 判断栈是否已满,见stack_full
  • 自底向上输出栈中的元素,见stack_print
class MyStack:
    def __init__(self, maxsize):
        self.__maxsize = maxsize
        self.__top = -1
        self.__S = [0]*maxsize # 当作普通数组
        
    def stack_empty(self):
        return self.__top == -1

    def stack_full(self):
        return self.__top + 1 == self.__maxsize
    
    def push(self, x):
        if self.stack_full():
            print("Stack is full!")
            return
        else:
            self.__top += 1
            self.__S[self.__top] = x
        
    def pop(self):
        if self.stack_empty():
            print("Stack is empty!")
            return
        else:
            self.__top -= 1
            return self.S[self.__top+1]
        
    def stack_print(self):
        for i in range(self.__top+1):
            print(self.__S[i], end=' ')
    
    
def test():
    s = MyStack(8)
    s.pop() # Stack is empty!
    for i in range(8):
        s.push(i)
    s.push(8) # Stack is full!
    s.stack_print()
    

if __name__ == '__main__':
    test() 

下面实现了书中的队列,包括:

  • P130:ENQUEUE,入队,见enqueue
  • P130:DEQUEUE,出队,见dequeue
  • 判断队列是否为空,见queue_empty
  • 判断队列是否已满,见queue_full
  • 从头到尾输出队列中的元素,见queue_print
  • 输出存储队列的数组中的元素,见queue_print_all
  • P131:练习10.1-4,使入队和出队操作分别能够处理上溢(overflow)和下溢(underflow),enqueuedequeue已满足该题。
class MyQueue:
    def __init__(self, maxsize):
        self.__maxsize = maxsize
        self.__head = 0
        self.__tail = 0 # 该位置不存放元素
        self.__S = [0]*maxsize # 当作普通数组
        
    def queue_empty(self):
        return self.__head == self.__tail
        
    def queue_full(self):
        return self.__head == (self.__tail+1) % self.__maxsize
        
    def enqueue(self, x):
        if self.queue_full():
            print("Queue is full!")
            return
    
        self.__S[self.__tail] = x
        self.__tail = (self.__tail + 1) % self.__maxsize
            
    def dequeue(self):
        if self.queue_empty():
            print("Queue is empty!")
            return
        
        x = self.__S[self.__head]
        self.__head = (self.__head + 1) % self.__maxsize
        return x
        
    def queue_print(self):
        begin = self.__head
        end = self.__tail
        if self.__tail < self.__head:
            end = self.__tail + self.__maxsize
        for i in range(begin, end):
            print(self.__S[i % self.__maxsize], end=' ')
            
    def queue_print_all(self):
        print(self.__S)
            
    
def test():
    q = MyQueue(6)
    q.dequeue() # Queue is empty!
    for i in range(1,6):
        q.enqueue(i)
    q.enqueue(6) # Queue is full!
    q.queue_print()
        
    print()
    q.dequeue()
    q.enqueue(6)
    q.queue_print_all()
    q.queue_print()
    
    print()   
    q.dequeue()
    q.enqueue(7)
    q.queue_print_all()
    q.queue_print()    
       

if __name__ == '__main__':
    test()

10.2 链表

链表是一种链式结构,其中的对象按线性排列。与数组不同,链表的顺序由各个对象里的指针的决定,为动态集合提供了一种简单而领过的表示方法。双向链表(doubly linked list)中的每一个对象包含一个数据和两个指针(nextprev),头指针指向链表第一个结点,即头结点,尾指针指向最后一个结点,即尾结点。其中头指针必须存在,尾指针可有可无。

书中P131中简单的双向链表L包含一个指向链表头结点的指针L.head。如果L.head为空,则链表为空。

下面实现了该链表,包括:

  • P132:LIST-SEARCH,链表搜索,见search
  • P132:LIST-INSERT,在链表头部插入,插入结点变为头结点,见insertHead
  • P132:LIST-DELETE,链表删除,见delete
  • 判断链表是否为空,见empty
  • 在链表尾部插入,插入结点变为尾结点,见insertTail
  • 输出链表中的元素,见print
class DLListNode:
    '''Double linked list node'''
    def __init__(self, val=None, prev=None, nex=None):
        self.val = val
        self.prev = prev
        self.next = nex
        
    
class DLList:
    '''Double linked list with a head pointer and without sentinel'''
    def __init__(self):
        self.__head = None
        
    def empty(self):
        return not self.__head
        
    def insertTail(self, val):
        '''Insert a node with val in tail'''
        if self.empty():
            self.insertHead(val)
        else:
            new_node = DLListNode(val, None, None)
            cur = self.__head
            while cur and cur.next:
                cur = cur.next
            new_node.prev = cur
            cur.next = new_node
          
    def insertHead(self, val):
        '''Insert a node with val in head'''
        new_node = DLListNode(val, None, self.__head)
        if self.empty():
            self.__head = new_node
        else:
            self.__head.prev = new_node
            self.__head = new_node
            
    def search(self, val):
        '''Return the first node with val. If not, return None'''
        cur = self.__head
        while cur and cur.val != val:
            cur = cur.next
        return cur
            
    def delete(self, val):
        '''Delete the first node whose val is val'''
        node_deleted = self.search(val)
        if self.__head == node_deleted:
            node_deleted.next.prev = None
            self.__head = node_deleted.next
        else:
            node_deleted.prev.next = node_deleted.next
            node_deleted.next.prev = node_deleted.prev
        del node_deleted
                
    def print(self):
        if self.empty():
            print('Linked list is empty!')
            return
        cur = self.__head
        while cur:
            print(cur.val, end=' ')
            cur = cur.next
            
            
def test():
    dll = DLList()
    dll.print() # Linked list is empty!
    
    for i in range(5):
        dll.insertHead(i)
    dll.print() # 4 3 2 1 0 
    
    print()
    for i in range(5):
        dll.insertTail(i)
    dll.print() # 4 3 2 1 0 0 1 2 3 4
    
    print()
    for i in range(5):
        if dll.search(i):
            print("Find node", i)
    
    for i in range(5):
        print("Delete node %d:" % i, end=' ')
        dll.delete(i)
        dll.print()
        print() 
        
    
if __name__ == '__main__':
    test()

书中P133中带哨兵结点的双向循环链表L(circular, doubly linked list with a sentinel)稍微复杂一些,增加了一个哨兵L.nil。该链表包含几个性质:

  • L.nil是一个哑对象,其作用是简化边界条件的处理。
  • L.nil.next指向链表头结点,L.nil.prev指向链表尾结点。如果二者都指向L.nil本身,则链表为空。
  • 链表头结点的prev指向L.nil,尾结点的next指向L.nil
  • 因为L.nil.next指向头结点,所以我们就可以去掉链表中指向头结点的指针L.head

下面实现了该链表,包括:

  • P133:LIST-DELETE’,链表删除,见delete
  • P133:LIST-SEARCH’,链表搜索,见search
  • P133:LIST-INSERT’,在链表头部插入,插入结点变为头结点,见insertHead
  • 判断链表是否为空,见empty
  • 在链表尾部插入,插入结点变为尾结点,见insertTail
  • 输出链表中的元素,见print
class DLListNode:
    '''Double linked list node'''
    def __init__(self, val=None, prev=None, nex=None):
        self.val = val
        self.prev = prev
        self.next = nex
        
    
class CDDList:
    '''Circular double linked list with a sentinel'''
    def __init__(self):
        self.__nil = DLListNode() # __nil points to a sentinel
        self.__nil.prev = self.__nil
        self.__nil.next = self.__nil
        
    def empty(self):
        return self.__nil.next == self.__nil and self.__nil.prev == self.__nil
        
    def insertTail(self, val):
        '''Insert a node with val in tail'''
        tail = self.__nil.prev
        new_node = DLListNode(val, tail, self.__nil)
        tail.next = new_node
        self.__nil.prev = new_node
          
    def insertHead(self, val):
        '''Insert a node with val in head'''
        new_node = DLListNode(val, self.__nil, self.__nil.next)
        self.__nil.next.prev = new_node
        self.__nil.next = new_node
            
    def search(self, val):
        '''Return the first node with val. If not, return None'''
        cur = self.__nil.next
        while cur and cur.val != val:
            cur = cur.next
        return cur
            
    def delete(self, val):
        '''Delete the first node whose val is val'''
        node_deleted = self.search(val)
        node_deleted.prev.next = node_deleted.next
        node_deleted.next.prev = node_deleted.prev
        del node_deleted
                
    def print(self):
        if self.empty():
            print('Linked list is empty!')
            return
        cur = self.__nil.next
        while cur is not self.__nil:
            print(cur.val, end=' ')
            cur = cur.next
            
            
def test():
    dll = CDDList()
    dll.print() # Linked list is empty!
    
    for i in range(5):
        dll.insertHead(i)
    dll.print() # 4 3 2 1 0 
    
    print()
    for i in range(5):
        dll.insertTail(i)
    dll.print() # 4 3 2 1 0 0 1 2 3 4
    
    print()
    for i in range(5):
        if dll.search(i):
            print("Find node", i)
    
    for i in range(5):
        print("Delete node %d:" % i, end=' ')
        dll.delete(i)
        dll.print()
        print() 
        
    
if __name__ == '__main__':
    test()

你可能感兴趣的:(默认,Python,算法)