目录
[1. 初始化栈](#1. 初始化栈)
[2. 入栈](#2. 入栈)
[3. 出栈](#3. 出栈)
[4. 获取栈顶元素](#4. 获取栈顶元素)
[5. 获取栈中有效元素个数](#5. 获取栈中有效元素个数)
[6. 检测栈是否为空](#6. 检测栈是否为空)
[7. 销毁栈](#7. 销毁栈)
[1. 初始化队列](#1. 初始化队列)
[2. 队尾入队列](#2. 队尾入队列)
[3. 队头出队列](#3. 队头出队列)
[4. 获取队列头部元素](#4. 获取队列头部元素)
[5. 获取队列队尾元素](#5. 获取队列队尾元素)
[6. 获取队列中有效元素个数](#6. 获取队列中有效元素个数)
[7. 检测队列是否为空](#7. 检测队列是否为空)
[8. 销毁队列](#8. 销毁队列)
[方法二:增加一个 size 变量](#方法二:增加一个 size 变量)
[1. 初始化循环队列](#1. 初始化循环队列)
[2. 判断队列是否为空](#2. 判断队列是否为空)
[3. 判断队列是否已满](#3. 判断队列是否已满)
[4. 入队](#4. 入队)
[5. 出队](#5. 出队)
[6. 获取队头元素](#6. 获取队头元素)
[7. 获取队尾元素](#7. 获取队尾元素)
[8. 获取队列中元素个数](#8. 获取队列中元素个数)
[9. 销毁队列](#9. 销毁队列)
栈
栈的概念及结构
栈:一种特殊的线性表 ,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端 称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶


栈的实现
栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的 代价比较小


接口
cpp
//下面是定长的静态栈的结构,实际中一般不实用,所以我们主要实现下面的支持动态增长的栈
typedef int STDataType;
#define N 10
typedef struct Stack
{
STDataType _a[N];
int _top; // 栈顶
}Stack;
// 支持动态增长的栈
typedef int STDataType;
typedef struct Stack
{
STDataType* _a;
int _top; // 栈顶
int _capacity; // 容量
}Stack;
// 初始化栈
void StackInit(Stack* ps);
// 入栈
void StackPush(Stack* ps, STDataType data);
// 出栈
void StackPop(Stack* ps);
// 获取栈顶元素
STDataType StackTop(Stack* ps);
// 获取栈中有效元素个数
int StackSize(Stack* ps);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps);
// 销毁栈
void StackDestroy(Stack* ps);
动态栈(支持扩容)的结构定义
_top 表示下一个可以存放元素的位置,即栈中元素个数。
初始化时 _top = 0;入栈时先放入再 _top++;出栈时直接 _top--。
_capacity 表示数组最多能容纳的元素个数。
当 _top == _capacity 时,需要扩容(通常 2 倍增长)。
cpp
typedef int STDataType; // 栈中元素类型,可修改
typedef struct Stack
{
STDataType* _a; // 指向动态开辟的数组
int _top; // 栈顶位置(通常指向栈顶元素的下一个位置)
int _capacity; // 当前已分配的容量
} Stack;
1. 初始化栈
解释 :
将栈结构体的指针、容量、栈顶都初始化为 0。
注意:_a 先置为 NULL,后续第一次入栈时再动态分配。
时间复杂度 O(1)。
cpp
// 初始化栈
void StackInit(Stack* ps)
{
assert(ps != NULL);
ps->_a = NULL;
ps->_top = 0; // 栈顶初始为 0,表示没有元素
ps->_capacity = 0;
}
2. 入栈
解释 :
将数据压入栈顶。
先检查是否需要扩容:若 _top == _capacity,则扩容(原容量为 0 时分配 4 个空间,否则翻倍)。
然后在 _a[_top] 处放入数据,_top++。
cpp
// 入栈
void StackPush(Stack* ps, STDataType data)
{
assert(ps != NULL);
// 检查容量,满了就扩容
if (ps->_top == ps->_capacity)
{
int newCapacity = (ps->_capacity == 0) ? 4 : ps->_capacity * 2;
STDataType* tmp = (STDataType*)realloc(ps->_a, newCapacity * sizeof(STDataType));
if (tmp == NULL)
{
perror("realloc fail");
return;
}
ps->_a = tmp;
ps->_capacity = newCapacity;
}
// 放入数据
ps->_a[ps->_top] = data;
ps->_top++;
}
3. 出栈
解释 :
删除栈顶元素。
只需将 _top-- 即可(逻辑删除)。
前提是栈非空,需断言检查。
cpp
// 出栈
void StackPop(Stack* ps)
{
assert(ps != NULL);
assert(ps->_top > 0); // 栈不能为空
ps->_top--;
}
4. 获取栈顶元素
解释 :
返回栈顶元素的值(不是删除)。
由于 _top 指向栈顶元素的下一个位置,栈顶元素下标为 _top - 1。
需确保栈非空。
cpp
// 获取栈顶元素
STDataType StackTop(Stack* ps)
{
assert(ps != NULL);
assert(ps->_top > 0);
return ps->_a[ps->_top - 1];
}
5. 获取栈中有效元素个数
解释 :
直接返回 _top 的值,即栈中元素个数。
cpp
// 获取栈中有效元素个数
int StackSize(Stack* ps)
{
assert(ps != NULL);
return ps->_top;
}
6. 检测栈是否为空
解释 :
如果栈为空,返回非零(常用 1);如果不为空,返回 0。
实现上直接返回 _top == 0 的结果。
cpp
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps)
{
assert(ps != NULL);
return ps->_top == 0 ? 1 : 0; // 空返回1,非空返回0
}
7. 销毁栈
解释 :
释放动态申请的数组内存,并将指针置为 NULL,同时重置 _top 和 _capacity。
防止内存泄漏。
cpp
// 销毁栈
void StackDestroy(Stack* ps)
{
assert(ps != NULL);
if (ps->_a != NULL)
{
free(ps->_a);
ps->_a = NULL;
}
ps->_top = 0;
ps->_capacity = 0;
}
代码总
cpp
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int QDataType;
// 队列结点
typedef struct QListNode
{
struct QListNode* _pNext;
QDataType _data;
} QNode;
// 队列结构(含头尾指针和元素个数)
typedef struct Queue
{
QNode* _front; // 队头指针
QNode* _rear; // 队尾指针
int _size; // 队列中元素个数
} Queue;
// 初始化队列
void QueueInit(Queue* q)
{
assert(q != NULL);
q->_front = NULL;
q->_rear = NULL;
q->_size = 0;
}
// 队尾入队列
void QueuePush(Queue* q, QDataType data)
{
assert(q != NULL);
QNode* newNode = (QNode*)malloc(sizeof(QNode));
if (newNode == NULL)
{
perror("malloc fail");
return;
}
newNode->_data = data;
newNode->_pNext = NULL;
if (q->_front == NULL) // 空队列
{
q->_front = newNode;
q->_rear = newNode;
}
else
{
q->_rear->_pNext = newNode;
q->_rear = newNode;
}
q->_size++;
}
// 队头出队列
void QueuePop(Queue* q)
{
assert(q != NULL);
assert(q->_front != NULL); // 队列非空
QNode* del = q->_front;
q->_front = q->_front->_pNext;
if (q->_front == NULL) // 删除后队列为空
q->_rear = NULL;
free(del);
q->_size--;
}
// 获取队列头部元素
QDataType QueueFront(Queue* q)
{
assert(q != NULL);
assert(q->_front != NULL);
return q->_front->_data;
}
// 获取队列队尾元素
QDataType QueueBack(Queue* q)
{
assert(q != NULL);
assert(q->_rear != NULL);
return q->_rear->_data;
}
// 获取队列中有效元素个数
int QueueSize(Queue* q)
{
assert(q != NULL);
return q->_size;
}
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
int QueueEmpty(Queue* q)
{
assert(q != NULL);
return q->_front == NULL ? 1 : 0;
}
// 销毁队列
void QueueDestroy(Queue* q)
{
assert(q != NULL);
QNode* cur = q->_front;
while (cur != NULL)
{
QNode* next = cur->_pNext;
free(cur);
cur = next;
}
q->_front = NULL;
q->_rear = NULL;
q->_size = 0;
}
// 测试入口
int main()
{
Queue q;
QueueInit(&q);
printf("入队 10, 20, 30\n");
QueuePush(&q, 10);
QueuePush(&q, 20);
QueuePush(&q, 30);
printf("队头: %d, 队尾: %d, 大小: %d\n",
QueueFront(&q), QueueBack(&q), QueueSize(&q)); // 队头: 10, 队尾: 30, 大小: 3
printf("出队\n");
QueuePop(&q);
printf("队头: %d, 队尾: %d, 大小: %d\n",
QueueFront(&q), QueueBack(&q), QueueSize(&q)); // 队头: 20, 队尾: 30, 大小: 2
printf("再入队 40, 50\n");
QueuePush(&q, 40);
QueuePush(&q, 50);
printf("当前队列: ");
while (!QueueEmpty(&q))
{
printf("%d ", QueueFront(&q));
QueuePop(&q);
}
printf("\n");
printf("队列空: %s\n", QueueEmpty(&q) ? "是" : "否"); // 队列空: 是
QueueDestroy(&q);
return 0;
}
队列
队列的概念及结构
队列:只允许在一端进行插入 数据操作,在另一端进行删除 数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out)
入队列:进行插入操作的一端称为队尾
出队列:进行删除操作的一端称为队头

队列的实现
队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数 组头上出数据,效率会比较低。

接口
cpp
typedef int QDataType;
// 队列结点
typedef struct QListNode
{
struct QListNode* _pNext;
QDataType _data;
} QNode;
// 队列结构(含头尾指针和元素个数)
typedef struct Queue
{
QNode* _front; // 队头指针
QNode* _rear; // 队尾指针
int _size; // 队列中元素个数
} Queue;
// 初始化队列
void QueueInit(Queue* q);
// 队尾入队列
void QueuePush(Queue* q, QDataType data);
// 队头出队列
void QueuePop(Queue* q);
// 获取队列头部元素
QDataType QueueFront(Queue* q);
// 获取队列队尾元素
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
int QueueEmpty(Queue* q);
// 销毁队列
void QueueDestroy(Queue* q);
1. 初始化队列
解释 :
将队列的头尾指针置为 NULL,元素个数置为 0。
cpp
void QueueInit(Queue* q)
{
assert(q != NULL);
q->_front = NULL;
q->_rear = NULL;
q->_size = 0;
}
2. 队尾入队列
解释 :
在链表尾部插入新结点。
先动态申请新结点,赋值。
如果队列为空(_front == NULL),则头尾都指向新结点;否则将当前尾结点的 _pNext 指向新结点,再更新 _rear 指向新结点。最后 _size++。
cpp
void QueuePush(Queue* q, QDataType data)
{
assert(q != NULL);
QNode* newNode = (QNode*)malloc(sizeof(QNode));
if (newNode == NULL)
{
perror("malloc fail");
return;
}
newNode->_data = data;
newNode->_pNext = NULL;
if (q->_front == NULL) // 空队列
{
q->_front = newNode;
q->_rear = newNode;
}
else
{
q->_rear->_pNext = newNode;
q->_rear = newNode;
}
q->_size++;
}
3. 队头出队列
解释 :
删除队头结点。
需保证队列非空。
保存队头结点,将 _front 指向下一个结点。如果队头成为 NULL(即队列变空),则 _rear 也要置为 NULL。释放原队头结点,_size--。
cpp
void QueuePop(Queue* q)
{
assert(q != NULL);
assert(q->_front != NULL); // 队列非空
QNode* del = q->_front;
q->_front = q->_front->_pNext;
if (q->_front == NULL) // 删除后队列为空
q->_rear = NULL;
free(del);
q->_size--;
}
4. 获取队列头部元素
解释 :
返回队头结点的数据,但不删除。需保证队列非空。
cpp
QDataType QueueFront(Queue* q)
{
assert(q != NULL);
assert(q->_front != NULL);
return q->_front->_data;
}
5. 获取队列队尾元素
解释 :
返回队尾结点的数据。需保证队列非空。
cpp
QDataType QueueBack(Queue* q)
{
assert(q != NULL);
assert(q->_rear != NULL);
return q->_rear->_data;
}
6. 获取队列中有效元素个数
解释 :
直接返回 _size 字段的值。
cpp
int QueueSize(Queue* q)
{
assert(q != NULL);
return q->_size;
}
7. 检测队列是否为空
解释 :
如果队列为空返回非零(通常 1),否则返回 0。可以判断 _front == NULL 或 _size == 0。
cpp
int QueueEmpty(Queue* q)
{
assert(q != NULL);
return q->_front == NULL ? 1 : 0;
}
8. 销毁队列
解释 :
释放链表中所有结点,防止内存泄漏。
遍历链表,依次 free 每个结点,最后将头尾指针置 NULL,大小置 0。
cpp
void QueueDestroy(Queue* q)
{
assert(q != NULL);
QNode* cur = q->_front;
while (cur != NULL)
{
QNode* next = cur->_pNext;
free(cur);
cur = next;
}
q->_front = NULL;
q->_rear = NULL;
q->_size = 0;
}
代码总
cpp
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int QDataType;
typedef struct QListNode
{
struct QListNode* _pNext;
QDataType _data;
} QNode;
typedef struct Queue
{
QNode* _front;
QNode* _rear;
int _size;
} Queue;
void QueueInit(Queue* q);
void QueuePush(Queue* q, QDataType data);
void QueuePop(Queue* q);
QDataType QueueFront(Queue* q);
QDataType QueueBack(Queue* q);
int QueueSize(Queue* q);
int QueueEmpty(Queue* q);
void QueueDestroy(Queue* q);
// 实现部分
int main()
{
Queue q;
QueueInit(&q);
printf("入队 10, 20, 30\n");
QueuePush(&q, 10);
QueuePush(&q, 20);
QueuePush(&q, 30);
printf("队头: %d, 队尾: %d, 大小: %d\n",
QueueFront(&q), QueueBack(&q), QueueSize(&q)); // 队头: 10, 队尾: 30, 大小: 3
printf("出队\n");
QueuePop(&q);
printf("队头: %d, 队尾: %d, 大小: %d\n",
QueueFront(&q), QueueBack(&q), QueueSize(&q)); // 队头: 20, 队尾: 30, 大小: 2
printf("再入队 40, 50\n");
QueuePush(&q, 40);
QueuePush(&q, 50);
printf("当前队列: ");
while (!QueueEmpty(&q))
{
printf("%d ", QueueFront(&q));
QueuePop(&q);
}
printf("\n");
printf("队列空: %s\n", QueueEmpty(&q) ? "是" : "否"); // 队列空: 是
QueueDestroy(&q);
return 0;
}
循环队列
扩展了解一下,实际中我们有时还会使用一种队列叫循环队列。Linux中的生产者消费者模型就会使用循环队列。环形队列可以使用数组实现,也可以使用循环链表实现。
为什么需要循环队列
普通队列(顺序存储)如果用数组实现,入队时 rear 后移,出队时 front 后移。但经过多次出队后,数组前面会出现无法再利用的空闲位置,造成"假溢出"------数组还有空位,但 rear 已经指向末尾,无法再入队。
循环队列将数组的首尾逻辑上连接起来,当 rear 到达数组末尾时,下一步就回到开头,从而复用空闲空间。

循环队列的结构(数组实现)
一个固定大小的数组
data[0..k-1]两个整型下标:
front指向队头元素的位置,rear指向队尾元素的下一个位置(或指向队尾元素,具体取决于实现)初始状态:
front = rear = 0,队列为空
常用约定:
入队:将元素放入
rear位置,rear = (rear + 1) % capacity出队:取出
front位置元素,front = (front + 1) % capacity

区分队空和队满
若使用 front == rear 表示空,那么满时也会出现 front == rear(因为绕一圈回来了),造成冲突。
解决方法(二选一):
方法一:牺牲一个存储单元
约定当
(rear + 1) % capacity == front时,认为队列已满。此时数组中还有一个空位,但不使用,用于区分空和满。
队列中最多存放
capacity - 1个元素。
方法二:增加一个 size 变量
在结构体中增加一个
int size,入队时size++,出队时size--。判断空:
size == 0;判断满:size == capacity。优点:不浪费空间;缺点:多维护一个变量。
循环队列的基本操作(以牺牲一个单元的方法为例)
数据结构定义:
cpp
typedef struct {
int* data; // 动态数组
int front; // 队头下标(指向队头元素)
int rear; // 队尾下标(指向队尾元素的下一个位置)
int capacity; // 数组总长度(实际容量 = capacity - 1)
} CircularQueue;
1. 初始化循环队列
解释 :
创建一个大小为 k 的循环队列(用户期望最多存放 k 个元素)。为了区分空和满,实际数组长度需要 k+1。
动态分配数组空间,将 front 和 rear 均初始化为 0。
cpp
void cqInit(CircularQueue* q, int k) {
// 分配 k+1 个整型空间(多一个用于判满)
q->data = (int*)malloc(sizeof(int) * (k + 1));
// 初始时队头和队尾重合,队列为空
q->front = 0;
q->rear = 0;
// 记录数组总长度
q->capacity = k + 1;
}
2. 判断队列是否为空
解释 :
当 front == rear 时,队列中没有元素。
cpp
int cqIsEmpty(CircularQueue* q) {
// 队头与队尾重合表示空队列
return q->front == q->rear;
}
3. 判断队列是否已满
解释 :
当 (rear + 1) % capacity == front 时,队列已满。此时如果再入队,会覆盖未出队的元素,因此不允许入队。
cpp
int cqIsFull(CircularQueue* q) {
// 队尾的下一个位置是队头,则队列已满(牺牲一个单元)
return (q->rear + 1) % q->capacity == q->front;
}
4. 入队
解释 :
若队列已满则操作失败。
否则将元素放入 data[rear] 位置,然后 rear 后移一位(取模)。
cpp
int cqEnQueue(CircularQueue* q, int value) {
// 先检查队列是否已满
if (cqIsFull(q))
return -1; // 入队失败
// 将新元素放到当前 rear 位置
q->data[q->rear] = value;
// rear 后移一位,如果到末尾则绕回开头(取模)
q->rear = (q->rear + 1) % q->capacity;
return 0; // 入队成功
}
5. 出队
解释 :
若队列为空则操作失败。
否则取出 data[front] 的值(通过输出参数返回),然后 front 后移一位(取模)。
cpp
int cqDeQueue(CircularQueue* q, int* out) {
// 先检查队列是否为空
if (cqIsEmpty(q))
return -1; // 出队失败
// 取出队头元素
*out = q->data[q->front];
// front 后移一位,取模实现环形
q->front = (q->front + 1) % q->capacity;
return 0; // 出队成功
}
6. 获取队头元素
解释 :
只读取队头元素的值,不出队。需保证队列非空。
cpp
int cqFront(CircularQueue* q, int* out) {
// 队列为空则无法获取
if (cqIsEmpty(q))
return -1;
// 将队头元素通过输出参数返回
*out = q->data[q->front];
return 0;
}
7. 获取队尾元素
解释 :
队尾元素位于 rear 的前一个位置(因为 rear 指向下一个空位)。需要处理 rear 为 0 时的回绕情况。
cpp
int cqRear(CircularQueue* q, int* out) {
// 队列为空则无法获取
if (cqIsEmpty(q))
return -1;
// 计算队尾下标: (rear - 1 + capacity) % capacity
int tailIndex = (q->rear - 1 + q->capacity) % q->capacity;
*out = q->data[tailIndex];
return 0;
}
8. 获取队列中元素个数
解释 :
由于队列是环形的,元素个数计算公式为:(rear - front + capacity) % capacity。
cpp
int cqSize(CircularQueue* q) {
// 环形队列长度计算公式
return (q->rear - q->front + q->capacity) % q->capacity;
}
9. 销毁队列
解释 :
释放动态数组内存,并将指针置空,相关变量归零,防止内存泄漏。
cpp
void cqDestroy(CircularQueue* q) {
// 释放数组内存
free(q->data);
// 将指针置空,避免野指针
q->data = NULL;
// 重置其他成员
q->front = 0;
q->rear = 0;
q->capacity = 0;
}
代码总
cpp
#include <stdio.h>
#include <stdlib.h>
// 循环队列结构定义(牺牲一个单元判满)
typedef struct {
int* data; // 动态数组
int front; // 队头下标(指向队头元素)
int rear; // 队尾下标(指向队尾元素的下一个位置)
int capacity; // 数组总长度(实际有效容量 = capacity - 1)
} CircularQueue;
// 初始化循环队列
void cqInit(CircularQueue* q, int k) {
// 分配 k+1 个空间,留一个用于判满
q->data = (int*)malloc(sizeof(int) * (k + 1));
q->front = 0;
q->rear = 0;
q->capacity = k + 1;
}
// 判断队列是否为空
int cqIsEmpty(CircularQueue* q) {
return q->front == q->rear;
}
// 判断队列是否已满
int cqIsFull(CircularQueue* q) {
return (q->rear + 1) % q->capacity == q->front;
}
// 入队
int cqEnQueue(CircularQueue* q, int value) {
if (cqIsFull(q)) {
return -1; // 队列已满,入队失败
}
q->data[q->rear] = value;
q->rear = (q->rear + 1) % q->capacity;
return 0;
}
// 出队
int cqDeQueue(CircularQueue* q, int* out) {
if (cqIsEmpty(q)) {
return -1; // 队列为空,出队失败
}
*out = q->data[q->front];
q->front = (q->front + 1) % q->capacity;
return 0;
}
// 获取队头元素(不出队)
int cqFront(CircularQueue* q, int* out) {
if (cqIsEmpty(q)) {
return -1;
}
*out = q->data[q->front];
return 0;
}
// 获取队尾元素(不删除)
int cqRear(CircularQueue* q, int* out) {
if (cqIsEmpty(q)) {
return -1;
}
// 队尾元素在 rear 的前一个位置,处理绕回
int tailIndex = (q->rear - 1 + q->capacity) % q->capacity;
*out = q->data[tailIndex];
return 0;
}
// 返回队列中实际元素个数
int cqSize(CircularQueue* q) {
return (q->rear - q->front + q->capacity) % q->capacity;
}
// 销毁队列,释放内存
void cqDestroy(CircularQueue* q) {
free(q->data);
q->data = NULL;
q->front = q->rear = q->capacity = 0;
}
// 测试入口
int main() {
CircularQueue q;
cqInit(&q, 3); // 最多存放 3 个元素
printf("入队 1, 2, 3\n");
cqEnQueue(&q, 1);
cqEnQueue(&q, 2);
cqEnQueue(&q, 3);
int val;
cqFront(&q, &val);
printf("队头: %d, 队尾: %d, 大小: %d\n", val, (cqRear(&q, &val), val), cqSize(&q)); // 队头: 1, 队尾: 3, 大小: 3
printf("再入队 4(应失败)\n");
int ret = cqEnQueue(&q, 4);
printf("入队结果: %d\n", ret); // 入队结果: -1
printf("出队\n");
cqDeQueue(&q, &val);
printf("出队元素: %d\n", val); // 出队元素: 1
cqFront(&q, &val);
printf("新队头: %d, 大小: %d\n", val, cqSize(&q)); // 新队头: 2, 大小: 2
printf("再入队 4\n");
cqEnQueue(&q, 4);
cqRear(&q, &val);
printf("队尾: %d, 大小: %d\n", val, cqSize(&q)); // 队尾: 4, 大小: 3
printf("队列元素依次出队: ");
while (!cqIsEmpty(&q)) {
cqDeQueue(&q, &val);
printf("%d ", val);
}
printf("\n"); // 输出: 2 3 4
cqDestroy(&q);
return 0;
}
栈和队列面试题
-
括号匹配问题。20. 有效的括号 - 力扣(LeetCode)
-
用队列实现栈。225. 用队列实现栈 - 力扣(LeetCode)
-
用栈实现队列。232. 用栈实现队列 - 力扣(LeetCode)
-
设计循环队列。622. 设计循环队列 - 力扣(LeetCode)
概念选择题
1. 一个栈的初始状态为空。现将元素1、2、3、4、5、A、B、C、D、E依次入栈,然后再依次出栈,则元素出栈的顺序是( )。
A 12345ABCDE
B EDCBA54321
C ABCDE12345
D 54321EDCBA
2. 若进栈序列为 1,2,3,4,进栈过程中可以出栈,则下列不可能的一个出栈序列是( )。
A 1,4,3,2
B 2,3,4,1
C 3,1,4,2
D 3,4,2,1
3. 循环队列的存储空间为 Q(1:100),初始状态为 front=rear=100。经过一系列正常的入队与退队操作后,front=rear=99,则循环队列中的元素个数为( )。
A 1
B 2
C 99
D 0 或者 100
4. 以下( )不是队列的基本运算?
A 从队尾插入一个新元素
B 从队列中删除第1个元素
C 判断一个队列是否为空
D 读取队头元素的值
5. 现有一循环队列,其队头指针为 front,队尾指针为 rear;循环队列长度为 N。其队内有效长度为?(假设队头不存放数据)
A (rear - front + N) % N + 1
B (rear - front + N) % N
C (rear - front) % (N + 1)
D (rear - front + N) % (N - 1)