菜鸟成长记录【1】使用两个栈实现一个队列

工欲善其事,必先利其器,先温习一下基础。

1、什么是栈:

        栈,存储货物或供旅客住宿的地方,可引申为仓库、中转站,所以引入到计算机领域里,就是指数据暂时存储的地方,所以才有进栈、出栈的说法。

2、栈的特点:

栈的特点是先进后出,进出元素都是在同一端(栈顶)。

2.1 入栈

 2.2出栈

        我们可以把栈的操作想象成蒸包子的过程,在没有放包子时最上面的那层和最下面那层都是处在同一层,这也就是栈空的特点;当需要蒸包子时,总会把它一层一层的堆起来,而最先放上去的总会再最后才能被拿下来,并且每次都只能往最上面那层放;同样往下取的时候也是只能从最上层取。

综上可以知道栈是先入后出,且只能对栈顶操作。

3、队列

就像我们排队买东西时,先去排的先买到。(了解是先入先出的特点就行)

4、用栈实现队列操作

栈是先入后出而队列是先入先出,显然要实现一个队列至少要两个栈。

  1. 将数据全部存储完后再全部取出

 

 由上图可见将一组数据经过入栈出栈两次后就实现了一个队列

        2. 多次存储与多次取出

上面虽然已经实现了一个队列,但并不能像队列那样能存储多个数据而仅读取少量数据。

设想一下,加入我存了几个数据后想读取部分,后再存储数据再全部读取出来,上面的方法已然难以实现,而要实现它仅仅需要加上一点注意事项罢了。

 

 

那么问题来了,我们后面再读取数据的时候如果再按之前的路子来,读到的将会是5而不是2,这样就像有人插队那样不礼貌了。

那么如果我们设置这样一个条件就可以解决:在每次需要读取数据的时候优先判断栈2内是不是还有数据没有读完,如果有就直接读栈二内的数据,如果没有的话就一次把栈1内所有数据出栈到栈2中,然后再读数据。 嗯~ 很有效

5、代码实现

先贴上封装好的入栈出栈子函数

/*
 * 功能:向栈内加入数据
 * 参数:
 *      @1:栈的地址
 *      @2:入栈数据
 * 返回值:成功返回OK,失败返回原因
 */
int enterStack(Stack *pStack,data_type item)
{
        if(NULL == pStack)
                return NULL_ERROR;

        //判断是否栈满 
        if(pStack->top == N-1)
                return FULL;

        //入栈
        pStack->top++;
        pStack->arr[pStack->top] = item;

        return OK;
}


/*
 * 功能:出栈
 * 参数:
 *      @1:栈的地址
 *      @2:出栈的数据
 * 返回值:成功返回OK,失败返回原因
 */
int outStack(Stack *pStack,data_type *item)
{
        if(NULL == pStack)
                return NULL_ERROR;

        //判断是否栈空
        if(pStack->top == -1)
                return EMPTY;

        //出栈
        *item = pStack->arr[pStack->top];
        pStack->top--;

        return OK;
}

5.1 一次性的存储与读取

int main()
{
        //待操作数据
        data_type data[5] = {1,2,3,4,5};
        data_type temp = 0;

        //创建第一个栈
        Stack *first = create();
        //创建第二个栈
        Stack *second = create();

        int i = 0;
        //先将数据全部入栈1
        while(OK == enterStack(first, data[i++]));

        //将栈1内所有数据出栈到栈2
        while(OK == outStack(first, &temp))
        {
                if(OK != enterStack(second, temp))
                {
                        break;
                }
        }

        //最后将栈2内所有数据出栈并打印看结果
        while(OK == outStack(second, &temp))
        {
                printf("%d  ",temp);
        }
        puts("");

        return 0;
}

结果如下:

完全符合队列的先入先出

5.2 多次或单次操作

 数据的存储还是没变,但是读取改了个子函数

/*
 * 功能:出队
 * 参数:
 *      @1:第一个栈的地址
 *      @2:第二个栈的地址
 *      @3:出栈的数据被存储地址
 * 返回值:成功返回OK,失败返回原因
 */
int outQueue(Stack *first,Stack *second,data_type *item)
{
        if(NULL == first || NULL == second)
                return NULL_ERROR;

        data_type temp = 0;

        //判断第二个栈是否为空
        if(-1 == second->top)
        {
                //第二个栈空时把第一个栈内所有存储数据导入第二个栈
                while(1)
                {
                        if(outStack(first,&temp) != OK)
                                break;
                        if(enterStack(second,temp) != OK)
                                break;
                }
        }

        if(outStack(second,item) != OK)
                return ERROR;

        return OK;
}

主函数实现

int main()
{
        data_type item = 0;
        int op = 0;
        Stack *first = create();
        Stack *second = create();
        while(1)
        {
                menu();
                scanf("%d",&op);
                if(0 == op)
                        break;
                switch(op)
                {
                        case 1:
                                printf("请输入要入队的数据:\n");
                                scanf("%d",&item);
                                if(OK != enterStack(first,item))
                                {
                                        printf("入队失败\n");
                                }
                                break;
                        case 2:
                                if(outQueue(first,second,&item) != OK)
                                {
                                        printf("出队失败\n");
                                        break;
                                }
                                printf("出队数据为:%d\n",item);
                                break;
                        case 3:
                                destroy(&first);
                                destroy(&second);
                                break;
                }
        }
        return 0;
}

以上若出现问题欢迎各位大佬指出。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值