数据结构与算法⑨(第三章_下)队列的概念和实现(力扣:225+232+622)(下)

简介: 数据结构与算法⑨(第三章_下)队列的概念和实现(力扣:225+232+622)

数据结构与算法⑨(第三章_下)队列的概念和实现(力扣:225+232+622)(上):https://developer.aliyun.com/article/1513405

力扣链接:622. 设计循环队列

难度中等

设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。

循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

你的实现应该支持如下操作:

MyCircularQueue(k): 构造器,设置队列长度为 k 。


Front: 从队首获取元素。如果队列为空,返回 -1 。


Rear: 获取队尾元素。如果队列为空,返回 -1 。


enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。


deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。


isEmpty(): 检查循环队列是否为空。


isFull(): 检查循环队列是否已满。


示例:

MyCircularQueue circularQueue = new MyCircularQueue(3); // 设置长度为 3

circularQueue.enQueue(1); // 返回 true

circularQueue.enQueue(2); // 返回 true

circularQueue.enQueue(3); // 返回 true

circularQueue.enQueue(4); // 返回 false,队列已满

circularQueue.Rear(); // 返回 3

circularQueue.isFull(); // 返回 true

circularQueue.deQueue(); // 返回 true

circularQueue.enQueue(4); // 返回 true

circularQueue.Rear(); // 返回 4

提示:


所有的值都在 0 至 1000 的范围内;


操作数将在 1 至 1000 的范围内;


请不要使用内置的队列库。

typedef struct {
 
} MyCircularQueue;
 
 
MyCircularQueue* myCircularQueueCreate(int k) {
 
}
 
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
 
}
 
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
 
}
 
int myCircularQueueFront(MyCircularQueue* obj) {
 
}
 
int myCircularQueueRear(MyCircularQueue* obj) {
 
}
 
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
 
}
 
bool myCircularQueueIsFull(MyCircularQueue* obj) {
 
}
 
void myCircularQueueFree(MyCircularQueue* obj) {
 
}
 
/**
 * Your MyCircularQueue struct will be instantiated and called as such:
 * MyCircularQueue* obj = myCircularQueueCreate(k);
 * bool param_1 = myCircularQueueEnQueue(obj, value);
 
 * bool param_2 = myCircularQueueDeQueue(obj);
 
 * int param_3 = myCircularQueueFront(obj);
 
 * int param_4 = myCircularQueueRear(obj);
 
 * bool param_5 = myCircularQueueIsEmpty(obj);
 
 * bool param_6 = myCircularQueueIsFull(obj);
 
 * myCircularQueueFree(obj);
*/

解析:

这道题用数组和链表都能实现,各有优劣

要注意下面的判空和判满问题:

判空和判满问题可以使用添加一个size解决,但比较官方是多开一个空间:


【0】 【1】 【2】 【3】 【4】

一般情况tail+1等于front 如上面tail 是【1】,front是【2】(1+1)%(4+1)==2也是满

但是如果tail是【4】,front是【0】,tail+1等于front就不能判断

用上面的公式(4+1)%(4+1)==0 就是满

链表空的情况和上面一样,满的情况是这样:


数组实现 函数bool myCircularQueueDeQueue(MyCircularQueue* obj)的图:

数组实现的代码:(有空可以写写链表实现的)

typedef struct {
    //匿名结构体
    int* arr;
    int front;
    int tail;
    int k;
} MyCircularQueue;
bool myCircularQueueIsEmpty(MyCircularQueue* obj);//可以先实现这两个 声明后下面可以用
bool myCircularQueueIsFull(MyCircularQueue* obj);
 
MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue* cq = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    //OJ题一般都会开辟空间成功,不用判空了
    cq->arr = (int*)malloc(sizeof(int) * (k + 1));//初始化 开k+1个空间
    cq->front = cq->tail = 0;
    cq->k = k;
    return cq;
}
 
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    //enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
    //(失败返回假)满了就失败  
    //先滑到下面实现myCircularQueueIsFull和myCircularQueueIsEmpty,记得在上面声明
    if (myCircularQueueIsFull(obj))
    {
        return false;
    }
    obj->arr[obj->tail] = value;
    obj->tail++;
    obj->tail %= (obj->k + 1);//超出k+1就模到0从头开始,没超,模和没模一样
    return true;
}
 
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    //deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
    if (myCircularQueueIsEmpty(obj))
    {
        return false;
    }
    obj->front++;  //不理解可以看上面的图
    obj->front %= (obj->k + 1); //超出k+1就模到0从头开始,没超,模和没模一样
    return true;
}
 
int myCircularQueueFront(MyCircularQueue* obj) {
    //Front: 从队首获取元素。如果队列为空,返回 -1 。
    if (myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->arr[obj->front];
}
 
int myCircularQueueRear(MyCircularQueue* obj) {
    //Rear: 获取队尾元素。如果队列为空,返回 -1 。
    if (myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    if (obj->tail == 0)//如果tail在0上,返回tail的上一个就是k
    {
        return obj->arr[obj->k];
    }
    else
    {
        return obj->arr[obj->tail - 1];
    }
}
 
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->front == obj->tail; //看上面图的判空和判满条件
}
 
bool myCircularQueueIsFull(MyCircularQueue* obj) {
    return (obj->tail + 1) % (obj->k + 1) == obj->front;
}
 
void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->arr);
    free(obj);      //有两层  结构体里面有个数组
}

