算法入门经典之栈和队列篇

做对的事情比把事情做对重要

/**
*@author StormMaybin
*@Date 2016-07-17
*/

最近一段时间会对数据结构的知识和算法基础进行总结,尽量一天一更!如果时间错不开的话,第二天会补上。

数据结构中,栈和队列是最基础的也是简单的,一种是先进后出的线性数据结构,另外一种是先进先出的线性数据结构!


案例一:卡片游戏(队列)

  1. 题目说明:假设桌上有一叠扑克牌,依次编号为1-n(从最上面开始)。当至少还有两张的时候,可以进行操作:把第一张牌扔掉,然后把新的第一张放到整叠牌的最后。输入n,输出每次要扔掉的牌,以及最后剩下的牌。
  2. 样例输入:7
    样例输出:1 3 5 7 4 2 6
  3. 分析:先开始是扔掉1,然后把2排到最后,然后扔掉3,把4排到最后······,我们会很自然的想到队列,就像排队一样,银行柜台前,第一个人先排的队,然后第一个人办完事之后第一个走······

代码实现1:
# include <stdio.h>
const int MAXN = 50;
int queue[MAXN] = {0};
int main (void)
{
    int n, front, rear;
    scanf ("%d",&n);
    for (int i = 0; i < n; i++)
    {
        queue[i] = i + 1;
    }
    front = 0;
    rear = n;
    while (front < rear)
    {
        printf ("%d ", queue[front++]);
        queue[rear++] = queue[front++];
    } 
    return 0;
} 

运行结果:
这里写图片描述
单看这个程序的输出结果,没有任何错误,答案就是我们想要的,现在让我们看看rear的值到最后是多大?
这里写图片描述
rear 的值是14,恰好是7的2倍,这么看的话,每次数组要开到2n,这就极大的浪费了内存空间。


让我们用c++的STL队列来解决这个问题。

代码实现2:
# include <cstdio>
# include <queue>
using namespace std;

queue <int> q;
int main (void)
{
    int n;
    scanf ("%d", &n);
    for (int i = 0; i < n; i++)
    {
        //初始化队列 
        q.push(i+1);
    }
    while (! q.empty())
    {
        //打印队首元素 
        printf ("%d ", q.front());
        //抛弃首元素 
        q.pop();
        //把队首元素加到队尾 
        q.push(q.front());
        //抛弃队首元素 
        q.pop();
    }
    return 0;
}

代码依旧简单,可读性也增强了不少!对于c++的STL库,不了解的可以去查查资料。



案例二:铁轨(栈)

  1. 假设有一个火车站,有n节车厢标记为1-n;现在要按照某种特定的顺序进入B铁轨驶出车站,为了重组车厢的顺序,你现在有一个中转站C(station),在中转站C里面,你可以停放任意数量的车厢,但是有一个规则就是:C的末端是封顶的,驶入C的车厢必须按照相反的顺序驶出中转站C,一旦从A->C,你就不能退回到A,同理C->B!
    这里写图片描述
  2. 样例输入:5
    1 2 3 4 5
    5
    5 4 1 2 3
    6
    6 5 4 3 2 1
    样例输出:
    Yes
    No
    Yes
  3. 分析:中转站C的规则其实就是栈这个数据结果的特点!

    代码实现1:
/**
*@author StormMaybin
*@Date 2016-07-17 
*/
# include <stdio.h>
const int MAXN = 1000 + 10;
int n, target[MAXN];

int main (void)
{
    while (scanf("%d",&n) == 1)
    {
        int stack[MAXN];
        int top = 0;
        int A = 1;
        int B = 1;
        for (int i = 1; i <= n; i++)
        {
            scanf ("%d", &target[i]);
        }
        int ok = 1;
        while (B <= n)
        {
            if (A == target[B])
            {
                A++;
                B++;
            }
            else if (top && stack[top] == target[B])
            {
                top--;
                B++;
            }
            else if (A <= n)
            {
                stack[++top] = A++;
            }
            else
            {
                ok = 0;
                break;
            }
        }
        printf ("%s\n",ok ? "Yes" : "No");
    }
    return 0;
} 

打印结果
这里写图片描述
代码原理也很简单,输出结果是Yes只有两种情况,一种是正序,一种就是逆序!

代码实现2:

接着,用c++STL库来写:

/**
*@author StormMaybin
*@Date 2016-07-17 
*/
# include <cstdio>
# include <stack>
using namespace std;
const int MAXN = 1000 + 10;

int n;
int target [MAXN];

int main (void)
{
    while (scanf ("%d",&n) == 1)
    {
        stack<int> s;
        int A = 1;
        int B = 1;
        for (int i = 1; i <= n; i++)
        {
            scanf ("%d", &target[i]);
        }
        int ok = 1;
        while (B <= n)
        {
            if (A == target[B])
            {
                A++;
                B++;
            }
            else if (! s.empty() && s.top() == target[B])
            {
                s.pop();
                B++;
            }
            else if (A <= n)
            {
                s.push(A++);
            }
            else
            {
                ok = 0;
                break;
            }
        }
        printf("%s\n", ok ? "Yes" : "No");
    }
    return 0;
}
  • 0
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值