栈实现

栈是一种操作受限的线性表只允许从一端插入和删除数据。栈有两种存储方式,即线性存储和链接存储(链表)。栈的一个最重要的特征就是栈的插入和删除只能在栈顶进行,所以每次删除的元素都是最后进栈的元素,故栈也被称为后进先出(LIFO)表。栈有两种处理方式,即进栈(push)和出栈(pop),因为在进栈只需要移动一个变量存储空间,所以它的时间复杂度为O(1),但是对于出栈分两种情况,栈未满时,时间复杂度也为O(1),但是当栈满时,需要重新分配内存,并移动栈内所有数据,所以此时的时间复杂度为O(n)。

  1. import abc
  2. class Stack(metaclass=abc.ABCMeta):
  3. @abc.abstractmethod
  4. def pop(self):
  5. pass
  6. @abc.abstractmethod
  7. def push(self, item):
  8. pass
  9. @abc.abstractmethod
  10. def clear(self):
  11. pass
  12. @abc.abstractmethod
  13. def empty(self):
  14. pass
  15. @abc.abstractmethod
  16. def size(self):
  17. pass
  18. @abc.abstractmethod
  19. def top(self):
  20. pass
  21. @abc.abstractmethod
  22. def show(self):
  23. pass
  24. class MyStack(Stack):
  25. def __init__(self):
  26. """ 初始化数据结构为 python 列表"""
  27. self.__data = []
  28. def push(self, item):
  29. """ 入栈 """
  30. self.__data.append(item)
  31. def empty(self):
  32. """ 判断是否为空栈 """
  33. return self.size() == 0
  34. def size(self):
  35. """ 输出栈的大小 """
  36. return len(self.__data)
  37. def pop(self):
  38. """ 出栈 """
  39. assert self.size() > 0, "stack is empty"
  40. return self.__data.pop()
  41. def top(self):
  42. """ 查看栈顶值 """
  43. assert self.size() > 0, "stack size is 0"
  44. return self.__data[self.size() - 1]
  45. def clear(self):
  46. """ 清空栈 """
  47. del self.__data[:]
  48. def show(self):
  49. str_start = "["
  50. for i in range(self.size()):
  51. if i == self.size() - 1:
  52. str_start += str(i)
  53. else:
  54. str_start += str(i) + ","
  55. str_start += "] top "
  56. print(str_start)
  57. def is_valid(s: str) -> bool:
  58. """ 括号匹配 """
  59. stack = MyStack()
  60. for i in s:
  61. if i in ["(", "[", "{"]:
  62. stack.push(i)
  63. else:
  64. if stack.empty():
  65. return False
  66. top_s = stack.pop()
  67. if i == ")" and top_s != "(":
  68. return False
  69. elif i == "]" and top_s != "[":
  70. return False
  71. elif i == "}" and top_s != "{":
  72. return False
  73. return stack.empty()

队列

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。

  1. import abc
  2. class ListQueue(metaclass=abc.ABCMeta):
  3. @abc.abstractmethod
  4. def dequeue(self):
  5. pass
  6. @abc.abstractmethod
  7. def enqueue(self, item):
  8. pass
  9. @abc.abstractmethod
  10. def empty(self):
  11. pass
  12. @abc.abstractmethod
  13. def size(self):
  14. pass
  15. @abc.abstractmethod
  16. def front(self):
  17. pass
  18. @abc.abstractmethod
  19. def show(self):
  20. pass
  21. class MyQueue(ListQueue):
  22. def __init__(self):
  23. """ 初始化数据结构为 python 列表"""
  24. self.__data = []
  25. def enqueue(self, item):
  26. """ 入队 """
  27. self.__data.append(item)
  28. def empty(self):
  29. """ 判断是否为空队 """
  30. return self.size() == 0
  31. def size(self):
  32. """ 输出队列的大小 """
  33. return len(self.__data)
  34. def dequeue(self):
  35. """ 出队 """
  36. assert self.size() > 0, "stack is empty"
  37. return self.__data.pop(0)
  38. def front(self):
  39. """ 查看队首元素 """
  40. assert self.size() > 0, "stack size is 0"
  41. return self.__data[0]
  42. def show(self):
  43. str_start = "front ["
  44. for i in range(self.size()):
  45. if i == self.size() - 1:
  46. str_start += str(i)
  47. else:
  48. str_start += str(i) + ","
  49. str_start += "] "
  50. print(str_start)

循环队列

从基本的队列数据结构中可以看到,在删除数据时候,需要对删除后的剩余数据进行位置转换,时间复杂度为O(n),为了解决这个问题,可以把队列当作一个首尾相连的环,这样在进行删除的元素时候就不用每次都移动剩余的元素,只需维护几个变量即可。这样做的优点就是可以适当的时候进行扩容和缩容,可以把时间复杂度均摊下来。

  1. class LoopQueue:
  2. def __init__(self, capacity=10):
  3. self.arr = [None] * (capacity+1) # 由于特意浪费了一个空间,所以arr的实际大小应该是用户传入的容量+1
  4. self.front = 0 # 队首下标
  5. self.tail = 0 # 下一个数据如队的下标
  6. self.size = 0 # 队列数据总量
  7. self.capacity = capacity # 队列容许的最大数据量
  8. def __len__(self):
  9. return len(self.arr)
  10. def size(self):
  11. # 获取队列中元素个数
  12. return self.size
  13. def get_capacity(self):
  14. # 获取队列容量
  15. return len(self.arr) - 1
  16. def is_full(self):
  17. # 判断队列是否为满 (取余) 当一个数据入队后如果和队首位置重复表示此时队列已满
  18. return (self.tail + 1) % len(self.arr) == self.front
  19. def is_empty(self):
  20. # 判断队列是否为空 可以判断队列中的元素个数 或是否队首和队尾下标重复(初始话的情况)
  21. # return front == tail
  22. return self.size == 0
  23. def get_front(self):
  24. # 获取队首
  25. return self.arr[self.front]
  26. def enqueue(self, e):
  27. # 入队
  28. if self.is_full():
  29. self.resize(self.get_capacity() * 2) # 如果队列满,以当前队列容积的2倍进行扩容
  30. self.arr[self.tail] = e
  31. self.tail = (self.tail + 1) % len(self.arr)
  32. self.size += 1
  33. def dequeue(self):
  34. # 先判断队列是否为空
  35. assert not self.is_empty(), "Cannot dequeue from en empty queue"
  36. result = self.arr[self.front]
  37. self.arr[self.front] = None
  38. # 更新其下标
  39. self.front = (self.front + 1) % len(self.arr)
  40. self.size -= 1
  41. # 如果元素个数少于容积的1/4并且元素个数
  42. if self.size < self.get_capacity() // 4 and self.get_capacity() > 1:
  43. self.resize(self.get_capacity() // 2)
  44. return result
  45. # 扩容或者缩容
  46. def resize(self, new_capacity: int):
  47. new_arr = [None] * (new_capacity + 1)
  48. for i in range(self.size):
  49. new_arr[i] = self.arr[(i + self.front) % len(self.arr)]
  50. self.arr = new_arr
  51. self.front = 0
  52. self.tail = self.size
  53. def show(self):
  54. print(self.arr)