栈和队列--oj题

目录

用栈实现队列

1.题目链接

2.题目描述

3.题目分析

4.代码实现

用队列实现栈

1.题目链接

2.题目描述

3.题目分析

4.代码实现

设计循环队列

1.题目链接

2.题目描述

3.题目分析

4.代码实现


用栈实现队列

1.题目链接

232. 用栈实现队列 - 力扣(LeetCode)

2.题目描述

3.题目分析 

图的上部分是我们要模拟出来的队列,下部分是两个栈

  • 我们首先选定一个栈作为入口

  •  但我们如果直接用栈出数据,得到的是3,为了得到需要的1,就将第一个栈的数据全部导入另一个栈中,之后在第二个栈中进行出栈即可

  •  如果我们继续出栈,可以直接在第二个栈中操作,此时它里面的数据顺序恰好为队列出栈顺序
  • 但若要入栈,则必须在第一个栈中进行,否则会扰乱数据顺序

  •  当第二个栈无数据时,就需要像前面那样,将第一个栈的数据导在里面

4.代码实现

#define MALLOC(type,num) (type*)malloc(num*sizeof(type))
#define REALLOC(obj,type,num) (type*)realloc(obj,num*sizeof(type))

typedef struct stack{
    int* data;  //用顺序表模拟栈
    int top;  //下一个栈顶元素的下标大小(也是栈顶元素的个数)
    int capacity;  //容量,当元素个数超过容量时,需要扩容
}node;
typedef struct {  //因为下面的函数中只传入了一个指针,所以需要用
                  //该指针管控两个设定的栈类型的指针
    node* stack1;
    node* stack2;
} MyQueue;

MyQueue* myQueueCreate() { //初始化
   MyQueue* obj=MALLOC(MyQueue,1);
   obj->stack1=MALLOC(node,1);
   obj->stack1->data=MALLOC(int,5);
   obj->stack1->capacity=5;
   obj->stack1->top=0;

   obj->stack2=MALLOC(node,1);
   obj->stack2->data=MALLOC(int,5);
   obj->stack2->capacity=5;
   obj->stack2->top=0;
   return obj;
}

void myQueuePush(MyQueue* obj, int x) {
    if(obj->stack1->top==obj->stack1->capacity){ //扩容
        int* tmp=REALLOC(obj->stack1->data,int,obj->stack1->capacity*2);
        obj->stack1->capacity*=2;
        obj->stack1->data=tmp;
    }
    obj->stack1->data[obj->stack1->top++]=x; //入1号栈
}

int myQueuePop(MyQueue* obj) {
    if(obj->stack2->top>0){  //如果2中还有元素,就直接出
        obj->stack2->top--;
        return obj->stack2->data[obj->stack2->top];
    }
    //没有元素,需要将1中数据导入2
    int tmp=obj->stack1->top;  //1中元素个数
    while(tmp--){
        obj->stack2->data[obj->stack2->top++]=obj->stack1->data[--obj->stack1->top];  //导入2中
    }
    int t=obj->stack2->data[obj->stack2->top-1];  //出2号栈
    obj->stack2->top--;
    return t;
}

int myQueuePeek(MyQueue* obj) {
    if(obj->stack2->top>0){
        return obj->stack2->data[obj->stack2->top-1];
    }
    
    int tmp=obj->stack1->top;  //1中元素个数
    while(tmp--){
        obj->stack2->data[obj->stack2->top++]=obj->stack1->data[--obj->stack1->top];  //导入2中
    }
    int t=obj->stack2->data[obj->stack2->top-1];
    return t;
}

bool myQueueEmpty(MyQueue* obj) {
    return ((obj->stack1->top==0)&&(obj->stack2->top==0)); //两个栈都为空时,才为队列空
}

void myQueueFree(MyQueue* obj) {
    free(obj->stack1->data);
    free(obj->stack2->data);
    free(obj->stack1);
    free(obj->stack2);
}

用队列实现栈

1.题目链接

225. 用队列实现栈 - 力扣(LeetCode)

2.题目描述

3.题目分析

图的右边是我们要模拟出来的栈,左边是两个队列

  • 我们首先选定一个队列入数据(在栈中入数据是右边这样)

  •  如果要出数据的话,我们需要出3,但由队列出的数据是1

  •  因此将1,2出队,进入到第二个队列中

 等第一个队列出3后,第一个队列就空了

  • 如果继续出栈,则需要将不为空的队列的前n-1个数据导入空队列,剩下一个直接在原队列出队

  • 如果要入栈,则直接在不为空的队列入即可,因为队列在导入的过程中并没有改变原顺序

4.代码实现

#define MALLOC(type,num) (type*)malloc(num*sizeof(type))
#define REALLOC(obj,type,num) (type*)realloc(obj,num*sizeof(type))

typedef struct node{
    int* data; //用顺序表模拟队列
    int head;
    int tail;  //数值为队列中的元素数量
    int capacity;  //容量
}node;
typedef struct {
    node* queue1;
    node* queue2;
} MyStack;

