栈结构的经典算法题

栈结构

颠倒一个栈的元素顺序

问题:假设有一个栈{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<int> &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<int> &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<int> s;

    for (n=0; n<6; n++) s.push(array[n]);

    Reverse(s);

    while (!s.empty()) {

        cout<<s.top()<<endl;
        s.pop();

    }   

}

栈的push、pop序列

用栈实现队列

设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<int> &s1, stack<int> &s2)
{
    return s1.empty() && s2.empty();
}

void enqueue(stack<int> &s1, stack<int> &s2, int val)
{
    s1.push(val);
}

void dequeue(stack<int> &s1, stack<int> &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"<<endl;
    }
}

int main()
{

    int n;
    int array[6] = {1,2,3,4,5,6};

    stack<int> s1;
    stack<int> s2; 

    for (n=0; n<6; n++) enqueue(s1, s2, array[n]);

    while (!queue_empty(s1, s2)) {

        dequeue(s1, s2, n);
        cout<<n<<endl;
    }

}

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

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

代码如下:

void enqueue2(stack<int> &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<int> s;

    for (n=0; n<6; n++) enqueue2(s, array[n]); 

    while (!s.empty()) {

        n = s.top();
        s.pop();
        cout<<n<<endl;
    }
}

用队列实现栈

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

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

void stack_pop(queue<int> &q1, queue<int> &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<int> q1, q2;

    for (n=0; n<6; n++) q1.push(array[n]);

    while (!q1.empty()) {
        stack_pop(q1, q2, n);
        cout<<n<<endl;
    }
}
时间: 2024-10-07 17:19:42

栈结构的经典算法题的相关文章

经典算法题每日演练——第十九题 双端队列

原文:经典算法题每日演练--第十九题 双端队列 话说大学的时候老师说妹子比工作重要~,工作可以再换,妹子这个...所以...这两个月也就一直忙着Fall in love,嗨,慢慢调整心态吧, 这篇就选一个简单的数据结构聊一聊,话说有很多数据结构都在玩组合拳,比如说:块状链表,块状数组,当然还有本篇的双端队列,是的,它就是 栈和队列的组合体. 一:概念 我们知道普通队列是限制级的一端进,另一端出的FIFO形式,栈是一端进出的LIFO形式,而双端队列就没有这样的限制级,也就是我们可以在 队列两端进行

经典算法题每日演练——第三题 猴子吃桃

原文:经典算法题每日演练--第三题 猴子吃桃 猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾就多吃了一个.第二天早上又将剩下的桃子吃了一半,还是不过瘾又多 吃了一个.以后每天都吃前一天剩下的一半再加一个.到第10天刚好剩一个.问猴子第一天摘了多少个桃子? 分析: 这是一套非常经典的算法题,这个题目体现了算法思想中的递推思想,递归有两种形式,顺推和逆推,针对递推,只要 我们找到递推公式,问题就迎刃而解了. 令S10=1,容易看出 S9=2(S10+1), 简化一下 S9=2S10+2 S8=2S

经典算法题每日演练——第九题 优先队列

原文:经典算法题每日演练--第九题 优先队列 前端时间玩小爬虫的时候,我把url都是放在内存队列里面的,有时我们在抓取url的时候,通过LCS之类的相似度比较,发现某些url是很重要的, 需要后端解析服务器优先处理,针对这种优先级比较大的url,普通的队列还是苦逼的在做FIFO操作,现在我们的需求就是优先级大的优先服务,要做 优先队列,非堆莫属. 一:堆结构 1:性质 堆是一种很松散的序结构树,只保存了父节点和孩子节点的大小关系,并不规定左右孩子的大小,不像排序树那样严格,又因为堆是一种完全二叉

经典算法题每日演练——第二十五题 块状链表

