定义
使用队列实现栈的下列操作:
push(x) – 元素 x 入栈
pop() – 移除栈顶元素
top() – 获取栈顶元素
empty() – 返回栈是否为空
用队列如果来模拟战:
还是需要二个队列使用。
入栈操作思路::
情况1:两个队列
都为空那就随便哪一个队列将元素入队列即可,也就相当于入栈操作,如下图(虚线表示模拟一个栈)
情况2:其中一个队列有元素,一个队列没有元素,则将元素插入到有元素的队列中,如下图,此时待入栈的c和d要插入到队列1中
这是入栈的思路,出栈时候:
出栈操作思路::
如图所示,此时队列1 当中有元素
但是由于队列只能从队首将元素出队列,而我们入栈的元素顺序是a b c d,所以根据栈后进先出的特点,此时出栈的元素应该是d,所以我们要将队列1 中的元素移动到一个空队列中也就是队列2,但是我们必须留下队列1中的队尾的最后一个元素,只剩下最后一个元素时,将这个元素出队列,就刚好模拟了栈的出栈操作。
- 就是说此时入栈成功后队列1是dcba,按照栈的思路是先进后出,应该是dcba,d先出
- 所以按照队列1出去是abc,再入队到队列2,是cba,队列1此时剩一个元素,出队列,模拟了栈的出栈操作
代码实现
结构定义
#include <stdlib.h>
#include <stdio.h>
#define max_size 1000
typedef char DataType;
typedef struct Queue
{
DataType data[max_size];
int head;
int tail;
//队列中有效元素个数
int size;
}Queue;
typedef struct Stack
{
Queue queue1; //作为主队列
Queue queue2; //用来反转的队列
//栈中有效元素个数
int size;
}Stack;
初始化
//队列初始化函数
void QueueInit(Queue *queue)
{
if(queue == NULL)
{
//非法输入
return;
}
queue->head = 0;
queue->tail = 0;
queue->size = 0;
}
入队操作
//入队列操作函数
void QueuePush(Queue *queue,DataType value)
{
if(queue == NULL)
{
//非法输入
return;
}
if(queue->size >= max_size)
{
//队列满了
return;
}
queue->data[queue->tail++] = value; //从队尾入队
queue->size++;
if(queue->tail > max_size)
{
//如果tail走到了队列的尾部
queue->tail = 0;
}
}
出队操作
//出队列操作函数
void QueuePop(Queue *queue)
{
if(queue == NULL)
{
//非法输入
return;
}
if(queue->size == 0)
{
//空队列
return;
}
if(queue->head >= max_size)
{
//如果head走到了队列的最后一个元素
//呢出队列以后继续回到队列一开始的地方
//就相当于是将最后一个元素出对队列
queue->head = 0;
}
//否则直接将head往后移动一步
queue->head++;
//将对列元素个数-1
queue->size--;
if(queue->size == 0)
{
queue->head = 0;
queue->tail = 0;
}
}
取队首元素
//取队首元素函数
int QueueGetTop(Queue *queue,DataType *value)
{
if(queue == NULL)
{
//非法输入
return 0;
}
if(queue->size == 0)
{
//空队列
return 0;
}
*value = queue->data[queue->head];
return 1;
}
打印队列
void Print(Queue *queue)
{
if(queue == NULL)
{
//非法输入
return;
}
if(queue->size == 0)
{
return;
}
if(queue->head < queue->tail)
{
int i = queue->head;
for(;i < queue->tail;i++)
{
printf("%c ",queue->data[i]);
}
}
else
{
int i = queue->head;
while(queue->head < max_size)
{
printf("%c ",queue->data[queue->head]);
queue->head++;
}
queue->head = 0;
for(;i < queue->tail;i++)
{
printf("%c ",queue->data[i]);
}
}
printf("\n\n");
}
上面实现的是队列的基本操作,下面实现模拟栈的操作区
栈结构初始化
//栈初始化函数
void StackInit(Stack *stack)
{
if(stack == NULL)
{
//非法输入
return;
}
QueueInit(&stack->queue1);
QueueInit(&stack->queue2);
stack->size = 0;
}
入栈操作
无元素随便入队,有元素插入有元素的队列
//入栈操作函数
void StackPush(Stack *stack,DataType value)
{
if(stack == NULL)
{
//非法输入
return;
}
//每次入栈时找到队列不为空的那一个队列入队列(相当于入栈)
//或者两个栈都为空时随便入哪一个队列都行
if(stack->queue1.size != 0)
{
//队列1不为空
QueuePush(&stack->queue1,value);
}
else
{
//队列2不为空或者两个队列都为空
QueuePush(&stack->queue2,value);
}
//每入栈一个元素将栈的有效元素个数+1
stack->size++;
}
出栈操作
把元素从队列中只剩一个,其他的导入到另外一个队列中
//出栈操作函数
void StackPop(Stack *stack)
{
if(stack == NULL)
{
//非法输入
return;
}
if(stack->size == 0)
{
//空栈
return;
}
Queue *from = NULL;
Queue *to = NULL;
//将from指向有元素的队列,to指向没有元素的队列
if(stack->queue1.size != 0)
{
from = &stack->queue1;
to = &stack->queue2;
}
else
{
from = &stack->queue2;
to = &stack->queue1;
}
//将from中的元素到腾到to中(但是from中必须要留下最后一个元素用于最后的出队列也就是出栈操作)
while(from->size != 1)
{
DataType top;
//取到from队列队首元素的值
QueueGetTop(from,&top);
//然后对from队列进行一次出栈操作
QueuePop(from);
//将从from队列取到的队首元素值插入到to队列中
QueuePush(to,top);
}
//循环结束
//此时from中就剩下最后一个元素将其出队列也就完成出栈操作
QueuePop(from);
//每出栈一次就将栈的有效元素个数-1
stack->size--;
}
取栈顶元素
取栈顶元素思路: 取栈顶元素操作和出栈操作类似,唯一不同的就是,当我们将元素移动到只剩下最后一个元素的时候,我们需要的是读取到该元素的值(取队首元素操作就行了),而这个元素依旧存在于该栈中,所以为了确保栈的元素不被破坏,读取完元素值以后我们依旧要把该元素移动到另外那个队列中去。
- 跟出栈操作类似,但是读取完元素值后不出栈,还是要移动到另一个队列去
//取栈顶元素函数
int StackGetTop(Stack *stack,DataType *value)
{
if(stack == NULL || value == NULL)
{
//非法输入
return 0;
}
if(stack->size == 0)
{
//空栈
return 0;
}
Queue *from = NULL;
Queue *to = NULL;
//将from指向有元素的队列,to指向没有元素的队列
if(stack->queue1.size != 0)
{
from = &stack->queue1;
to = &stack->queue2;
}
else
{
from = &stack->queue2;
to = &stack->queue1;
}
//将from中的元素到腾到to中(但是from中必须要留下最后一个元素用于最后的取队首元素操作也就是取栈顶元素操作)
while(from->size != 1)
{
DataType top;
//取到from队列队首元素的值
QueueGetTop(from,&top);
//然后对from队列进行一次出栈操作
QueuePop(from);
//将从from队列取到的队首元素值插入到to队列中
QueuePush(to,top);
}
//循环结束
//此时from中就剩下最后一个元素
//对from队列取队首元素操作(也就是取栈顶元素)
int ret = QueueGetTop(from,value);
//当我们取到栈顶元素之后,在将该元素从from队列出队列
QueuePop(from);
//并且将该元素入to队列
//否则栈就被破坏了
QueuePush(to,*value);
return ret;
}
打印栈元素
//打印函数便于观察测试结果
void PrintStackElem(Stack *stack,const char *msg)
{
printf("[%s]\n",msg);
if(stack == NULL)
{
//非法输入
return;
}
if(stack->size == 0)
{
//空栈
return;
}
Queue *print = NULL; //新建一个队列print
if(stack->queue1.size == 0) //如果队列1元素为0个
{
print = &stack->queue2; //print=queue2
}
else
{
print = &stack->queue1; //pirnt=queue1
}
Print(print); //打印出来
}
测试主函数
//以下为测试函数
void TestStackBy2Queue()
{
printf("\n==========%s==========\n",__FUNCTION__);
Stack stack;
//初始化
StackInit(&stack);
//入栈函数测试
StackPush(&stack,'a');
StackPush(&stack,'b');
StackPush(&stack,'c');
StackPush(&stack,'d');
PrintStackElem(&stack,"入栈4个元素expected:a b c d");
//取栈顶元素测试
DataType top;
int ret = StackGetTop(&stack,&top);
printf("expected ret = 1,actual ret = %d\n",ret);
printf("expected top = d,actual top = %c\n",top);
//出栈函数测试
StackPop(&stack);
StackPop(&stack);
PrintStackElem(&stack,"出栈两个元素之后expected: a b");
//取栈顶元素函数测试2
ret = StackGetTop(&stack,&top);
printf("expected ret = 1,actual ret = %d\n",ret);
printf("expected top = b,actual top = %c\n",top);
StackPop(&stack);
StackPop(&stack);
PrintStackElem(&stack,"将剩下的两个元素出栈之后expected:");
//取栈顶元素函数测试3
ret = StackGetTop(&stack,&top);
printf("expected ret = 0,actual ret = %d\n",ret);
//销毁栈
StackDestroy(&stack);
}
//主函数调用测试函数
int main()
{
TestStackBy2Queue();
return 0;
}