申明一下在开头先:下面代码的实现有用到栈和队列的操作代码,。
栈的代码链接:https://blog.csdn.net/ijn842/article/details/80274340
队列的代码链接:https://blog.csdn.net/ijn842/article/details/80314060
1.使用两个栈实现一个队列
假设要入队列的元素为 1 、2、3、4、5,而队列的底层实现为两个栈,我们都知道队列的规则为先进先出(即在队尾进行入元素的操作,而在队头进行出元素的操作),而栈的规则为先进后出(或者是后进先出,一样的),两个栈想要实现一个队列就必须指定一个栈来先进行入队列的操作,但是因为先进去的元素在栈底,出队列的时候就不能是它先出,所以将除栈底以外的元素保存到另一个栈中,这时栈底的元素已成为栈顶,就可以出栈也就是出队列了。这样就实现了队列的进出了
下面是代码
QueueBy2StackInterview.h
#include "Stack.h" typedef struct QueueBy2Stack { struct Stack s1; struct Stack s2; }QueueBy2Stack,*PQueueBy2Stack; //1.初始化队列 void QueueBy2StackInit(PQueueBy2Stack q); //2.入队列 void QueueBy2StackPush(PQueueBy2Stack q,DataType data); //3.出队列 void QueueBy2StackPop(PQueueBy2Stack q); //4.判空 int QueueBy2StackEmpty(PQueueBy2Stack q); //5.获取队头元素 DataType QueueBy2StackFront(PQueueBy2Stack q); //6.获取队尾元素 DataType QueueBy2StackRear(PQueueBy2Stack q); //7.队列长度 int QueueBy2StackSize(PQueueBy2Stack q); //8.打印队列 void QueueBy2StackPrint(PQueueBy2Stack q);
QueueBy2StackInterview.c
#define _CRT_SECURE_NO_WARNING 1 #include "QueueAndStackInterview.h" //1.初始化队列 void QueueBy2StackInit(PQueueBy2Stack q) { assert(q); StackInit(&q->s1); StackInit(&q->s2); } //2.入队列 void QueueBy2StackPush(PQueueBy2Stack q,DataType data) { assert(q); if(MAX_SIZE == q->s1._top) return; if(!StackEmpty(&q->s2)) { while(StackSize(&q->s1)) { StackPush(&q->s1,StackTop(&q->s2)); StackPop(&q->s2); } } else StackPush(&q->s1,data); } //3.出队列 void QueueBy2StackPop(PQueueBy2Stack q) { assert(q); if(QueueBy2StackEmpty(q)) return; //出完一个元素后,将栈s2里的元素放回栈s1里(因为指定了进出队列都在栈s1里) if(!StackEmpty(&q->s2)) { while(StackSize(&q->s2)) { StackPush(&q->s1,StackTop(&q->s2)); StackPop(&q->s2); } } //将栈s1里的元素放到栈s2中,直到s1里剩一个元素为止,将该元素出栈即可 while(StackSize(&q->s1) > 1) { StackPush(&q->s2,StackTop(&q->s1)); StackPop(&q->s1); } StackPop(&q->s1); } //4.判空 int QueueBy2StackEmpty(PQueueBy2Stack q) { assert(q); if(StackEmpty(&q->s1)&&StackEmpty(&q->s2)) return 1; return 0; } //5.获取队头元素 DataType QueueBy2StackFront(PQueueBy2Stack q) { assert(q); if(!QueueBy2StackEmpty(q)) { //将栈s1里的全部元素放到s2里 while(StackSize(&q->s1)) { StackPush(&q->s2,StackTop(&q->s1)); StackPop(&q->s1); } } return StackTop(&q->s2); } //6.获取队尾元素 DataType QueueBy2StackRear(PQueueBy2Stack q) { assert(q); if(!StackEmpty(&q->s2)) { if(!StackEmpty(&q->s2)) //将栈s2里的全部元素放到s1里 { while(StackSize(&q->s2)) { StackPush(&q->s1,StackTop(&q->s2)); StackPop(&q->s2); } } } return StackTop(&q->s1); } //7.队列长度 int QueueBy2StackSize(PQueueBy2Stack q) { assert(q); if(QueueBy2StackEmpty(q)) return 0; if(!StackEmpty(&q->s2)) { while(StackSize(&q->s2)) { StackPush(&q->s1,StackTop(&q->s2)); StackPop(&q->s2); } } return StackSize(&q->s1); } //8.打印队列 void QueueBy2StackPrint(PQueueBy2Stack q) { int i = 0; assert(q); if(QueueBy2StackEmpty(q)) return ; if(!StackEmpty(&q->s2)) { while(StackSize(&q->s2)) { StackPush(&q->s1,StackTop(&q->s2)); StackPop(&q->s2); } } for( ; i < StackSize(&q->s1) ;i++) { printf("%d--->", q->s1._array[i]); } printf("NULL\n"); }
test.c
#include "QueueAndStackInterview.h" int main() { QueueBy2Stack q; QueueBy2StackInit(&q); QueueBy2StackPush(&q,1); QueueBy2StackPush(&q,2); QueueBy2StackPush(&q,3); QueueBy2StackPush(&q,4); QueueBy2StackPush(&q,5); QueueBy2StackPush(&q,6); QueueBy2StackPush(&q,7); QueueBy2StackPrint(&q); printf("front is:%d\n",QueueBy2StackFront(&q)); printf("rear is:%d\n",QueueBy2StackRear(&q)); printf("size is:%d\n",QueueBy2StackSize(&q)); QueueBy2StackPop(&q); QueueBy2StackPop(&q); QueueBy2StackPrint(&q); printf("front is:%d\n",QueueBy2StackFront(&q)); printf("rear is:%d\n",QueueBy2StackRear(&q)); printf("size is:%d\n",QueueBy2StackSize(&q)); return 0; }
2.使用两个队列实现栈
栈的实现底层用两个队列 | |
---|---|
队列的基本特性是先进先出 | 栈的基本特性是先进后出 |
元素进队列的时候,比如{1,2,3,4,5,},进队列的完毕是 (从队尾开始) {5,4,3,2,1} | {1,2,,3,4,5}进栈完毕后的序列也是{5,4,3,2,1},所以说用队列实现了进栈 |
但是问题来了,由于栈和队列的出特性并不一致,那么怎样实现呢?
就拿{1,2,3,4,5}继续来说,入队列完毕后队尾是5,而在栈中它便是栈顶元素,不能直接出栈,所以此时我们另一个队列便派上了用场,可以让队头元素1保存入队列到第二个队列里面,后面的2,3,4进行一样的操作,最后第一个队列只剩下队尾元素同时也是队头元素5出队列了也就是实现了出栈,只不过此时队列2里面的元素序列为{4,3,2,1}和队列1未进行出栈操作前是一样的(当然了少了一个元素5而已),所以并不需要重新把元素搬回队列1,重复上述和队列1一样的操作就可以实现出栈了。
QueueBy2StackInterview.h
typedef struct StackBy2Queue { struct SQueue q1; struct SQueue q2; }StackBy2Queue,*PStackBy2Queue; //1.初始化栈 void StackBy2QueueInit(PStackBy2Queue s); //2.入栈 void StackBy2QueuePush(PStackBy2Queue s,DataType data); //3.出栈 void StackBy2QueuePop(PStackBy2Queue s); //4.获取栈顶元素 DataType StackBy2QueueTop(PStackBy2Queue s); //5.查看栈的元素个数 int StackBy2QueueSize(PStackBy2Queue s); //6.判空 int StackBy2QueueEmpty(PStackBy2Queue s);
QueueBy2StackInterview.c
//1.初始化栈 void StackBy2QueueInit(PStackBy2Queue s) { assert(s); SQueueInit(&s->q1); SQueueInit(&s->q2); } //2.入栈 void StackBy2QueuePush(PStackBy2Queue s,DataType data) { assert(s); if(SQueueEmpty(&s->q1) && SQueueEmpty(&s->q2)) SQueuePush(&s->q1,data); else if(!SQueueEmpty(&s->q1)) SQueuePush(&s->q1,data); else SQueuePush(&s->q2,data); } //3.出栈 void StackBy2QueuePop(PStackBy2Queue s) { assert(s); if(!StackBy2QueueEmpty(s)) { if(!SQueueEmpty(&s->q1)) { while(SQueueSize(&s->q1) > 1) { SQueuePush(&s->q2,SQueueFrontData(&s->q1)); SQueuePop(&s->q1); } SQueuePop(&s->q1); } else { while(SQueueSize(&s->q2) > 1) { SQueuePush(&s->q1,SQueueFrontData(&s->q2)); SQueuePop(&s->q2); } SQueuePop(&s->q2); } } } //4.获取栈顶元素 DataType StackBy2QueueTop(PStackBy2Queue s) { assert(s); if(StackBy2QueueEmpty(s)) return 0; if(!SQueueEmpty(&s->q1)) return SQueueRearData(&s->q1); else return SQueueRearData(&s->q1); } //5.查看栈的元素个数 int StackBy2QueueSize(PStackBy2Queue s) { assert(s); if(StackBy2QueueEmpty(s)) return 0; if(!SQueueEmpty(&s->q1)) return SQueueSize(&s->q1); return SQueueSize(&s->q2); } //6.判空 int StackBy2QueueEmpty(PStackBy2Queue s) { if(SQueueEmpty(&s->q1) &&SQueueEmpty(&s->q2)) return 1; return 0; } #endif
test.c
StackBy2Queue s; StackBy2QueueInit(&s); StackBy2QueuePush(&s,1); StackBy2QueuePush(&s,2); StackBy2QueuePush(&s,3); StackBy2QueuePush(&s,4); StackBy2QueuePush(&s,5); StackBy2QueuePush(&s,6); StackBy2QueuePush(&s,7); StackBy2QueuePush(&s,8); printf("top is:%d\n",StackBy2QueueTop(&s)); printf("size is:%d\n",StackBy2QueueSize(&s)); StackBy2QueuePop(&s); StackBy2QueuePop(&s); printf("top is:%d\n",StackBy2QueueTop(&s)); printf("size is:%d\n",StackBy2QueueSize(&s));
3.实现一个栈,要求实现Push(出栈)、Pop(入栈)、Min(返回最小值)的时间复杂度为O(1)
我们都知道对于一个栈来说入栈和出栈操作每次都是一个元素,时间复杂度便是O(1),但是对于获得最小值便不一定了,因为有可能最小值不一定在栈顶位置,所以是不能直接对其进行操作的。
故此我们可以用一个结构体在里面封装元素data和最小值mindata,有什么用呢?
相当于我们每次入栈的时候都是入这个结构体,即有元素和最小值元素两个数值均入栈,当第一元素入栈的时候将最小值也标记为该元素的值,当第二个元素入栈的时候,用其和第一个最小值比较,如果小于便将第二个元素的最小值置为该元素的值,后面的元素入栈的最小值依次进行该操作,最后当我们取栈顶元素,同时可以取到栈顶元素的值和最小元素的值,时间复杂度均为O(1)
QueueBy2StackInterview.h
//1.实现一个栈,要求实现Push(入栈)、Pop(出栈)、 //Min(返回最小值)的时间复杂度为O(1) //1.初始化栈 void MinStackInit(Stack* s); //2.入栈 void MinStackPush(Stack* s,ElemType data); //3.出栈 void MinStackPop(Stack* s); //4.判空 int MinStackEmpty(Stack* s); //5.获取栈顶元素 ElemType MinStackTop(Stack* s); //6.获取栈的长度 int MinStackSize(Stack* s); //7.查看最小元素 ElemType MinStackminData(Stack* s);
QueueBy2StackInterview.c
//1.初始化栈void MinStackInit(Stack* s)
{ assert(s); StackInit(s); } //2.入栈 void MinStackPush(Stack* s,ElemType data) { DataType elem; assert(s); if(StackEmpty(s)) { elem._data = elem._mindata = data; StackPush(s,elem); } else { elem = StackTop(s); if(elem._mindata > data) elem._mindata = data; elem._data = data; StackPush(s,elem); } } //3.出栈 void MinStackPop(Stack* s) { assert(s); if(StackEmpty(s)) return; s->_top--; } //4.判空 int MinStackEmpty(Stack* s) { assert(s); return s->_top == 0; } //5.获取栈顶元素 ElemType MinStackTop(Stack* s) { assert(!MinStackEmpty(s)); return s->_array[s->_top]._data; } //6.获取栈的长度 int MinStackSize(Stack* s) { assert(s); return s->_top; } //7.查看最小元素 ElemType MinStackminData(Stack* s) { assert(!MinStackEmpty(s)); return s->_array[s->_top]._mindata; }
4.一个数组实现两个栈
QueueBy2StackInterview.h
#include <stdio.h> #include <assert.h> #define MAX_SIZE 10 typedef int DataType; typedef struct Stack { DataType _array[MAX_SIZE]; int _top1; int _top2; }Stack; //1.栈的初始化 void ShareStackInit(Stack* s); //2.入栈 void ShareStackPush(Stack* s, DataType data, int which); //3.出栈 void ShareStackPop(Stack* s, int which); //4.判空 int ShareStackEmpty(Stack* s, int which); //5.查看长度 int ShareStackSize(Stack* s, int which); //6.查看栈顶元素 DataType ShareStackTop(Stack* s,int which);
QueueBy2StackInterview.c
void ShareStackInit(Stack* s) { assert(s); s->_top1 = 0; s->_top2 = MAX_SIZE-1;//栈2的栈顶从数组下标的最后一个开始 } //2.入栈 void ShareStackPush(Stack* s, DataType data, int which) { assert(s); assert(1 == which || 2 == which); if(s->_top1 > s->_top2) { printf("栈已满!!!\n"); return; } if(1 == which) s->_array[s->_top1++] = data; else s->_array[s->_top2--] = data; } //3.出栈 void ShareStackPop(Stack* s, int which) { assert(s); assert(1 == which || 2 == which); if(1 == which) { if(0 == s->_top1) return; s->_top1--; } else { if(MAX_SIZE-1 == s->_top2)//栈顶指针指到了栈底,此时说明栈2为空 return; s->_top2++; } } //4.判空 int ShareStackEmpty(Stack* s, int which) { assert(s); assert(1 == which || 2 == which); if(1 == which) { if(0== s->_top1) return 1; } else { if(MAX_SIZE-1 == s->_top2) return 1; } return 0; } //5.查看长度 int ShareStackSize(Stack* s, int which) { assert(s); assert(1 == which || 2 == which); return 1 == which ? s->_top1 : MAX_SIZE-1-s->_top2; } //6.查看栈顶元素 DataType ShareStackTop(Stack* s,int which) { assert(s); assert(1 == which || 2 == which); if(1 == which) return s->_array[s->_top1-1]; else return s->_array[s->_top2-1]; }
test.c
int main() { Stack s; ShareStackInit(&s); ShareStackPush(&s,1,1); ShareStackPush(&s,2,1); ShareStackPush(&s,3,1); ShareStackPush(&s,4,1); printf("size1 is:%d\n",ShareStackSize(&s,1)); //printf("top1 is:%d\n",ShareStackTop(&s,2)); printf("s->_top1 empty is:%d\n",ShareStackEmpty(&s,1)); ShareStackPop(&s,1); printf("size1 is:%d\n",ShareStackSize(&s,1)); //printf("top1 is:%d\n",ShareStackTop(&s,2)); printf("s->_top1 empty is:%d\n",ShareStackEmpty(&s,1)); ShareStackInit(&s); ShareStackPush(&s,5,2); ShareStackPush(&s,6,2); ShareStackPush(&s,7,2); ShareStackPush(&s,8,2); printf("size2 is:%d\n",ShareStackSize(&s,2)); //printf("top2 is:%d\n",ShareStackTop(&s,2)); printf("s->_top2 empty is:%d\n",ShareStackEmpty(&s,2)); ShareStackPop(&s,2); printf("size2 is:%d\n",ShareStackSize(&s,2)); //printf("top2 is:%d\n",ShareStackTop(&s,2)); printf("s->_top2 empty is:%d\n",ShareStackEmpty(&s,2)); return 0; }
5.元素出栈、入栈顺序的合法性。如入栈序列{1,2,3,4,5},出栈序列{4,5,3,2,1}
我们用index来标记入栈数组下标,用outdex来标记出栈序列下标,当入栈的元素等于outdex下标所标记的元素时,就让该元素出栈,两个下标继续往后走,如果不相等,就让入栈序列继续入栈(index++),直到有index所指元素等于outdex所指元素相等时,该元素才出栈,outdex才继续玩后走,重复循环上述步骤即可。
源代码
int InOutIsValid(int* Inorder,int InSize,int* Outorder,int OutSize) { int Index = 0;//入栈数组下标 int Outdex = 0;//出栈数组下标 Stack s; StackInit(&s); while(Outdex<OutSize) { while(StackEmpty(&s) || StackTop(&s) != Outorder[Outdex]) { if(Index < InSize) { StackPush(&s,Inorder[Index++]); } else return 0; } StackPop(&s); Outdex++; } return 1; }
测试代码
#include "QueueAndStackInterview.h" int main() { int Inorder[] = {1,2,3,4,5}; int Outorder[] = {4,5,3,2,1}; int InSize = sizeof(Inorder)/sizeof(Inorder[0]); int OutSize = sizeof(Outorder) / sizeof(Outorder[0]); int ret = InOutIsValid(Inorder, InSize,Outorder,OutSize); printf("%d\n",ret); return 0; }