目录
用栈实现队列
1.题目链接
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.题目链接
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.题目链接
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);
}