1.栈实现队列
用栈实现队列也就是使用栈来实现先进先出的效果,该操作用一个栈是无法完成的,我们考虑用两个栈,栈a用来模拟入队操作,栈b来模拟出队操作。例如以下把1,2,3,4入队(入栈),现在要做的是实现出栈顺序为1,2,3,4。
需要模拟出队操作时只需要把栈a导到栈b中,然后在进行出栈就行,即出栈顺序就成了1,2,3,4而不是4,3,2,1,那么我们考虑把元素保持在栈b中,需要入队(入栈)的时候在把它导到栈a中,入完后再导回来。 这样就能实现先进先出的效果。
c语言代码演示 :
typedef int STDataType;
typedef struct Stack
{
STDataType* _a; //栈空间
int _top; // 栈顶
int _capacity; // 容量
}Stack;
void StackInit(Stack* ps)//初始化栈
{
assert(ps);
ps->_a = NULL;
ps->_top = ps->_capacity = 0;
}
void StackPush(Stack* ps, STDataType data)//入栈
{
assert(ps);
if (ps->_top == ps->_capacity)
{
int dt = ps->_capacity == 0 ? 4 : ps->_capacity * 2;
STDataType* pnew = (STDataType*)realloc(ps->_a, sizeof(STDataType) * dt);
assert(pnew);
ps->_a = pnew;
ps->_capacity = dt;
}
ps->_a[ps->_top] = data;
ps->_top++;
}
void StackPop(Stack* ps)//出栈
{
assert(ps);
assert(ps->_top);
ps->_top--;
}
STDataType StackTop(Stack* ps)//获取栈顶元素
{
assert(ps);
assert(ps->_top);
return ps->_a[ps->_top-1];
}
int StackSize(Stack* ps)//获取栈中有效元素个数
{
assert(ps);
return ps->_top;
}
int StackEmpty(Stack* ps)//检测栈是否为空,如果为空返回非零结果,如果不为空返回0
{
assert(ps);
return ps->_top == 0 ? 1 : 0;
}
void StackDestroy(Stack* ps)//销毁栈
{
assert(ps);
free(ps->_a);
ps->_a = NULL;
ps->_top = ps->_capacity = 0;
}
///
typedef struct {
Stack* p1;
Stack* p2;
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue* prt=(MyQueue*)malloc(sizeof(MyQueue));
prt->p1=(Stack*)malloc(sizeof(Stack));
prt->p2=(Stack*)malloc(sizeof(Stack));
StackInit(prt->p1);
StackInit(prt->p2);
return prt;
}
void myQueuePush(MyQueue* obj, int x) {
while(!StackEmpty(obj->p2))
{
StackPush(obj->p1,StackTop(obj->p2));
StackPop(obj->p2);
}
StackPush(obj->p1,x);
while(!StackEmpty(obj->p1))
{
StackPush(obj->p2,StackTop(obj->p1));
StackPop(obj->p1);
}
}
int myQueuePop(MyQueue* obj) {
int ret=StackTop(obj->p2);
StackPop(obj->p2);
return ret;
}
int myQueuePeek(MyQueue* obj) {
return StackTop(obj->p2);
}
bool myQueueEmpty(MyQueue* obj) {
return StackEmpty(obj->p1)&&StackEmpty(obj->p2);
}
void myQueueFree(MyQueue* obj) {
StackDestroy(obj->p1);
StackDestroy(obj->p2);
free(obj);
}
2.队列实现栈
如果要用队列实现栈的话,使用一个队列是肯定不行的,队列结构是先进先出,栈结构是先进后出,所以我们要做的就是使用两个队列实现元素的先进后出的功能,要实现出栈操作我们只要,把左边栈的元素逐个导入右边队列中,直到剩下最后一个,再将它取出相当于出队操作。
此操作以后就会有一个队列空,在入栈操作的话我们需要把元素入到队列不为空的空间中, 要时刻保持有一个队列为空,让它用来做出栈的前几个元素的一个载体。也就是说每次入栈和出栈的时候都需要判断一下那个队列为空,那个不为空,再进行相应操作。
c语言代码演示 :
#define QueueData int
typedef struct QueueNode
{
QueueData val;
struct QueueNode* next;
}QueueNode;
typedef struct
{
QueueNode* phead;
QueueNode* pend;
int size;
}Queue;
void QueueInit(Queue* pQ)
{
assert(pQ);
pQ->pend = pQ->phead = NULL;
pQ->size = 0;
}
void QueuePush(Queue* pQ, QueueData x)
{
assert(pQ);
QueueNode* pnew = (QueueNode*)malloc(sizeof(QueueNode));
assert(pnew);
pnew->val = x;
pnew->next = NULL;
if (pQ->size == 0)
{
pQ->pend = pQ->phead = pnew;
}
else
{
pQ->pend->next = pnew;
pQ->pend = pnew;
}
pQ->size++;
}
QueueData QueueFront(Queue* pQ)
{
assert(pQ);
assert(pQ->size);
return pQ->phead->val;
}
QueueData QueueBack(Queue* pQ)
{
assert(pQ);
assert(pQ->size);
return pQ->pend->val;
}
void QueuePop(Queue* pQ)
{
assert(pQ);
QueueData ret = pQ->phead->val;
if (pQ->size == 1)
{
free(pQ->phead);
pQ->pend = pQ->phead = NULL;
}
else
{
QueueNode* pn = pQ->phead;
pQ->phead = pQ->phead->next;
free(pn);
}
pQ->size--;
}
int QueueSize(Queue* pQ)
{
assert(pQ);
return pQ->size;
}
bool QueueEmpty(Queue* pQ)//判空
{
assert(pQ);
return pQ->size==0;
}
void QueueDestroy(Queue* pQ)
{
assert(pQ);
while (pQ->phead)
{
QueueNode* pnext = pQ->phead->next;
free(pQ->phead);
pQ->phead=pnext;
}
pQ->pend = pQ->phead = NULL;
pQ->size = 0;
}
typedef struct {
Queue pQ1;
Queue pQ2;
} MyStack;
MyStack* myStackCreate() {
MyStack* prt=(MyStack*)malloc(sizeof(MyStack));
QueueInit(&prt->pQ1);
QueueInit(&prt->pQ2);
return prt;
}
void myStackPush(MyStack* obj, int x) {
if(!QueueEmpty(&obj->pQ1))
QueuePush(&obj->pQ1,x);
else
QueuePush(&obj->pQ2,x);
}
int myStackPop(MyStack* obj) {
Queue* pnull=&obj->pQ1;
Queue* pn=&obj->pQ2;
if(QueueEmpty(pn))
{
pnull=&obj->pQ2;
pn=&obj->pQ1;
}
while(pn->size-1!=0)
{
QueuePush(pnull,QueueFront(pn));
QueuePop(pn);
}
int ret=QueueFront(pn);
QueuePop(pn);
return ret;
}
int myStackTop(MyStack* obj) {
if(!QueueEmpty(&obj->pQ1))
return QueueBack(&obj->pQ1);
else
return QueueBack(&obj->pQ2);
}
bool myStackEmpty(MyStack* obj) {
return QueueEmpty(&obj->pQ1)&&QueueEmpty(&obj->pQ2);
}
void myStackFree(MyStack* obj) {
QueueDestroy(&obj->pQ1);
QueueDestroy(&obj->pQ2);
free(obj);
obj=NULL;
}
3.循环队列
对于循环队列的实现我们可以使用顺序表或链表,不过使用链表比较复杂,更为推荐使用顺序表,此题我们就以顺序表来解决。
我们使用Head来储存队头下标,使用End来储存队尾元素的下一个空间的下标,那么当队列为空的时候,Head和End就指向同一个位置,等队满之后,End又绕回到头。如下:
这样看起来一个循环队列很简单的就能写出来,不过这里还有一个显而易见的问题,就是如何判断队列是否空?如何判断队列是否满?这里可千万不要认为Head和End指向同一个位置就是满或空,或者认为Head和End同时指向下标为0的位置就是空。我们来看把上面队列元素都出队会怎样:
在这里我们可以观察到无论是队列满还是空Head和End都是指向同一个位置,所以此时我们是无法判断队列是满是空的, 为了解决之这个问题现在有两个方案
方案1:添加一个变量size来储存队列的长度,当有元素入队size++,有元素出队size--。
方案2:添加一个新的空间而这个新的空间并不用来储存有效元素,只是为了当栈满的时候不让End指向Head可以用来区别于End和Head指向同一位置的时候栈为空的情况,比如原来队列需要的是k个空间,那么我们可以创建k+1个空间,那么我们就可以用Head和End相等来表示栈空,Head等于End+1来表示栈满,然后需要处理一下End等于k这个特殊情况,如下两种栈满的情况:
处理一下End等于k这个特殊情况,我们可以用if语句或者用取模运算,如:(End+1)%(k+1)
typedef struct {
int* arr;
int head;
int end;
int k;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* prt=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
prt->arr=(int*)malloc(sizeof(int)*(k+1));
prt->head=prt->end=0;
prt->k=k;
return prt;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
if(obj->end!=obj->k)
return obj->end+1==obj->head;
else
return obj->head==0;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return obj->head==obj->end;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if(myCircularQueueIsFull(obj))
return false;
else
{
obj->arr[obj->end]=value;
obj->end++;
if(obj->end==obj->k+1)
obj->end=0;
return true;
}
}
bool myCircularQueueDeQueue(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
return false;
obj->head++;
obj->head%=obj->k+1;
return true;
}
int myCircularQueueFront(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return -1;
int ret=obj->arr[obj->head];
return ret;
}
int myCircularQueueRear(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return -1;
if(obj->end==0)
return obj->arr[obj->k];
return obj->arr[obj->end-1];
}
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->arr);
free(obj);
}