前言
为了更好的掌握与练习数据结构的栈与队列,下面三道经典例题,可以帮我们更好的掌握,区分栈和队列的特性及应用。补充下面代码均是不完整(原码只包括oj中方法的调用,队列和栈方法的原码,如有需要可查看栈与队列文章)。
用队列实现栈
案列分析
这里注意点就是:入栈,出栈,插入怎么处理,入栈先向一个空链表进行入栈,出栈的时候把size-1个元素出到另一个链表中(可以理解为空链表进行存储),插入时,记得插入的链表是不为空的链表,而不是为空的。
大坑出现的情况:
代码实现
typedef struct {
Queue q1;
Queue q2;
} MyStack;
//创建一个栈
MyStack* myStackCreate() {
//指向栈的指针
MyStack *str=(MyStack *)malloc(sizeof(MyStack));
QueueInit(&str->q1);
QueueInit(&str->q2);
return str;
}
void myStackPush(MyStack* obj, int x) {
if(!QueueEmpty(&obj->q1))
{
QueuePush(&obj->q1,x);
}
else
{
QueuePush(&obj->q2,x);
}
}
//出栈
int myStackPop(MyStack* obj) {
//进行假设空和不为空的链表
Queue*none=&obj->q1;
Queue*empty=&obj->q2;
//找不为空的链表
if(!QueueEmpty(&obj->q1))
{
none=&obj->q1;
empty=&obj->q2;
}
//进行循环的出栈
while(QueueSize(none)>1)
{
int front=QueueFront(none);
QueuePush(empty,front);
QueuePop(none);
}
//此时出完。就剩一个,保存这个数据之后删除
int pop=QueueFront(none);
QueuePop(none);
return pop;
}
//获取栈顶元素
int myStackTop(MyStack* obj) {
//取队尾数据
if(!QueueEmpty(&obj->q1))
{
return QueueBack(&obj->q1);
}
else
{
return QueueBack(&obj->q2);
}
}
bool myStackEmpty(MyStack* obj) {
return(QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2));
}
void myStackFree(MyStack* obj) {
QueueDestroy(&obj->q1);
QueueDestroy(&obj->q2);
//销毁的时候要看看初始化,所以记得要销毁指向栈的指针
free(obj);
obj=NULL;
}
用栈实现队列
案列分析
代码实现
typedef struct {
ST pop;
ST pus;
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue *st=(MyQueue*)malloc(sizeof(MyQueue));
STInit(&st->pop);
STInit(&st->pus);
return st;
}
void myQueuePush(MyQueue* obj, int x) {
//插入
StackPush(&obj->pop,x);
}
int myQueuePop(MyQueue* obj) {
//出栈
//assert(&obj->pop);
if(StackEmpty(&obj->pus))
{
while(!StackEmpty(&obj->pop))
{
//栈顶元素出栈存到另一个栈中
StackPush(&obj->pus, StackTop(&obj->pop));
//对原栈顶元素进行删除
StackPop(&obj->pop);
}
}
int pop=StackTop(&obj->pus);
//删除栈顶元素
StackPop(&obj->pus);
return pop;
}
int myQueuePeek(MyQueue* obj) {
//取栈顶
if(StackEmpty(&obj->pus))
{
while(!StackEmpty(&obj->pop))
{
StackPush(&obj->pus, StackTop(&obj->pop));
StackPop(&obj->pop);
}
}
//取栈顶是不用删除
return StackTop(&obj->pus);
}
bool myQueueEmpty(MyQueue* obj) {
//判断是否为空
return StackEmpty(&obj->pop)&&StackEmpty(&obj->pus);
}
void myQueueFree(MyQueue* obj) {
//释放
STDestroy(&obj->pus);
STDestroy(&obj->pop);
free(obj);
obj=NULL;
}
设计循环队列
案列分析
代码实现
typedef struct {
int *arr;
int front;
int rear;
int capacity;
} MyCircularQueue;
//初始化
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* st=(MyCircularQueue* )malloc(sizeof(MyCircularQueue));
//对数组进行开辟空间
st->arr=(int *)malloc(sizeof(int)*(k+1));
st->front=st->rear=0;
st->capacity=k;
return st;
}
//判断是否满了
bool myCircularQueueIsFull(MyCircularQueue* obj) {
return (obj->rear+1)%(obj->capacity+1)==obj->front;
}
//判断循环队列是否为空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return (obj->front==obj->rear);
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
//首先看是否满了,不满时进行插入
if(myCircularQueueIsFull(obj))
{
return false;
}
obj->arr[obj->rear++]=value;
//不满的时候进行插入要注意是否溢出
obj->rear%=obj->capacity+1;
return true;
}
//删除循环队列的元素
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
//要是队列不为空
//删除一次front++
if(myCircularQueueIsEmpty(obj))
{
return false;
}
//不为空的时候
obj->front++;
//防止溢出
obj->front%=obj->capacity+1;
return true;
}
//取队列的头元素
int myCircularQueueFront(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
return obj->arr[obj->front];
}
//取队列的尾元素
int myCircularQueueRear(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
//当rear为0时那么rear就会溢出
int prev=obj->rear-1;
if(obj->rear==0)
{
prev=obj->capacity;
}
return obj->arr[prev];
}
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->arr);
free(obj);
obj=NULL;
}
总结
这三个案列极好的练习了前段时间所学的栈与队列知识的点,上述三个案例虽然思路不是很难,但是细节较多,需要认真的练习。整理不易,期待各位大佬的一键三连(点赞,收藏,关注)。