【数据结构初阶】详解:实现循环队列、用栈实现队列、用队列实现栈

一、循环队列

1、题目简述

与队列的区别:循环队列的空间大小是固定的,且队尾连接队头形成循环。
在这里插入图片描述
要实现的方法:
在这里插入图片描述

2、方法讲解

我们开始就说过,循环队列的数据储存的数量是固定的,为了方便讲解,我们这里设队列可储存4个数据。即 k=4。

2.1、了解tail的指向

我们将队列的数据存放在数组中,head为队头下标,tail为队尾的下一个元素的下标
在这里插入图片描述

tail为队尾的下一个元素的下标 原因:
若指向队尾数据:
当对列为空时,head、tail均指向首,即head=tail=0
而当队列有一个元素时,tail指向队尾,则仍有head=tail=0
产生歧义,无法区分队列是否有元素。
故,tail必须指向队尾元素的下一个元素

2.2、了解空间是如何利用的

注:队列遵循先进先出的规则
下面来举例了解数据的循环入队列:
1、入三个数据1,2,3
在这里插入图片描述

2、出两次数据
在这里插入图片描述
3、入三个数据4,5,6
在这里插入图片描述
在有限空间内,保证先进先出,空间重复使用。
那么问题来了:如何判断队列是否为空?

2.3、如何判断队列是否为空(假溢出问题)?

假溢出:空、满时判断条件相同。
在这里插入图片描述
此时无法区分空、满。
为了解决假溢出问题,我们有两种方法

  • 方法一:通过size来计录数据
    空:size = 0
    满:size = k (k:队列可储存数据个数)

  • 方法二:多开一个空间
    k = 4 (最多push入4个数据)
    在这里插入图片描述
    push入4个数据 1,2,3,4
    在这里插入图片描述
    空一个空间出来,则满的时候 head不可能等于tail,假溢出问题就解决了。
    已经入了4个数据了,想要再入数据就要先出数据,把空间空出来。

pop 出三次
在这里插入图片描述
push 入 5,6,7
在这里插入图片描述
由上可得:

空: head == tail
满: (tail+1)% (k+1)== head

2.4、实现代码

1、初始化
在这里插入图片描述
2、获取队首元素
在这里插入图片描述
3、取尾
在这里插入图片描述
在取尾返回时,也可写为
在这里插入图片描述

//数组
typedef struct {
   
    
    
    int* a;
    //数组下标
    int head;
    int tail;//指向尾的下一个
    int k;
} MyCircularQueue;

//初始化
MyCircularQueue* myCircularQueueCreate(int k) {
   
    
    
    MyCircularQueue* obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    //开k+1个数组空间
    obj->a = (int*)malloc(sizeof(int) * (k + 1));
    obj->head = obj->tail = 0;
    obj->k = k;
    return obj;
}
//判空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
   
    
    
    return obj->head == obj->tail;
}
//判满
bool myCircularQueueIsFull(MyCircularQueue* obj) {
   
    
    
    return (obj->tail + 1) % (obj->k + 1) == obj->head;
}
//入队列
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
   
    
    
    if (myCircularQueueIsFull(obj))
        return false;

    obj->a[obj->tail] = value;
    obj->tail++;
    obj->tail %= (obj->k + 1);
    return true;
}
//删除数据
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
   
    
    
    if (myCircularQueueIsEmpty(obj))
        return false;
    obj->head++;
    obj->head %= obj->k + 1;
    return true;
}
//找头
int myCircularQueueFront(MyCircularQueue* obj) {
   
    
    
    if (myCircularQueueIsEmpty(obj))
        return -1;
    else
        return obj->a[obj->head];
}
//取尾
int myCircularQueueRear(MyCircularQueue* obj) {
   
    
    
    if (myCircularQueueIsEmpty(obj))
        return -1;
    else
        return obj->tail==0? obj->a[obj->k] : obj->a[obj->tail-1];
}

//释放
void myCircularQueueFree(MyCircularQueue* obj) {
   
    
    
    free(obj->a);
    free(obj);
}

二、用栈实现队列

1、题目简述

在这里插入图片描述
注意:C语言不支持栈,我们需要先模拟栈。
模拟栈在这里就不赘述了,以下是C语言模拟的栈:

typedef int STDataType;
typedef struct Stack
{
   
    
    
	STDataType* a;//指针指向数组
	int top;
	int capacity;//数组大小
}ST;

//初始化与销毁
void STInit(ST* pst)
{
   
    
    
	assert(pst);//指针不为空
	pst->a = NULL;

	//若初始化top=0;++之后,当要入栈的数据入完,top指向的是栈顶元素的下一个位置(因为top进行了++)
	//若初始化top=-1;++之后,当要入栈的数据入完,top指向的是栈顶元素
	pst->top = 0;
	pst->capacity = 0;
}
void STDestroy(ST* pst)
{
   
    
    
	assert(pst);
	free(pst->a);
	pst->a