stack & queue, since 2020-04-18

(2020.04.18)
*注: 除了本文中提到的list表达,还可以用linked list实现stack/queue。

Stack

Stack: Last In First Out (LIFO)
Stack的array-based实现方法:
直接用Python的list实现。注意到stack.push()可用list.append()实现,而stack.pop()可用list.pop()实现。这种一种类的方法实为对另一种类的方法的调用,称为设计模式中的适配器模式 (adapter pattern)

class Empty(Exception):
    pass

class array_stack:
    def __init__(self):
        self._data = []
    def __len__(self):
        return len(self._data)

    def is_empty(self):
        return len(self._data) == 0

    def push(self, p):
        return self._data.append(p)

    def pop(self):
        if self.is_empty():
            raise Empty('Stack empty')
        return self._data.pop()

    def top(self):
        return self._data[-1]

复杂度分析:
考虑到该方法的base是Python list,所以操作可以参考list对应的操作。
stack.push(p): O(1) amortised
stack.pop(): O(1) amortised
stack.is_empty(): O(1)
stack.top(): O(1)
stack._ _ len _ _(): O(1)
提速方法:
初始化过程中将hidden list从长度0改为长度n (用户定义),这种方式比从长度0开始的list更高效 (但复杂度保持不变?)。
应用: reverse a sequence反转,matching parentheses and HTML tags检查括号匹配。
括号匹配的算法和实例:
对序列做扫描从左到右,每次遇到左括号(open symbol),push it into stack。每次遇到右括号(close symbol),pop a symbol from the stack(非空),并检测popped symbol和右括号是否是valid pair。如果完成扫描并且均是匹配,则该序列的括号合理匹配。

def is_match(seq):
    lefty, righty = '([{', ')]}'
    s = array_stack()
    for oc in seq:
        if oc in lefty:
            s.push(oc)
        elif oc in righty:
            if s.is_empty(): 
                return False
            if righty.index(oc) != lefty.index(s.pop()):
                return False
    return s.is_empty()

Stack相关面试题

(2022.09.13 Tues)
*设计一个数据结构,push和pop符合 stack的标准,同时每次pop值时也会包含当前stack中的最小值。
解决方案:除了用于实现push和pop操作的stack本体,还需要一个附加结构用于保存当前剩余stack中的最小值。可设计一个affiliated stack(a stack),该stack满足:与stack本体同样的push和pop操作,但每次push时将比较当前push的值与栈顶的值,如果小于栈顶值,则push,如果大约等于栈顶值,则复制栈顶值,将其push进这个stack。这样保证了每次stack本体从栈顶pop一个值时,a stack的栈顶pop出的值也是当前stack的最小值。
分析:该解决方案实现了题目要求,但空间复杂度达到了。可使用哈希对象作为元素push进a stack。该哈希对象的key是当前stack最小值,value是计数器,每次遇到push进的对象比key大,则计数器加1,比key小,则push进一个新的哈希对象。

Queue

Queue: First In First Out (FIFO)
操作: queue.enqueue(p)从尾部加入p, queue.dequeue()剔除头部点。
Queue的低效实现方法:

  • 直接用list实现,queue.push(a)参考list.append(a)queue.pop()参考list.pop(0)push复杂度O(1) amortised,pop复杂度是O(n),其中n表示list长度,因为list.pop(0)在删除了index=0元素后便将从index=1开始到结尾平移到index=0开始。
  • 与前一种方法相似,queue.push(a)相同,但queue.pop()的方法不同于list.pop(0)queue.pop()时queue的头部元素变成None,同时head index加1。这种方法的特点是push次数越多,list长度越长,pop次数越多list头部的None越多。

一种高效的实现方式: using an array Circularly
一个list,有头、尾两个指针,记录头、尾的位置,初始为0、0。每次push操作尾index+1,每次pop操作头index+1,前提是index+1之后的指针值没超过list长度。或者不设置尾指针,而有头指针结合queue length计算尾指针。如果超过list长度,则执行求模module操作,tail = (tail+1) % len(list),这种操作可以保证在index=9之后+1操作回到index=0的职位,成为一个circule。每次push操作后queue length += 1,每次pop操作后queue length -= 1。

class circular_array_queue:
    DEFAULT_CAPACITY = 20
    def __init__(self):
        self._data = [None] * circular_array_queue.DEFAULT_CAPACITY
        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 empty')
        return self._data[self._front]
    def dequeue(self):
        if self.is_empty():
            raise Empty('Queue empty')
        answer = self._data[self._front]
        self._data[self._front] = None
        self._front = (self._front + 1) % len(self._data) 
        # len(self._data) not exactly circular_array_queue.DEFAULT_CAPACITY, 
        # which depends on whether the queue is resized or not
        self._size -= 1
        return answer
    def enqueue(self, e):
        if self._size == len(self._data):
            self._resize(2*len(self._data))
        tail = (self._front + self._size) % len(self._data)
        self._data[tail] = e
        self._size += 1
    def _resize(self, newlen):
        old = self._data
        self._data = [None] * newlen
        walk = self._front
        for k in range(self._size):
            self._data[k] = old[walk]
            walk = (walk+1) % len(old)
        self._front = 0

复杂度分析:
queue.enqueue(n): O(1) amortised
queue.dequeue(): O(1) amortised
queue.first(): O(1)
queue.is_empty(): O(1)
queue.is_empty(): O(1)
queue.len(): O(1)

(2022.04.28 Thur)
queue的常规实现方法

class queue:
    def __init__(self):
        self.head = None
        self.tail = None
    def enqueue(self, node):
        if self.tail:
            self.tail.next = node
            tmp = self.tail
            self.tail = node
            self.tail.next = None
            self.tail.prev = tmp
        elif not self.head and not self.tail:
            self.head = node
            self.tail = node
            self.tail.prev = None
            self.head.next = None
            self.tail.next = None
            self.head.prev = None
        return 'enqueue done'
    @property
    def dequeue(self):
        if not self.head:
            tmp = None
        elif self.head == self.tail:
            tmp = self.head
            self.head = None
            self.tail = None
        else:
            tmp = self.head
            self.head = self.head.next 
            self.head.prev = None
        return tmp
    def __len__(self):
        cntr = 0
        if not self.head and not self.tail:
            pass
        else:
            tmp = self.head
            while tmp:
                cntr += 1
                tmp = tmp.next
        return cntr

reference:

  1. M.T. Goodrich and etc., Data Structures and Algorithms.

你可能感兴趣的:(stack & queue, since 2020-04-18)