五、概念选择题

1.下列关于队列的叙述错误的是( )

A.队列可以使用链表实现

B.队列是一种“先入先出”的数据结构

C.数据出队列时一定只影响尾指针

D.数据入队列时一定从尾部插入

2.用无头单链表存储队列,其头指针指向队头结点,尾指针指向队尾结点,则在进行出队操作时( )

A.仅修改队头指针

B.队头、队尾指针都要修改

C.队头、队尾指针都可能要修改

D.仅修改队尾指针

3.下列关于栈的叙述正确的是( )

A.栈是一种“先进先出”的数据结构

B.栈可以使用链表或顺序表来实现

C.栈只能在栈底插入数据

D.栈不能删除数据

4.一个栈的入栈序列为ABCDE,则不可能的出栈序列为( )

A.ABCDE

B.EDCBA

C.DCEBA

D.ECDBA

5.链栈与顺序栈相比,比较明显的优点是( )

A.插入操作更加方便

B.删除操作更加方便

C.入栈时不需要扩容

6.以下不是队列的基本运算的是( )

A.从队尾插入一个新元素

B.从队列中删除队尾元素

C.判断一个队列是否为空

D.读取队头元素的值

7.(多选)下面关于栈和队列的说法中错误的是( )

A.队列和栈通常都使用链表实现

B.队列和栈都只能从两端插入、删除数据

C.队列和栈都不支持随机访问和随机插入

D.队列是“先入先出”,栈是“先入后出”

8.下列关于用栈实现队列的说法中错误的是( )

A.用栈模拟实现队列可以使用两个栈,一个栈模拟入队列,一个栈模拟出队列

B.每次出队列时,都需要将一个栈中的全部元素导入到另一个栈中,然后出栈即可

C.入队列时,将元素直接往模拟入队列的栈中存放即可

D.入队列操作时间复杂度为O(1)

9.下列关于顺序结构实现循环队列的说法,正确的是( )

A.循环队列的长度通常都不固定

B.直接用队头和队尾在同一个位置可以判断循环队列是否为满

C.通过设置计数的方式可以判断队列空或者满

D.循环队列是一种非线性数据结构

10.现有一循环队列,其队头为front,队尾为rear,循环队列长度为N,最多存储N-1个数据。其队内有效长度为( )

A.(rear - front + N) % N + 1

B.(rear - front + N) % N

C.(rear - front) % (N + 1)

D.(rear - front + N) % (N - 1)

答案:

1答案:C

出队操作,一定会影响头指针,如果出队之后,队列为空,会影响尾指针。


2.答案:C


出队操作,一定会修改头指针,如果出队之后,队列为空,需要修改尾指针。


3.答案:B


A错误:栈是一种后进先出的数据结构,队列是先进先出的


B正确:顺序表和链表都可以用来实现栈,不过一般都使用顺序表,因为栈想当于是阉割版的顺序表,只用到了顺序表的尾插和尾删操作,顺序表的尾插和尾删不需要搬移元素效率非常高,故一般都是使用顺序表实现


C错误:栈只能在栈顶进行输入的插入和删除操作


D错误:栈是有入栈和出栈操作,出栈就是从栈中删除一个元素


4.答案:D


此题在校招选择题中出现较频繁,稳妥的做法是画图逐个选项检测,大概率是不会出错的


如果是E先出,说明ABCDE都已经全部入栈,E出栈之后,此时栈顶元素是D,如果再要出栈应该是D,而不应该是C。


5.答案:C


A错误,如果是链栈,一般需要进行头插或者头删操作,而顺序栈一般进行尾插和尾删操作,链表的操作比顺序表复杂,因此使用顺序结构实现栈更简单


B错误,原因参考A


C正确,链式结构实现栈时,每次入栈相当于链表中头插一个节点,没有扩容一说


6.答案:B


队列只能从队头删除元素。


7.答案:AB


A错误:栈是尾部插入和删除,一般使用顺序表实现,队列是头部删除尾部插入,一般使用链表实现


B错误:栈是后进先出,尾部插入和删除;队列是先进先出,尾部插入头部删除


C正确:栈只能访问栈顶元素,不支持随机访问,队列也不支持


D正确:栈和队列的特性


8.答案:B


选项B中,一个栈模拟入队列,一个栈模拟出队列,出队列时直接弹出模拟出队列栈的栈顶元素,当该栈为空时,将模拟入队列栈中所有元素导入即可,不是每次都需要导入元素,故错误


选项A中,栈和队列的特性是相反的,一个栈实现不了队列


选项C中,一个栈模拟入队列,一个栈模拟出队列,入队列时,将元素直接往模拟入队列的栈中存放


选项D中,入队列就是将元素放到栈中,因此时间复杂度就是O(1)


9.答案:C


