博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
栈结构的经典算法题
阅读量:7136 次
发布时间:2019-06-28

本文共 5477 字,大约阅读时间需要 18 分钟。

栈结构

 

颠倒一个栈的元素顺序

问题:假设有一个栈{1,2,3,4,5,6},6是栈顶,1是栈底,现在要把这个栈中的元素颠倒一下。

思路:最简单的办法当然是把栈中的元素依次pop到一个数组中,然后把这个数组再push回栈里面即可,但这样需要O(n)的辅助空间。

下面介绍一种仅使用O(1)辅助空间的算法,我们知道,可以使用递归来模拟栈的操作。我们借助函数递归pop元素,这样在递归的函数栈上依次有

{6,5,4,3,2,1},1是栈顶,6是栈底,然后在递归返回的时候,如何把当前元素塞到原栈的底部呢?这里借助了另一个递归!

 

C++代码实现如下:

void Add2Bottom(stack
&s, int val){ int top; if (s.empty()) { s.push(val); } else { top = s.top(); s.pop(); Add2Bottom(s, val); s.push(top); } }void Reverse(stack
&s) { int top; if (!s.empty()) { top = s.top(); s.pop(); Reverse(s); Add2Bottom(s, top); } }int main(){ int n; int array[6] = {
1,2,3,4,5,6}; stack
s; for (n=0; n<6; n++) s.push(array[n]); Reverse(s); while (!s.empty()) { cout<
<

 

栈的min函数

定义栈的数据结构,要求添加一个min函数,能够得到栈的最小元素。要求函数min、push以及pop的时间复杂度都是O(1)。

思路:利用辅助栈,每次对stack push/pop一个元素时,同时也要更新辅助栈(存储最小元素的位置),例如:

 步骤              数据栈            辅助栈                最小值

1.push 3    3          0             3
2.push 4    3,4        0,0           3
3.push 2    3,4,2      0,0,2         2
4.push 1    3,4,2,1    0,0,2,3       1
5.pop       3,4,2      0,0,2         2
6.pop       3,4        0,0           3
7.push 0    3,4,0      0,0,2         0

 

C++代码实现:

#include 
#include
#include
using namespace std;template
class CStackWithMin{ public: CStackWithMin(void) {} virtual ~CStackWithMin(void) {} T& top(void); const T& top(void) const; void push(const T& value); void pop(void); const T& min(void) const; private: deque
m_data; // the elements of stack deque
m_minIndex; // the indices of minimum elements};// get the last element of mutable stacktemplate
T& CStackWithMin
::top(){ return m_data.back();}// get the last element of non-mutable stacktemplate
const T& CStackWithMin
::top() const{ return m_data.back();}// insert an elment at the end of stacktemplate
void CStackWithMin
::push(const T& value){ // append the data into the end of m_data m_data.push_back(value); // set the index of minimum elment in m_data at the end of m_minIndex if(m_minIndex.size() == 0) { m_minIndex.push_back(0); } else { if(value < m_data[m_minIndex.back()]) m_minIndex.push_back(m_data.size() - 1); else m_minIndex.push_back(m_minIndex.back()); }}// erease the element at the end of stacktemplate
void CStackWithMin
::pop(){ // pop m_data m_data.pop_back(); // pop m_minIndex m_minIndex.pop_back();}// get the minimum element of stacktemplate
const T& CStackWithMin
::min() const{ assert(m_data.size() > 0); assert(m_minIndex.size() > 0); return m_data[m_minIndex.back()];}

int main()

{
class CStackWithMin<int> stk;

 

stk.push(3);

cout<<"min="<<stk.min()<<endl;

 

stk.push(4);

cout<<"min="<<stk.min()<<endl;

 

stk.push(2);

cout<<"min="<<stk.min()<<endl;

 

stk.push(1);

cout<<"min="<<stk.min()<<endl;

 

stk.pop();

cout<<"min="<<stk.min()<<endl;

 

stk.pop();

cout<<"min="<<stk.min()<<endl;

 

stk.push(0);

cout<<"min="<<stk.min()<<endl;
}

 

 

 

 

栈的push、pop序列

输入两个整数序列,其中一个序列表示栈的push顺序,判断另一个序列有没有可能是对应的pop顺序。为了简单起见,我们假设push序列的任意两个整数都是不相等的。 

比如输入的push序列是1、2、3、4、5,那么4、5、3、2、1就有可能是一个pop系列。因为可以有如下的push和pop序列:push 1,push 2,push 3,push 4,pop,push 5,pop,pop,pop,pop,这样得到的pop序列就是4、5、3、2、1。但序列4、3、5、1、2就不可能是push序列1、2、3、4、5的pop序列。

 

 C++实现:

int verify(int in[], int out[], int N){    int n;      int m = 0;    stack
s; for (n=0; n

 

 

 

用栈实现队列

设2 个栈为A和B,A用作入队,B用作出队。

队满:A满且B不为空;
队空:A和B都为空;
入队
(1) 如果A未满,将新元素push 入栈A;
(2) 如果A已满,将栈A中所有元素依次pop 出并push 到栈B,然后将元素入栈A;
出队
(1) 如果B为空,则将栈A 中所有元素依次pop 出并push 到栈B,然后将元素出栈B;
(2) 如果B不为空,将栈B 的栈顶元素pop 出;

 

C++代码实现:

bool queue_empty(stack
&s1, stack
&s2){ return s1.empty() && s2.empty();}void enqueue(stack
&s1, stack
&s2, int val){ s1.push(val);}void dequeue(stack
&s1, stack
&s2, int &val){ int top; if (s2.empty()) { while (!s1.empty()) { top = s1.top(); s1.pop(); s2.push(top); } } if (!s2.empty()) { val = s2.top(); s2.pop(); } else { cout<<"error: queue is empty"<
s1; stack
s2; for (n=0; n<6; n++) enqueue(s1, s2, array[n]); while (!queue_empty(s1, s2)) { dequeue(s1, s2, n); cout<
<

注意:这里没有考虑栈空间可能满的问题。

 

其实,也可以用一个栈来模拟队列结构,仍然是借助递归栈,每次往栈插入元素时,把它塞到栈底,这样就实现了FIFO的队列结构。

代码如下:

void enqueue2(stack
&s, int val){ int top; if (s.empty()) { s.push(val); } else { top = s.top(); s.pop(); enqueue2(s, val); s.push(top); } }int main(){ int n; int array[6] = {
1,2,3,4,5,6}; stack
s; for (n=0; n<6; n++) enqueue2(s, array[n]); while (!s.empty()) { n = s.top(); s.pop(); cout<
<

 

 

用队列实现栈

 

设2 个队列为A和B,A用作入队/出队,B用作辅助。

队满:A满且B不为空;
队空:A和B都为空;
入栈:将新元素插入队列A;
出栈
(1) 除最后一个元素外,将队列A的元素全部插入到队列B;
(2) 将队列A的最后一个元素出队;

(3) 将队列B的元素换回到队列A;

 

void stack_pop(queue
&q1, queue
&q2, int &n){ int i, head; while (!q1.empty()) { head = q1.front(); q1.pop(); if (q1.empty()) { n = head; } else { q2.push(head); } } while (!q2.empty()) { head = q2.front(); q1.push(head); q2.pop(); }}int main(){ int n; int array[6] = {
1,2,3,4,5,6}; queue
q1, q2; for (n=0; n<6; n++) q1.push(array[n]); while (!q1.empty()) { stack_pop(q1, q2, n); cout<
<

 

转载地址:http://mucrl.baihongyu.com/

你可能感兴趣的文章
Uber自动驾驶在加州合法化,但旗下的Otto却陷入了法律争端
查看>>
E店宝ERP再推多包裹解决方案
查看>>
近几个月Github上最热门的Java项目一览
查看>>
Linux常见实用命令大全
查看>>
Android VideoView播放在线视频(2)
查看>>
Gradle添加依赖及使用注解(添加插件)
查看>>
Python3 与 NetCore 基础语法对比(List、Tuple、Dict、Set专栏)
查看>>
从零开始理解JAVA事件处理机制(1)
查看>>
如何在Java文件中创建以太坊帐户和通过web3j查询账目情况?
查看>>
寻找源代码
查看>>
如何挖出真正能打动用户的关键点呢?5个靠谱方法
查看>>
Java程序员必须掌握的常用Linux命令。
查看>>
基于Kali-Linu的一次渗透
查看>>
AR+营销,推广只是第一步,和AR购物联姻才是未来
查看>>
在创新中创新,在探索中探索 | 专访数据院教育指导委员会委员刘震
查看>>
JDBC实例代码
查看>>
MySQL 8.0窗口函数--row_number over..应用
查看>>
区块链是一种思维
查看>>
腾讯开源大规模 Node.js 微服务框架 Tars.js
查看>>
13-51单片机ESP8266学习-AT指令(ESP8266作为TCP客户端,连接TCP服务器,用串口调试助手和手机TCP调试助手测试)...
查看>>