原文:经典算法题每日演练--第二十五题 块状链表 在数据结构的世界里,我们会认识各种各样的数据结构,每一种数据结构都能解决相应领域的问题,每一种数据结构都像 是降龙十八掌中的某一掌,掌掌毙命... 当然每个数据结构,有他的优点,必然就有它的缺点,那么如何创造一种数据结构 来将某两种数据结构进行扬长避短,那就非常完美了.这样的数据结构也有很多,比如:双端队列,还有就是今天讲的 块状链表, 我们都知道 数组 具有 O(1)的查询时间,O(N)的删除,O(N)的插入... 链表 具有 O(N)的查询时

经典算法题每日演练——第十六题 Kruskal算法

原文:经典算法题每日演练--第十六题 Kruskal算法 这篇我们看看第二种生成树的Kruskal算法,这个算法的魅力在于我们可以打一下算法和数据结构的组合拳,很有意思的. 一:思想 若存在M={0,1,2,3,4,5}这样6个节点,我们知道Prim算法构建生成树是从”顶点”这个角度来思考的,然后采用“贪心思想” 来一步步扩大化,最后形成整体最优解,而Kruskal算法有点意思,它是站在”边“这个角度在思考的,首先我有两个集合. 1. 顶点集合(vertexs): 比如M集合中的每个元素都可以认

经典算法题每日演练——第二十题 三元组

原文:经典算法题每日演练--第二十题 三元组 我们知道矩阵是一个非常强大的数据结构,在动态规划以及各种图论算法上都有广泛的应用,当然矩阵有着不足的地方就是空间和时间 复杂度都维持在N2上,比如1w个数字建立一个矩阵,在内存中会占用1w*1w=1亿的类型空间,这时就会遇到outofmemory...那么面 临的一个问题就是如何来压缩矩阵,当然压缩的方式有很多种,这里就介绍一个顺序表的压缩方式:三元组. 一:三元组 有时候我们的矩阵中只有零星的一些非零元素,其余的都是零元素,那么我们称之为稀疏矩阵,

经典算法题每日演练——第二十四题 梳排序

原文:经典算法题每日演练--第二十四题 梳排序 这篇再看看一个经典的排序,梳排序,为什么取名为梳,可能每个梳都有自己的gap吧,大梳子gap大一点,小梳子gap小一点. 上一篇我们看到鸡尾酒排序是在冒泡排序上做了一些优化,将单向的比较变成了双向,同样这里的梳排序也是在冒泡排序上做了一些优化. 冒泡排序上我们的选择是相邻的两个数做比较,就是他们的gap为1,其实梳排序提出了不同的观点,如果将这里的gap设置为一定的大小, 效率反而必gap=1要高效的多. 下面我们看看具体思想,梳排序有这样一个1.

经典算法题每日演练——第十七题 Dijkstra算法

原文:经典算法题每日演练--第十七题 Dijkstra算法 或许在生活中,经常会碰到针对某一个问题,在众多的限制条件下,如何去寻找一个最优解?可能大家想到了很多诸如“线性规划”,“动态规划” 这些经典策略,当然有的问题我们可以用贪心来寻求整体最优解,在图论中一个典型的贪心法求最优解的例子就莫过于“最短路径”的问题. 一:概序 从下图中我要寻找V0到V3的最短路径,你会发现通往他们的两点路径有很多:V0->V4->V3,V0->V1->V3,当然你会认为前者是你要找的最短 路径,那如

经典算法题每日演练——第七题 KMP算法

原文:经典算法题每日演练--第七题 KMP算法 在大学的时候,应该在数据结构里面都看过kmp算法吧,不知道有多少老师对该算法是一笔带过的,至少我们以前是的, 确实kmp算法还是有点饶人的,如果说红黑树是变态级的,那么kmp算法比红黑树还要变态,很抱歉,每次打kmp的时候,输 入法总是提示“看毛片”三个字,嘿嘿,就叫“看毛片算法”吧. 一:BF算法 如果让你写字符串的模式匹配,你可能会很快的写出朴素的bf算法,至少问题是解决了,我想大家很清楚的知道它的时间复 杂度为O(MN),原因很简单,主串和模