前言
之前学的顺序表和链表都是线性表,关注于数据如何存放,顺序表是采用连续的存储空间存放数据,但是链表是采用离散的存储空间进行存放数据,但是线性表存储的数据都是线性的;
我们如何对这些线性的数据进行操作呢,就需要用到接下来的堆栈和队列,堆栈和队列都是容器,关注于对数据的操作,堆栈是Stack 类似于一个杯子,只能从堆栈的一端进行操作数据,也就是栈顶,后进来的先出去,LIFO模型;
还有接下来一篇需要用到的队列也是一种容器,对数据的操作时从队列的一端存放元素,从队列的另一端取出元素,先进来的先出去,FIFO模型;
可以借助于之前的数据结构也就是顺序表或者队列来实现堆栈或者队列;
1. 实现堆栈
#_+_coding:utf-8_*_ #author: xuanxuan #Time : 2018/11/8 18:21 class Stack(object): """实现堆栈(使用顺序表--python中的list)""" def __init__(self): self.__list=[] def push(self,item): """往堆栈的顶部放入数据""" self.__list.append(item) # 把list的尾部当做堆栈的栈顶,时间复杂度O(1) # self.__list.insert(item) # 把list的头部当做堆栈的栈顶 时间复杂度O(n)---因为list内部使用顺序表存储的 def pop(self): """从栈顶pop删除一个元素""" if self.__list: self.__list.pop() # list的pop()删除列表尾部的元素(pop是按照索引去删元素) # self.__list.pop(0) # 如果是吧list的头部当做栈顶,pop()栈顶的元素也就是删除list的头部元素 def peek(self): """返回栈顶元素,但是不删除""" if self.__list: return self.__list[-1] def is_empty(self): """判断栈是否为空""" return not self.__list def size(self): """返回堆栈的长度""" return len(self.__list) if __name__=="__main__": s=Stack() print("堆栈是否为空:",s.is_empty()) s.push(1) print(s.peek()) s.push(2) print(s.peek()) s.push(3) print(s.peek()) s.push(4) print(s.peek()) print("堆栈的长度:",s.size()) print(s.peek()) s.pop() print(s.peek()) s.pop() print(s.peek()) s.pop() print(s.peek()) s.pop()
运行结果:
2. 实现队列
class Queue(object): """实现队列""" def __init__(self): self.__list=[] # 仍然是使用列表实现队列 def enqueue(self,item): """往队列的尾部添加元素""" self.__list.append(item) # 这里默认需要实现的队列的尾部就是list的尾部; # self.__list.insert(0,item) # 把list的头部当成队列的尾部 def dequeue(self): """在队列的头部执行删除操作""" return self.__list.pop(0) # 从list的头部删除元素(list的头部默认为队列的头部) # self.__list.pop() # 从list的尾部删除元素(是把list的尾部当成队列的头部操作的) 无论如何,队列的添加删除元素的操作总是一个O(1) 一个O(n) def is_empty(self): """判断队列是否为空""" return not self.__list def size(self): """返回队列的长度""" return len(self.__list) if __name__=="__main__": q=Queue() print("队列是否为空:", q.is_empty()) q.enqueue(1) # 入队(尾部) q.enqueue(2) q.enqueue(3) q.enqueue(4) print("队列的长度是:", q.size()) print(q.dequeue()) # 出队(头部) print(q.dequeue()) print(q.dequeue()) print(q.dequeue())
运行结果:
对于队列,添加和删除元素总是会有一个O(1) 一个O(n) ( 而栈可以在实现添加删除的时候都满足O(1)的操作 就是把列表的尾部当成栈顶来操作)所以具体实现队列的时候采用哪种方式,根据具体情况而定,如果出栈次数多,那么就把list的尾部当做队列的头部,入队:self__list.insert(0,item); 出队:self.__list.pop() ;
3. 实现双端队列
双端队列(deque)全名double-ended-queue 是一种具有队列和栈性质的数据结构;
双端队列的元素可以从两端弹出,其限定插入和删除操作在表的两端进行,双端队列可以在任何一端进行入队和出队;
class Deque(object): """实现双端队列""" def __init__(self): self.__list=[] def add_front(self,item): """在队列的头部添加元素""" self.__list.insert(0,item) # 把list的头部当做队列的头部 (list的那边当做队列的头,那边当做尾部,都一样,只不过需要对应起来) def add_rear(self,item): """在队列的尾部添加元素""" self.__list.append(item) def remove_front(self): """从队列的头部删除元素""" return self.__list.pop(0) def remove_rear(self): """从队列的尾部删除元素""" return self.__list.pop() def is_empty(self): """判断队列是否为空""" return not self.__list def size(self): """返回队列的尺寸""" return len(self.__list) if __name__=="__main__": dq=Deque() print("双端队列是否为空:",dq.is_empty()) dq.add_front(1) dq.add_front(2) dq.add_rear(-1) dq.add_rear(-2) print("双端队列的长度:",dq.size()) print(dq.remove_front()) print(dq.remove_rear()) print(dq.remove_front()) print(dq.remove_rear())
运行结果: