申明一下在开头先:下面代码的实现有用到栈和队列的操作代码,。
栈的代码链接: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;
}