目录
本文题目编译自 Donne Martin 的开源项目
017使用单个数组实现多个栈
使用单个数组实现多个栈,并且实现每个栈入栈和出栈的方法。栈的介绍如下:
- 栈(stack)是限定仅在表尾进行插入或删除操作的线性表。
- 栈是一种数据结构,它按照后进先出的原则存储数据,先进入的数据被压入栈底,最后进入的数据在栈顶,需要读数据的时候从栈顶开始弹出数据。
挑战内容
本次挑战中,你需要在 n_stacks.py
文件中补充类 Stacks
的空缺部分。
Stacks
类是定义的使用单个数组实现多个栈的类。Stacks
中的__init__
方法用于初始化栈,参数num_stacks
用于指定栈的个数,参数stack_size
用于指定单个栈的长度。Stacks
中的abs_index
方法用于寻找进行入栈操作时数据存储的位置,即数组的索引,参数stack_index
用于指定是第几个栈,它需要返回一个表示数组索引的数字。Stacks
中的push
方法用于进行入栈操作,参数stack_index
用于指定是第几个栈,参数data
用于指定入栈的数据元素,它没有返回值。Stacks
中的pop
方法用于进行出栈操作,参数stack_index
用于指定是第几个栈,它需要返回出栈的那个数据元素。- 在进行入栈操作时,如果栈已经满了,则需要使用
raise
语句显示Exception
。 - 在进行出栈操作时,如果栈是空的,也需要使用
raise
语句显示Exception
。
代码如下:使用stack_index获取数组中的索引,使用数组来存取数据。
class Stacks(object):
def __init__(self, num_stacks, stack_size):
self.num_stacks=num_stacks
self.stack_size=stack_size
self.stack_pointers=[-1]*self.num_stacks
self.stack_array=[None]*self.stack_size*self.num_stacks
def abs_index(self, stack_index):
return stack_index*self.stack_size+self.stack_pointers[stack_index]
def push(self, stack_index, data)://先变指针,再写数据
if self.stack_pointers[stack_index]==self.stack_size-1:
raise Exception('Full')
self.stack_pointers[stack_index]+=1
array_index=self.abs_index(stack_index)
self.stack_array[array_index]=data
def pop(self, stack_index)://先取数据,再动指针
if self.stack_pointers[stack_index]==-1:
raise Exception('Empty')
array_index=self.abs_index(stack_index)
data=self.stack_array[array_index]
self.stack_array[array_index]=None
self.stack_pointers[stack_index]-=1
return data
018实现链栈
实现链栈入栈,出栈,查看栈顶元素,查看栈是否为空的方法。链栈的介绍如下:
- 链栈是指采用链接存储结构实现的栈。通常将链表的头部作为栈顶,尾部作为栈底。
挑战内容
本次挑战中,你需要在 stack.py
文件中补充类 Node
和类 Stack
的空缺部分。
-
Node
类是定义的结点。 -
Node
中的__init__
方法用于初始化结点,结点包含数据元素data
和指向下一个结点地址的指针next
。 -
Stack
类是定义的链栈。 -
Stack
中的__init__
方法用于初始化链栈,参数top
为栈顶的指针。 -
Stack
中的push
方法用于进行入栈操作,参数data
用于指定入栈的数据元素,它没有返回值。 -
Stack
中的pop
方法用于进行出栈操作,它没有参数,需要返回出栈的那个数据元素。如果栈是空的,返回None
。 -
Stack
中的peek
方法用于查看栈顶元素,它没有参数,需要返回栈顶的数据元素。 -
Stack
中的is_empty
方法用于查看栈是否为空,它没有参数,需要返回一个布尔值,即True
或者False
。代码如下:
class Node(object): def __init__(self, data, next=None): self.data=data self.next=next class Stack(object): def __init__(self, top=None): self.top=top def push(self, data): self.top=Node(data,self.top) def pop(self): if self.top is None: return None data=self.top.data self.top=self.top.next return data def peek(self): return self.top.data if self.top is not None else None def is_empty(self): return self.top is None
019实现一个跟踪其最小元素的栈
实现栈入栈,出栈,跟踪栈元素最小值的方法。要求如下:
- 实现一个最小值栈用于存储最小值,如果入栈的元素值比最小值栈的栈顶值小,就将这个值存入最小值栈。
- 算法运行的时间复杂度为 O(1)O(1)。
- 假设入栈的元素没有重复值。
挑战内容
本次挑战中,你需要在 stack_min.py
文件中补充类 StackMin
的空缺部分。
StackMin
类继承“实现链栈”挑战中的Stack
类。StackMin
中的__init__
方法继承Stack
类的初始化操作,并且将最小值栈初始化为一个Stack
类的实例。参数top
为栈顶的指针。StackMin
中的peek
方法用于寻找栈元素的最小值,即最小值栈的栈顶值。它没有参数,需要返回栈元素的最小值。如果最小值栈为空,则返回sys.maxsize
。StackMin
中的push
方法继承Stack
类的入栈操作,并且当入栈的元素值小于最小值栈的栈顶值时,对最小值栈执行入栈操作。参数data
用于指定入栈的数据元素,它没有返回值。StackMin
中的pop
方法继承Stack
类的出栈操作,并且当出栈的元素值是最小值时,对最小值栈执行出栈操作。它没有参数,需要返回出栈的那个数据元素。
代码:super()方法设计目的是用来解决多重继承时父类的查找问题,所以在单重继承中用不用 super 都没关系;但是,使用 super() 是一个好的习惯。一般我们在子类中需要调用父类的方法时才会这么用
super()的好处就是可以避免直接使用父类的名字.
import sys
class StackMin(Stack):
def __init__(self, top=None):
super(StackMin, self).__init__(top)//调用父类方法时使用
self.stack_of_mins = Stack()
def minimum(self):
if self.stack_of_mins.top is None:
return sys.maxsize
else:
return self.stack_of_mins.peek()
def push(self, data):
super(StackMin, self).push(data)
if data < self.minimum():
self.stack_of_mins.push(data)
def pop(self):
data = super(StackMin, self).pop()
if data == self.minimum():
self.stack_of_mins.pop()
return data
020实现包装多个栈的类
实现一种数据结构 SetOfStack
,它由多个栈组成,其中每个栈的容量限制为 indiv_stack_capacity
,当前一个栈填满时,新建一个栈。
挑战内容
本次挑战中,你需要在 set_of_stacks.py
文件中补充类 StackWithCapacity
和 SetOfStacks
的空缺部分。
-
StackWithCapacity
类继承“实现链栈”挑战中的Stack
类。 -
StackWithCapacity
中的__init__
方法继承Stack
类的初始化操作。参数top
为栈顶的指针,参数capacity
用于指定栈的容量,即栈的长度。 -
StackWithCapacity
中的push
方法继承Stack
类的入栈操作,参数data
用于指定入栈数据元素,它没有返回值。如果栈已经满了,需要使用raise
语句显示Exception
。 -
StackWithCapacity
中的pop
方法继承Stack
类的出栈操作,它没有参数,需要返回出栈的那个数据元素。 -
StackWithCapacity
中的is_full
方法用于查看栈是否已满,它没有参数,需要返回一个布尔值,即True
或者False
。 -
StackWithCapacity
中的is_empty
方法用于查看栈是否为空,它没有参数,需要返回一个布尔值,即True
或者False
。 -
SetOfStacks
类是定义的包装栈的类。 -
SetOfStacks
中的__init__
方法用于初始化,参数indiv_stack_capacity
用于指定单个栈的容量。 -
SetOfStacks
中的push
方法用于进行入栈操作,参数data
用于指定入栈的数据元素,它没有返回值。当前一个栈填满时,新建一个栈。 -
SetOfStacks
中的pop
方法用于进行出栈操作,它没有参数,需要返回出栈的那个数据元素。当栈中没有元素时,返回None
。
代码:综合运用
from stack import Stack
class StackWithCapacity(Stack)://固定容量的链栈类,使用父类方法用super函数
def __init__(self, top=None, capacity=10):
super(StackWithCapacity,self).__init__(top)
self.capacity=capacity
self.num_items=0//对节点进行计数,并用于判断栈的空满
def push(self, data):
if self.is_full():
raise Exception('full')
super(StackWithCapacity,self).push(data)
self.num_items+=1//节点数加一
def pop(self):
if self.is_empty():
return
data=super(StackWithCapacity,self).pop()
self.num_items-=1//节点数减一
return data
def is_full(self):
return self.num_items==self.capacity
def is_empty(self):
return self.num_items==0
class SetOfStacks(object):
def __init__(self, indiv_stack_capacity):
self.indiv_stack_capacity=indiv_stack_capacity
self.stacks=[]//建立列表(数组)存储各个容量栈
self.last_stack=None//表示当前栈的状态,此时没有加入列表
def push(self, data):
if self.last_stack is None or self.last_stack.is_full()://无状态(初始状态和元素取完返回的初始状态)或满状态时,生成固定容量链栈
self.last_stack=StackWithCapacity(None,self.indiv_stack_capacity)
self.stacks.append(self.last_stack)//加入新生成的固定容量链栈
self.last_stack.push(data)
def pop(self):
if self.last_stack is None:
return None
data=self.last_stack.pop()
if self.last_stack.is_empty():
self.stacks.pop()//弹出被取空的固定容量链栈
self.last_stack=self.stacks[-1] if self.stacks else None//列表为空则回到无类型状态
return data
021使用两个栈实现队列
使用两个栈实现队列。队列的介绍如下:
- 队列和栈一样,也是一种对数据的"存"和"取"有严格要求的线性存储结构。
- 队列只允许在表的前端进行删除操作,而在表的后端进行插入操作。进行插入操作的端称为队尾,进行删除操作的端称为队头。
挑战内容
本次挑战中,你需要在 queue_from_stacks.py
文件中补充类 QueueFromStacks
的空缺部分。
QueueFromStacks
使用两个栈实现队列类。QueueFromStacks
中的__init__
方法使用两个栈来进行初始化。QueueFromStacks
中的shift_stacks
方法用于将一个栈的元素依次弹出并插入另一个栈中,参数source
用于指定需要弹出元素的栈,参数destination
用于指定入用于插入元素的栈。QueueFromStacks
中的enqueue
方法用于进行入队操作,参数data
用于指定入队的数据元素,它没有返回值。QueueFromStacks
中的dequeue
方法用于进行出队操作,它没有参数,需要返回出队的那个数据元素。
原理:双栈栈底对栈底,左栈的栈顶进行入队操作,右栈的栈顶进行出队操作。显然,如果不把左栈的数据移入右栈,必然出现左栈多而右栈空的情形。解决方案:入队时把右栈数据全部移入左栈(右栈栈顶变成左栈栈底),出栈时把左栈数据全部移入右栈 (左栈栈顶变成右栈栈底)
代码:
from stack import Stack
class QueueFromStacks(object):
def __init__(self):
self.left_stack=Stack()
self.right_stack=Stack()
def shift_stacks(self, source, destination)://dastination是执行操作的栈,初始保持空,获取另一个栈的全部数据(另一个栈变成空)
while source.peek() is not None:
destination.push(source.pop())
def enqueue(self, data):
self.shift_stacks(self.right_stack,self.left_stack)
self.left_stack.push(data)
def dequeue(self):
self.shift_stacks(self.left_stack,self.right_stack)
return self.right_stack.pop()
023实现链式队列
实现链式队列入队,出队的方法。链式队列的介绍如下:
- 链式队列是使用链表实现的队列存储结构。
挑战内容
本次挑战中,你需要在 queue_list.py
文件中补充类 Node
和类 Queue
的空缺部分。
-
Node
类是定义的结点。 -
Node
中的__init__
方法用于初始化结点,结点包含数据元素data
和指向下一个结点地址的指针next
。 -
Queue
类是定义的链栈。 -
Queue
中的__init__
方法用于初始化链式队列。 -
Queue
中的enqueue
方法用于进行入队操作,参数data
用于指定入队的数据元素,它没有返回值。 -
Queue
中的dequeue
方法用于进行出队操作,它没有参数,需要返回出队的那个数据元素。如果队列是空的,返回None
。
代码:(基础扫盲)
class Node(object):
def __init__(self, data):
self.data=data
self.next=next
class Queue(object):
def __init__(self):
self.head=None
self.tail=None
def enqueue(self, data):
node=Node(data)
if self.head is None and self.tail is None:
self.head=node
self.tail=node
else:
self.tail.next=node
self.tail=node
def dequeue(self):
if self.head is None and self.tail is None:
return None
data=self.head.data
if self.head==self.tail:
self.head=None
self.tail=None
else:
self.head=self.head.next
return data