前言
学会了队列和栈,我们可以再了解一下如何将数据结构进行相互转换。
1. 用队列实现栈
思路:我们知道,队列先进先出,而栈后进先出。我们可以将一个队列进行存储数据,当pop时,将这个队列的除了最后一个数据,其余的全传到另一个队列里面,如何将最后一个数据pop掉,这个队列变成空队列。再pop的话,将这个不为空的队列除了最后一个数据,全部传到另一个队列中,再pop掉最后数据。
如图:
当push时,向不为空的列表中插入数据即可。
当获取栈顶数据时,看似可以像pop一样,但实则不同。因为当取了栈顶元素却不pop掉时,则会产生pop时找不到空队列进行插入,而产生报错。所以我们可以改为取不为空队列的尾数据。
判断栈是否为空需要判断两个队列是否为空,只要有一个不为空,则不为空。
销毁时需要销毁两个队列以及结构体,free结构体和队列并置为空。
具体代码如下:
typedef struct {
qu q1;
qu q2;
} MyStack;
MyStack* myStackCreate() {
MyStack * pst = (MyStack * )malloc(sizeof(MyStack)) ;
quinit(&pst->q1);
quinit(&pst->q2);
return pst;
}
void myStackPush(MyStack* obj, int x) {
if(queueempty(&obj->q1))
//往不为空的列表中插入新数据
{
qupush(&obj->q1,x);
}
else
{
qupush(&obj->q2,x);
}
}
//出栈
int myStackPop(MyStack* obj) {
qu * emptyqu = &obj->q1;
qu * nonequ = &obj->q2;
if(queueempty(&obj->q1))
{
emptyqu = &obj->q2;
nonequ = &obj->q1;
}
while(queuesize(nonequ)>1)
{
queuedatatype front = qugetfront(nonequ);
qupop(nonequ);
qupush(emptyqu,front);
}
queuedatatype pop = qugetfront(nonequ);
qupop(nonequ);
return pop;
}
int myStackTop(MyStack* obj) {
if(queueempty(&obj->q1))
{
return qugetback(&obj->q1);
}
else
{
return qugetback(&obj->q2);
}
}
bool myStackEmpty(MyStack* obj) {
return !queueempty(&obj->q1)&&!queueempty(&obj->q2);
}
void myStackFree(MyStack* obj) {
queuedetroy(&obj->q1);
queuedetroy(&obj->q2);
free(obj);
obj = NULL;
}
2. 用栈实现队列
思路:栈是先入后出,而队列是先入先出。我们直接将一个栈作为push栈,再将一个栈作为pop栈,将push栈的数据传到pop栈,就实现了队列。
当pop时,判断是否pop栈为空,为空则将push栈的数据全部传过来,然后进行pop,不为空则直接进行pop。
当push时,传数据到push栈即可。
传开头元素即pop一样的操作,只是不进行最后的pop。
判断为空即判断两个栈是否为空,两个为空都为空才为空。
代码如下:
typedef struct {
ST push;
ST pop;
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue * qst = (MyQueue * )malloc(sizeof(MyQueue));
stinit(&qst->push);
stinit(&qst->pop);
return qst;
}
void myQueuePush(MyQueue* obj, int x) {
//在push栈中插入数据
stpush(&obj->push,x);
//将pop栈插入数据
}
int myQueuePop(MyQueue* obj) {
//&obj->push->top-- int*
if(stackempty(&obj->pop))
{
while(!stackempty(&obj->push))
{
stpush(&obj->pop, gettop(&obj->push));
stpop(&obj->push);
}
}
int x = gettop(&obj->pop);
stpop(&obj->pop);
return x;
}
int myQueuePeek(MyQueue* obj) {
if(stackempty(&obj->pop))
{
while(!stackempty(&obj->push))
{
stpush(&obj->pop, gettop(&obj->push));
stpop(&obj->push);
}
}
int x = gettop(&obj->pop);
return x;
}
bool myQueueEmpty(MyQueue* obj) {
return stackempty(&obj->pop)&&stackempty(&obj->push);
}
void myQueueFree(MyQueue* obj) {
stdestroy(&obj->push);
stdestroy(&obj->pop);
free(obj);
obj =NULL;
}
3. 循环队列的实现
循环队列的底层结构是数组,因为容量有限,且删除插入的时候不需要结点的释放以及指针的使用。
判断一下简单的问题:如何判断队满和队空,rear==front好像两个都可以判断。那我们设计一个判断队满新的思路:rear+1==front。这里我们设计一个比实际存储空间大一个的空间,多的一格用来存放rear。即当rear+1循环到front时,则是队满。因为有循环,所以rear+1也需要进行求余,即(rear+1)%(capacity+1)==front。
这些问题解决后,就可以解决其他的问题。
插入:先判断队满,队满则false,不满则插入,然后rear++。
删除:先判断队空,队空则报错,不空则直接front++。
取头元素:先判断是否为空,为空则false,不为空则返回位置为front的值。
取尾元素:先判断是否为空,为空则false,不为空则返回位置为rear-1的值。如果rear==0的话,则rear就是capacity。
代码如下:
typedef struct {
int * arr;
int front ;
int rear ;
int capacity ;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* circlequeue = (MyCircularQueue * ) malloc(sizeof(MyCircularQueue));
circlequeue->arr = (int * )malloc(sizeof(int)*(k+1));
circlequeue->capacity = k;
circlequeue->front = 0;
circlequeue->rear = 0;
return circlequeue;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if((obj->rear+1)%(obj->capacity+1)==obj->front)
{
return false;
}
else
{
obj->arr[obj->rear++]=value;
obj->rear%=(obj->capacity+1);
return true;
}
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if(obj->rear ==obj->front)
{
return false;
}
else
{
obj->front++;
obj->front %= (obj->capacity+1);
return true;
}
}
int myCircularQueueFront(MyCircularQueue* obj) {
if(obj->rear ==obj->front)
return -1;
else
{
return obj->arr[obj->front];
}
}
int myCircularQueueRear(MyCircularQueue* obj) {
if(obj->rear ==obj->front)
return -1;
int prev = obj->rear-1;
if(obj->rear==0)
{
prev = obj->capacity;
}
return obj->arr[prev];
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return (obj->rear ==obj->front);
}
bool myCircularQueueIsFull(MyCircularQueue* obj)
{
return ((obj->rear+1)%(obj->capacity+1)==obj->front);
}
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->arr);
free(obj);
obj=NULL;
}
4. 源码
用栈实现队列 · 6e79861 · 重邮阿江/c_study_experience - Gitee.com
循环队列的实现 · edbb195 · 重邮阿江/c_study_experience - Gitee.com用两个队列实现栈 · 9c03e08 · 重邮阿江/c_study_experience - Gitee.com