算法漫游指北(第五篇):栈、队列、栈结构实现、基于列表实现栈、基于链表实现栈、基于列表实现队列、基于链表实现队列
2021-01-24 10:13
标签:单链表 其他 start art 删除元素 数据 front self deque 栈(stack),有些地方称为堆栈,但是不能叫堆,是一种容器,可存入数据元素、访问元素、删除元素,它的特点在于只能允许在容器的一端(称为栈顶端指标,英语:top)进行加入数据(英语:push)和输出数据(英语:pop)的运算。 没有了位置概念,保证任何时候可以访问、删除的元素都是此前最后存入的那个元素,确定了一种默认的访问顺序。 注意:栈(stack),有些地方称为堆栈,可以叫栈,但是不能叫堆,堆是Heap,是另外一种数据结构。 由于栈数据结构只允许在一端进行操作,因而按照后进先出(LIFO, Last In First Out)的原理运作。
栈可以用顺序表(数组)实现,也可以用链表实现。 对栈的两种主要操作是将一个元素压入栈和将一个元素弹出栈。入栈使用push()方法,出栈使用pop()方法。 另一个常用的操作是预览栈顶的元素。pop()方法虽然可以访问栈顶的元素,但是调用该方法后,栈顶元素也从栈中被永久性地删除了。peek()方法则只返回栈顶元素,而不删除它。 push()、pop()和peek()是栈的3个主要方法,但是栈还有其他方法和属性。 stack通常的操作: 数组栈是栈的一种实现方式,在C语言中以数组的形式实现,而在Python中,则可以使用与数组类似的列表进行实现。 执行过程图
分析:用列表作为容器,按照顺序存入元素,将最新存入的元素作为top指针即下次最先被取出的元素。 链表栈是以单链表为基础实现的栈数据结构,主要有以下几个关键点: 栈顶元素:栈顶元素即为链表的头结点 压栈:向链表的头结点插进入栈元素,无表头链表则替换插入元素为头结点 弹栈:弹出链表头结点,并将链表头结点替换为下一个元素 链表实现栈动图
分析过程: 1、创建值为10的第一个节点,将新节点的next指向之前的self.top即None,设置新的top指针为新节点node(10) 2、创建第二个节点node(20),将第二个节点的next指向第一个节点,设置新的top指针为新节点node(20) 3、创建第三个节点node(30),将第三个节点的next指向第二个节点,设置新的top指针为新节点node(20) 其实这里类似链表的头插法,即在链表的头部插入链表节点 4、从栈里取值过程,找到现在的top即下一个要被取出的节点,将self.top设置为之前的一个,返回现在的top的值。 1、对于顺序表和单链表,前端插入和删除都是O(1)的时间复杂度。 2、在操作数较少的情况下,数组栈需要不停的拓展存储空间、转移元素,这样消耗时间比较多。 3、在操作数较大的情况下,链表栈需要不停的创建存储Node的内存空间,相对耗时(注意数组栈的扩容方式是乘以2哦),所以此时链表栈用时稍多。 添加操作、删除操作时间复杂度皆为O(1) 队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。 队列是一种先进先出的(First In First Out)的线性表,简称FIFO。允许插入的一端为队尾,允许删除的一端为队头。队列不允许在中间部位进行操作!假设队列是q=(a1,a2,……,an),那么a1就是队头元素,而an是队尾元素。这样我们就可以删除时,总是从a1开始,而插入时,总是在队列最后。这也比较符合我们通常生活中的习惯,排在第一个的优先出列,最后来的当然排在队伍最后。
进行插入的一端成为队尾(rear),插入动作称为进队或入队。 进行删除的一端称为队头(front),删除动作称为出队。 队列的性质:先进先出(First-in, First-out)。
栈:后进先出(LIFO-last in first out):最后插入的元素最先出来。 队列:先进先出(FIFO-first in first out):最先插入的元素最先出来。 同栈一样,队列也可以用顺序表或者链表实现。 常见方法 列表实现队列动图
分析: 1、队列以列表作为容器,按顺序添加元素,将新增加的元素按照顺序添加到之前的列表的后面,head计数 是下一个要取出元素的下标,tail计数是目前使用已经使用过的列表容量的下标。 2、添加元素时,按照列表申请的内存空间顺序添加,将head计数指向0 3、取出元素时,根据head计数来取出,同时head计数+1 4、当head计数与tail计数相等时,则队列为空 过程分析: 1、添加第一个节点node(10),head指针(即代码中的self.front)指向node(10),tail指针(即代码中的self.rear)也指向node(10) 2、添加第二个节点node(20),head指针指向node(10), 在enqueue方法中,由于队列不为空,则执行else语句, 执行self.rear.next=node语句,即node(10).next=node(20) 执行self.rear = node ,使tail指针指向node(20),self.rear = node(20) 3、添加第三个节点node(30),head指针仍然指向node(10), 执行self.rear.next=node语句,即node(20).next=node(30) 执行self.rear = node ,使得tail指针指向node(30),self.rear = node(30) 4、添加第四个节点node(40),head指针仍然指向node(10), 执行self.rear.next=node语句,即node(30).next=node(40) 执行self.rear = node ,使tail指针指向node(40),self.rear = node(40) 5、取出队列节点,执行dequeue方法 执行item = self.front.val,即head指针指向的node(10)的值,取出10 执行self.front = self.front.next,即将head指针指向下一个,当前的self.front=node(10), node(10).next = node(20) ,所以这里执行的是self.front = node(20). 最后返回取出的节点的值。 添加操作、删除操作时间复杂度皆为O(1) 算法漫游指北(第五篇):栈、队列、栈结构实现、基于列表实现栈、基于链表实现栈、基于列表实现队列、基于链表实现队列 标签:单链表 其他 start art 删除元素 数据 front self deque 原文地址:https://www.cnblogs.com/Nicholas0707/p/12866304.html一、栈
栈结构实现
Stack() 建立一个空的栈对象
push() 把一个元素添加到栈的最顶层
pop() 删除栈最顶层的元素,并返回这个元素
peek() 返回最顶层的元素,并不删除它
isEmpty() 判断栈是否为空
size() 返回栈中元素的个数
基于列表实现栈
class Stack(object):
"""栈"""
def __init__(self):
self.items = []
?
def is_empty(self):
"""判断是否为空"""
return self.items == []
?
def push(self, item):
"""加入元素"""
self.items.append(item)
?
def pop(self):
"""弹出元素"""
if self.is_empty():
raise IndexError,‘pop from empty stack‘
return self.items.pop()
?
def peek(self):
"""返回栈顶元素"""
return self.items[len(self.items)-1]
?
def size(self):
"""返回栈的大小"""
return len(self.items)
?
if __name__ == "__main__":
stack = Stack()
stack.push("hello")
stack.push("world")
print stack.size()
print stack.peek()
print stack.pop()
print stack.pop()
print stack.pop()
基于链表实现栈
?
class Node:
"""链表节点类"""
def __init__(self,val):
self.val = val
self.next = None
?
def __str__(self):
return str(self.val)
class LinkedListStack:
"""链表结构堆栈类"""
def __init__(self):
"""初始化堆栈的属性"""
self.head = None
self.top = self.head # 堆栈的顶端,当前表示堆栈为空
self.length = 0
def is_empty(self):
"""判断堆栈是否为空"""
if self.top == None:
return True
else:
return False
def push(self, item):
"""向堆栈中存入数据"""
new_node = Node(item) #创造节点类
new_node.next = self.top #设置node为栈顶
self.top = new_node #将设置过的栈顶的指针指向原栈顶
self.length += 1
print("成功存入数据",item)
def pop(self):
"""从堆栈中取出数据"""
if self.is_empty():
print("堆栈已空,不能再取数据")
node = self.top # 先取到原栈顶
self.top = self.top.next # 将栈顶设置为原栈顶的下一个元素
self.length -= 1
print("取出数据",node.val)
?
return node.val # 返回原栈顶的值
?
def peek(self):
"""获取栈顶元素"""
if self.is_empty():
raise Exception("堆栈已空!")
print(‘查看栈顶元素‘,self.top.val)
return self.top.val
?
def size(self):
"""得到栈的长度"""
return self.length
?
def show(self): #输出栈
def _traversal(self):
node = self.top
while node and node.next:
yield node
node = node.next
yield node # 这里如果不yield,则栈底的元素会无法被遍历到,因为最后一个元素并不满足while循环的条件,会中止迭代
print(‘\n‘.join(map(lambda x:‘|{:^7}|‘.format(str(x)),_traversal(self)))+ ‘\n‘ + 7*‘-‘)
if __name__ == ‘__main__‘:
s = LinkedListStack()
s.push(10)
s.push(20)
# s.pop()
s.show()
s.push(30)
s.peek()
s.show()
s.pop()
s.show()
列表栈与链表栈
栈的时间复杂度
方法
复杂度
Access(取值)
O(n)
Search
O(n)
Insertion
O(1)
Deletion
O(1)
二、队列
队列的实现
- Queue() 创建一个空的队列
- enqueue(item) 往队列中添加一个item元素
- dequeue() 从队列头部删除一个元素
- is_empty() 判断一个队列是否为空
- size() 返回队列的大小
基于列表实现队列
class Queue(object):
"""队列"""
def __init__(self):
self.items = []
?
def is_empty(self):
return self.items == []
?
def enqueue(self, item):
"""进队列"""
self.items.insert(0,item)
?
def dequeue(self):
"""出队列"""
return self.items.pop()
?
def size(self):
"""返回大小"""
return len(self.items)
?
if __name__ == "__main__":
q = Queue()
q.enqueue("hello")
q.enqueue("world")
q.enqueue("nicholas")
print q.size()
print q.dequeue()
print q.dequeue()
print q.dequeue()
基于链表实现队列
?
class Node:
"""链表节点类"""
def __init__(self,val):
self.val = val
self.next = None
?
def __str__(self):
return str(self.val)
class LinkedListQueue:
"""链表结构堆栈类"""
def __init__(self):
"""初始化队列的属性"""
self.front = None #队列头部元素
self.rear = None #队尾元素
self.length = 0 #队列长度
def is_empty(self):
"""判断队列是否为空"""
if self.front == None:
return True
else:
return False
?
def enqueue(self,item):
"""进队列,向队列中加入一个元素"""
node=Node(item)
if self.is_empty():
self.front = node
else:
self.rear.next=node
self.rear = node
self.length += 1
print(‘向队列中加入‘,item)
?
?
def dequeue(self):
"""出队列,从队列中取出一个元素"""
if self.front is None:
raise "The queue is empty"
elif self.front is self.rear:
self.rear = None
item = self.front.val
self.front = self.front.next
self.length -= 1
print("取出数据",item)
return item
?
def peek(self):
"""查看队列头部"""
if self.is_empty():
raise Exception("队列已空!")
print(‘查看队列头部元素‘,self.front.val)
return self.front.val
?
def size(self):
"""得到队列的长度"""
return self.length
?
def show(self): #显示队列
def _traversal(self):
node = self.front
while node and node.next:
yield node
node = node.next
yield node # 这里如果不yield,则队列最后的元素会无法被遍历到,因为最后一个元素并不满足while循环的条件,会中止迭代
print(‘\n‘.join(map(lambda x:‘|{:^7}|‘.format(str(x)),_traversal(self)))+ ‘\n‘ + 7*‘-‘)
if __name__ == ‘__main__‘:
s = LinkedListQueue()
s.enqueue(10)
s.enqueue(20)
s.enqueue(30)
s.enqueue(40)
s.enqueue(50)
s.dequeue()
s.show()
s.enqueue(60)
s.peek()
s.show()
s.dequeue()
s.show()
链表实现队列动图
?队列时间复杂度
方法
复杂度
Access
O(n)
Search
O(n)
Insertion
O(1)
Deletion
O(1)
上一篇:FME如何使用Python?
下一篇:7、js——数组
文章标题:算法漫游指北(第五篇):栈、队列、栈结构实现、基于列表实现栈、基于链表实现栈、基于列表实现队列、基于链表实现队列
文章链接:http://soscw.com/essay/46268.html