MyStack* myStackCreate() {//初始化
   MyStack* obj=MALLOC(MyStack,1);
   obj->queue1=MALLOC(node,1);
   obj->queue1->data=MALLOC(int,5);
   obj->queue1->capacity=5;
   obj->queue1->head=obj->queue1->tail=0;

   obj->queue2=MALLOC(node,1);
   obj->queue2->data=MALLOC(int,5);
   obj->queue2->capacity=5;
   obj->queue2->head=obj->queue2->tail=0;
   return obj;
}
bool Empty(node* q){ //判断哪个队列为空,为空返回真
    return (q->tail==0);
}
void myStackPush(MyStack* obj, int x) { 
    node* emp=obj->queue1,*nonemp=obj->queue2; //假设1为空,2不为空
    if(Empty(obj->queue2)&&(!Empty(obj->queue1))){ //如果2为空且1不为空(防止都为空的情况),就修改指针内容
        emp=obj->queue2;
        nonemp=obj->queue1;
    }
    if(nonemp->tail==nonemp->capacity){  //入在不为空的队列里(即使都为空,也可以入成功)
    //不够时进行扩容
        int* tmp=REALLOC(nonemp->data,int,nonemp->capacity*2);
        nonemp->capacity*=2;
        nonemp->data=tmp;
    }
    nonemp->data[nonemp->tail++]=x;
}
bool myStackEmpty(MyStack* obj) {  //两个队列都为空时,才为空
    return (obj->queue1->tail==0)&&(obj->queue2->tail==0);
}
int myStackPop(MyStack* obj) {  //要出不为空的队列
    node* emp=obj->queue1,*nonemp=obj->queue2;
    if(Empty(obj->queue2)&&(!Empty(obj->queue1))){
        emp=obj->queue2;
        nonemp=obj->queue1;
    }

    if(!myStackEmpty(obj)){
        int t=nonemp->tail-1;
        int ans=nonemp->data[t]; //先将要返回的栈顶元素(即非空队列最后一个元素)保存住
        while(t--){ //将n-1个元素导出到空队列
            emp->data[emp->tail]=nonemp->data[emp->tail];
            emp->tail++;//使先前的空队列元素+1
            nonemp->tail--;  //使先前的非空队列元素-1
            if(emp->tail==emp->capacity){ //扩容,因为emp正在加元素
                int* tmp=REALLOC(emp->data,int,emp->capacity*2);
                emp->capacity*=2;
                emp->data=tmp;
            }
        }
        nonemp->tail--; //因为最后还剩下一个元素,直接将tail-1即可
        //因为之前ans已经保存了该元素的值
        return ans;
    }   
    return 0;
}

int myStackTop(MyStack* obj) {  
    if(!myStackEmpty(obj)){
        node* emp=obj->queue1,*nonemp=obj->queue2; //还是之前的操作,找到非空队列,
        //直接返回最后一个元素
        if(Empty(obj->queue2)&&(!Empty(obj->queue1))){
        emp=obj->queue2;
        nonemp=obj->queue1;
        }
        int t=nonemp->tail-1;
        int ans=nonemp->data[t];
        return ans;
    }
    return 0;
}

void myStackFree(MyStack* obj) {
    free(obj->queue1->data);
    free(obj->queue1);
    free(obj->queue2->data);
    free(obj->queue2);
}

设计循环队列

1.题目链接

622. 设计循环队列 - 力扣(LeetCode)

2.题目描述

3.题目分析

  • 因为循环队列的容量是固定的,因此不需要扩容操作
  • 由于是循环,并且我们是用下标访问,因此在入队和出队时需要处理下标(只要当他出范围时,赋为0即可,或者取余数也可)

4.代码实现

#define MALLOC(type,num) (type*)malloc(sizeof(type)*num)
typedef struct {
    int* data;
    int head; //记录起始下标
    int tail; //记录最后一个元素的下一个下标
    int size;  //元素个数
    int capacity;  //容量,这里无法扩容,因为循环队列容量是固定的
} MyCircularQueue;

MyCircularQueue* myCircularQueueCreate(int k) {  //初始化
    MyCircularQueue* obj=MALLOC(MyCircularQueue,1);
    obj->data=MALLOC(int,k+1);
    obj->head=0;
    obj->tail=0;obj->size=0;
    obj->capacity=k;
    return obj;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(obj->size==obj->capacity){  //当队列已满,则不能添加数据了
        return false;
    }
    if(obj->tail==obj->capacity){   //如果尾指针向右移动至数组外,需要将其移动至0处
        //(会出现这种情况的原因是:满队列的情况下进行出队,就有空元素了,
        //也就需要tail++,但tail需要保持在数组下标的范围内)
        obj->tail=0;
    }
    //入队
    obj->data[obj->tail]=value;  
    obj->tail++;
    obj->size++;  
    return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(obj->size==0){  //如果队列内无元素,就不能出队了
        return false;
    }
    obj->data[obj->head]=0;
    obj->head++;
    if(obj->head==obj->capacity){ //放在后面处理是为了及时将head控制在合理的范围内.防止其他函数使用head时出现越界访问
        obj->head=0;
    }
    obj->size--;
    return true;
}

int myCircularQueueFront(MyCircularQueue* obj) {
    if(obj->size==0){
        return -1;
    }
    return obj->data[obj->head]; //head所在位置就是队头元素
}

int myCircularQueueRear(MyCircularQueue* obj) {
    if(obj->size==0){
        return -1;
    }
    int ans;
    if(obj->tail==0){  //这里要分情况,如果不分的话,当tail=0时,
        //我们需要的是tail-1所在的元素,但-1不在合理范围内
        ans=obj->capacity-1;  //因此按照逻辑,此时的队尾元素应该是capacity-1所在位置
    }
    else{
        ans=obj->tail-1; 
    }
    return obj->data[ans];
}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    if(obj->size==0){  //直接用size判断,简单又快捷
        return true;
    }
    return false;
}

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    if(obj->size==obj->capacity){
        return true;
    }
    return false;
}

void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->data);
    free(obj);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值