一、问题描述
用两个顺序栈来模拟实现一个队列的入队和出队的运算操作
二、问题分析
首先,在开始用代码实现这个问题之前,让我们先分析一下这个问题中提到的数据结构中的两个常用的结构 栈和队列。
栈的定义和特点
栈的定义:
一种后进的元素需要先出, 后来的反而需要先服务的线性结构,就是一个访问受限的线性表。
栈的特点:栈内的元素:后进先出,先进后出
顺序栈的栈顶在尾部, 因为入栈和出栈的时间复杂度为O(1)
![](https://img-blog.csdnimg.cn/direct/17f29faef34446c59fed808b6df9ecd6.png)
队列的定义和特点
队列定义:
先进先出的一种线性结构, 入队(插入)的一端称为队尾, 出队(删除)的一端称为队头
队列特点:
队列的存储方式有两种, 一种为顺序结构(顺序队列), 两一种为链式结构(链式队列)
顺序队列一定会设计成环形队列, 原因是线性队列的入队为O(1),
出队为O(n), 而环形队列的入队为O(1), 出队为O(1)
浪费一个空间不使用, 主要是为了区分队空和队满的情况:
空是队头和队尾相同, 满是rear(队尾指针)再往后走一步为front(队头指针) (浪费一个空间)
![](https://img-blog.csdnimg.cn/direct/d3e92e18bcba4211953bd5dc734e3e4b.png)
三、程序设计
通过对问题描述以及分析的理解,我们就是用两个后进先出的线性结构来模拟一个先进先出的线性结构。
我们假设有两个顺序栈(栈:stack,简称为s)s1和s2。
第一步:
往栈s1中入元素来模拟入队的操作。
![](https://img-blog.csdnimg.cn/direct/5bbacf8198fe48d196ac755bc66f4c8f.png)
第二步:
再将s1中的栈顶元素保存,依次出栈,再入栈到栈s2中,s2中栈顶元素的出栈即为模拟出队操作。
再将s2中的元素出栈就可以模仿出队操作。
二次入队:
若想再次入队,只需将栈s2中的栈顶元素出栈,入栈到栈s1中,然后在栈s1中入元素,再次重复上述第二步操作即可。
程序优化:
我们把每次如对都当做二次入队,在每次模仿入队操作之前都进行一次上述二次入队的操作。
四、代码设计
程序代码:
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#define INIT_SIZE 10
typedef struct
{
int* base;//指向动态内存
int top;//栈顶指针,实际为下标
int stacksize;//栈的总大小
}Stack;
void InitStack(Stack* ps);
void Shift_s2_to_s1(Stack* s1, Stack* s2);
bool Push(Stack* ps, int val);
bool Pop(Stack* ps, int* rtval);
bool IsEmpty(Stack* ps);
//初始化
void InitStack(Stack *ps)
{
assert(ps != NULL);
if (ps == NULL)
return;
ps->base = (int*)malloc(INIT_SIZE * sizeof(int));
assert(ps->base != NULL);
ps->top = 0;
ps->stacksize = INIT_SIZE;
}
//将栈s2中的元素全部出栈,并且入栈到栈s1中(程序设计中的第二步)
void Shift_s2_to_s1(Stack *s1, Stack *s2)
{
assert(s1 != NULL);
assert(s2 != NULL);
if (s1 == NULL)
return;
if (s2 == NULL)
return;
int top;
while (!IsEmpty(s2))
{
Pop(s2, &top);//将栈s2的栈顶元素出栈,将其值保存在top中
}
}
//判满
static bool IsFull(Stack *ps)
{
return ps->top == ps->stacksize;
}
//扩容
static void Inc(Stack *ps)
{
ps->stacksize *= 2;
ps->base = (int*)realloc(ps->base, ps->stacksize * sizeof(int));
}
//往栈中入数据(入栈操作)
bool Push(Stack *ps, int val)
{
assert(ps != NULL);
if (ps == NULL)
return false;
if (IsFull(ps))
{
Inc(ps);
}
ps->base[ps->top++] = val;//后置++ <==> ps->top++
//ps->top++;
return true;
}
//获取栈顶元素的值,并且删除
bool Pop(Stack *ps, int* rtval)
{
assert(ps != NULL);
if (ps == NULL)
return false;
if (IsEmpty(ps))
return false;
*rtval = ps->base[--ps->top];
return true;
}
//判空
bool IsEmpty(Stack *ps)
{
assert(ps != NULL);
if (ps == NULL)
return false;
return ps->top == 0;
}
int main()
{
Stack s1;
Stack s2;
//初始化栈s1
InitStack(&s1);
//初始化栈s2
InitStack(&s2);
int s1_Top;//保存栈s1的栈顶元素
int s2_Top;//保存栈s2的栈顶元素
//入栈模仿入队操作
Shift_s2_to_s1(&s1, &s2);//先将栈s2中的元素出栈到栈s1中
for (int i = 1; i < 6; i++)
{
Push(&s1, i);//往栈s1中入元素
}
//入队
while (!IsEmpty(&s1))
{
Pop(&s1, &s1_Top); //将栈s1中的栈顶元素依次获取并删除
//模仿入队操作
Push(&s2, s1_Top);//通过入栈操作入进栈s2,类似于入队操作
}
//出队
printf("队列特点:先进先出\n入队顺序:1 2 3 4 5 \n预期出队结果:1 2 3 4 5\n");
while (!IsEmpty(&s2))
{
//模仿出队操作
Pop(&s2, &s2_Top);//将栈s2中的栈顶元素依次获取并且删除,类似于出队操作
printf(" %d ", s2_Top);//输出出队元素
}
printf("\n");
return 0;
}
程序运行结果:
![](https://img-blog.csdnimg.cn/direct/b564d93c6c184e26a7faf6cbfefdc73c.png)