队列适合使用链表实现,使用顺序结构(即固定的连续空间)实现时会出现假溢出的问题,因此大佬们设计出了循环队列,循环队列就是为了解决顺序结构实现队列假溢出问题的


A错误:循环队列的长度都是固定的


B错误:队头和队尾在同一个位置时 队列可能是空的,也可能是满的,因此无法判断


C正确:设置计数即添加一个字段来记录队列中有效元素的个数,如果队列中有效元素个数等于空间总大小时队列满,如果队列中有效元素个数为0时队列空


D错误:循环队列也是队列的一种,是一种特殊的线性数据结构


10答案:B


有效长度一般是rear-front, 但是循环队列中rear有可能小于front,减完之后可能是负数,所以需要+N,此时结果刚好是队列中有效元素个数,但如果rear大于front,减完之后就是有效元素个数了,再加N后有效长度会超过N,故需要%N。

第三章完。

目录
相关文章
|
4月前
|
机器学习/深度学习 算法 数据可视化
近端策略优化算法PPO的核心概念和PyTorch实现详解
本文深入解析了近端策略优化(PPO)算法的核心原理,并基于PyTorch框架实现了完整的强化学习训练流程。通过Lunar Lander环境展示了算法的全过程,涵盖环境交互、优势函数计算、策略更新等关键模块。内容理论与实践结合,适合希望掌握PPO算法及其实现的读者。
671 2
近端策略优化算法PPO的核心概念和PyTorch实现详解
|
8月前
|
前端开发 Java
java实现队列数据结构代码详解
本文详细解析了Java中队列数据结构的实现,包括队列的基本概念、应用场景及代码实现。队列是一种遵循“先进先出”原则的线性结构,支持在队尾插入和队头删除操作。文章介绍了顺序队列与链式队列,并重点分析了循环队列的实现方式以解决溢出问题。通过具体代码示例(如`enqueue`入队和`dequeue`出队),展示了队列的操作逻辑,帮助读者深入理解其工作机制。
266 1
232.用栈实现队列,225. 用队列实现栈
在232题中,通过两个栈(`stIn`和`stOut`)模拟队列的先入先出(FIFO)行为。`push`操作将元素压入`stIn`,`pop`和`peek`操作则通过将`stIn`的元素转移到`stOut`来实现队列的顺序访问。 225题则是利用单个队列(`que`)模拟栈的后入先出(LIFO)特性。通过多次调整队列头部元素的位置,确保弹出顺序符合栈的要求。`top`操作直接返回队列尾部元素,`empty`判断队列是否为空。 两题均仅使用基础数据结构操作,展示了栈与队列之间的转换逻辑。
|
11月前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
536 77
|
10月前
|
算法 调度 C++
STL——栈和队列和优先队列
通过以上对栈、队列和优先队列的详细解释和示例,希望能帮助读者更好地理解和应用这些重要的数据结构。
246 11
|
10月前
|
DataX
☀☀☀☀☀☀☀有关栈和队列应用的oj题讲解☼☼☼☼☼☼☼
### 简介 本文介绍了三种数据结构的实现方法:用两个队列实现栈、用两个栈实现队列以及设计循环队列。具体思路如下: 1. **用两个队列实现栈**: - 插入元素时,选择非空队列进行插入。 - 移除栈顶元素时,将非空队列中的元素依次转移到另一个队列,直到只剩下一个元素,然后弹出该元素。 - 判空条件为两个队列均为空。 2. **用两个栈实现队列**: - 插入元素时,选择非空栈进行插入。 - 移除队首元素时,将非空栈中的元素依次转移到另一个栈,再将这些元素重新放回原栈以保持顺序。 - 判空条件为两个栈均为空。
|
10月前
|
缓存 监控 算法
内网监控管理软件:PHP 语言队列算法揭秘
在数字化办公环境中,内网监控管理软件对企业的稳定运行和信息安全至关重要。本文深入介绍PHP中的队列算法及其在内网监控软件中的应用,包括监控数据收集、任务调度和日志记录等场景,通过代码示例展示其实现方法。队列算法可提高性能、保证数据顺序并实现异步处理,为企业提供高效的安全保障。
166 1
|
11月前
|
C++
【C++数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】
【数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】(1)遇到左括号:进栈Push()(2)遇到右括号:若栈顶元素为左括号,则出栈Pop();否则返回false。(3)当遍历表达式结束,且栈为空时,则返回true,否则返回false。本关任务:编写一个程序利用栈判断左、右圆括号是否配对。为了完成本关任务,你需要掌握:栈对括号的处理。(1)遇到左括号:进栈Push()开始你的任务吧,祝你成功!测试输入:(()))
253 7
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
822 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
机器学习/深度学习 存储 缓存
数据结构与算法学习十:排序算法介绍、时间频度、时间复杂度、常用时间复杂度介绍
文章主要介绍了排序算法的分类、时间复杂度的概念和计算方法,以及常见的时间复杂度级别,并简单提及了空间复杂度。
553 1
数据结构与算法学习十:排序算法介绍、时间频度、时间复杂度、常用时间复杂度介绍

热门文章

最新文章