栈与队列OJ题精选,数据结构的实践应用

news/2025/1/11 5:31:24/

系列文章目录

🎈 🎈 我的CSDN主页:OTWOL的主页,欢迎!!!👋🏼👋🏼
🎉🎉我的C语言初阶合集:C语言初阶合集,希望能帮到你!!!😍 😍
🔍🔍我的C语言进阶合集:我的C语言进阶合集,期待你的点击!!!🌈🌈
🎉🎉我的数据结构与算法合集数据结构与算法合集,点进去看看吧!!! 🎊🎊
😍 👋🏼🎉🎊创作不易,欢迎大家留言、点赞加收藏!!! 🥳😁😍

文章目录

  • 系列文章目录
  • 一、有效的括号
    • (1)题目描述
    • (2)代码示例
  • 二、用队列实现栈
    • (1)题目描述
    • (2)代码示例
  • 三、用栈实现队列
    • (1)题目描述
    • (2)代码示例
  • 四、设计循环队列
    • (1)题目描述
    • (2)代码示例
  • END

一、有效的括号

(1)题目描述

下面是该题的链接🔗

有效的括号

(2)代码示例

写一个 顺序 栈:

// 定义一个类型别名,将 char 类型重命名为 STDataType,方便后续代码中使用,提高代码可读性和可维护性
typedef char STDataType;// 定义一个结构体,用于表示栈结构
// 其中包含一个指向存储栈元素的数组指针 a,栈顶索引 top,以及栈的容量 capacity
typedef struct Stack
{STDataType* a;int top;int capacity;
}ST;// 初始化栈的函数
// 接收一个指向栈结构体的指针 ps,用于对栈进行初始化操作
void STInit(ST* ps)
{// 断言传入的指针不为空,若为空则表示出现了错误情况,因为后续要通过该指针操作栈结构体assert(ps);// 初始设置栈的容量为 4ps->capacity = 4;// 初始时 栈顶索引 为 0,表示栈为空ps->top = 0;// 动态分配内存来存储栈元素,根据初始容量分配相应大小的内存空间// 将分配的内存地址强转为 STDataType* 类型后赋值给临时指针 tmpSTDataType* tmp = (STDataType*)malloc(ps->capacity * sizeof(STDataType));// 如果内存分配失败(返回的指针为NULL)if (tmp == NULL){// 输出错误信息,提示malloc分配内存失败perror("malloc fail");// 直接返回,不再进行后续初始化操作return;}// 将成功分配内存的地址赋值给栈结构体中的数组指针 a,使得栈可以使用这块内存来存储元素ps->a = tmp;
}// 销毁栈的函数,用于释放栈所占用的内存资源等清理工作
void STDestroy(ST* ps)
{// 断言传入的指针不为空,确保操作的合法性assert(ps);// 释放栈中存储元素的数组所占用的内存空间free(ps->a);// 将栈结构体中的数组指针 a 置为 NULL,防止出现野指针情况ps->a = NULL;// 将 栈顶索引 和 容量 都重置为 0,恢复到初始的 “空” 状态表示ps->top = ps->capacity = 0;
}// 向栈中压入元素的函数
// 接收一个指向栈结构体的指针 ps 以及要压入的元素 x(类型为 STDataType)
void STPush(ST* ps, STDataType x)
{// 断言传入的指针不为空,保证后续操作能正常进行assert(ps);// 检查栈是否已满(即当前元素个数等于栈的容量),如果已满则需要进行扩容操作if (ps->capacity == ps->top){// 使用 realloc 对栈的存储空间进行扩容,扩容为原来的 2 倍大小// 将重新分配后的内存地址强转为STDataType*类型后赋值给临时指针 tmpSTDataType* tmp = (STDataType*)realloc(ps->a, ps->capacity * 2 * sizeof(STDataType));// 如果扩容失败(返回的指针为 NULL)if (tmp == NULL){// 输出错误信息,提示 realloc 扩容失败perror("realloc fail");// 直接返回,不进行元素压入操作了return;}// 将扩容后成功分配的内存地址赋值给栈结构体中的数组指针 a,更新栈的存储空间ps->a = tmp;// 将栈的容量更新为原来的 2 倍ps->capacity *= 2;}// 将元素 x 存放到栈顶位置,然后栈顶索引 top 自增 1,指向下一个空闲位置ps->a[ps->top++] = x;
}// 判断栈是否为空的函数
// 接收一个指向栈结构体的指针 ps
bool STEmpty(ST* ps)
{// 断言传入的指针不为空,确保操作的合法性assert(ps);// 通过判断 栈顶索引 是否为 0 来确定栈是否为空,返回相应的布尔值return (ps->top == 0);
}// 获取栈中元素个数的函数
// 接收一个指向栈结构体的指针 ps
int STSize(ST* ps)
{// 断言传入的指针不为空,确保操作的合法性assert(ps);// 直接返回 栈顶索引 的值,因为 栈顶索引 的值就代表了当前栈中元素的个数return (ps->top);
}// 弹出栈顶元素的函数(只是将 栈顶索引 减 1,逻辑上表示栈顶元素被移除了)
// 接收一个指向栈结构体的指针 ps
void STPop(ST* ps)
{// 断言传入的指针不为空,保证操作的合法性assert(ps);// 断言栈不能为空,若为空则不能进行弹出操作,否则会出现错误情况assert(!STEmpty(ps));// 将 栈顶索引 减 1,实现逻辑上的弹出栈顶元素操作--ps->top;
}// 获取栈顶元素的函数(但不会弹出栈顶元素)
// 接收一个指向栈结构体的指针 ps
STDataType STTop(ST* ps)
{// 断言传入的指针不为空,保证操作的合法性assert(ps);// 断言栈不能为空,若为空则没有栈顶元素可供获取,会出现错误情况assert(!STEmpty(ps));// 返回栈顶元素的值(通过 栈顶索引 减 1 的索引来获取,因为数组下标从 0 开始)return (ps->a[ps->top - 1]);
}

判断有效括号

// 判断给定的括号字符串s是否有效(左右括号匹配)的函数
bool isValid(char* s) 
{// 创建一个栈结构体实例 stST st;// 初始化栈stSTInit(&st);// 遍历字符串s,直到遇到字符串结束符'\0'while(*s){// 如果当前字符是左括号('(' 或 '[' 或 '{')if(*s == '(' || *s == '[' || *s == '{'){// 将该左括号压入栈st中STPush(&st,*s);}else{// 如果栈为空,说明没有与之匹配的左括号了,括号字符串无效if(STEmpty(&st)){// 销毁栈,释放资源STDestroy(&st);return false;}// 如果栈不为空,说明有对应的左括号else{// 获取栈顶元素STDataType top = STTop(&st);// 弹出栈顶元素(因为已经获取到了,并且后续要检查匹配情况,所以可以弹出)STPop(&st);// 检查当前右括号与获取到的栈顶左括号是否匹配,如果不匹配则括号字符串无效if(     *s == ')' && top!= '('|| *s == ']' && top!= '['|| *s == '}' && top!= '{'){// 销毁栈,释放资源STDestroy(&st);return false;}}}// 移动指针到下一个字符继续检查++s;}// 遍历完字符串后,检查栈是否为空,如果为空则说明所有括号都匹配,返回true,否则返回falsebool ret = STEmpty(&st);// 销毁栈,释放资源STDestroy(&st);return ret;
}

二、用队列实现栈

(1)题目描述

下面是该题的链接🔗

用队列实现栈

(2)代码示例

写一个 链式 队列:

// 定义一个类型别名,将 int 类型重命名为 QDataType,方便后续代码中使用,增强代码可读性和可维护性
typedef int QDataType;// 定义结构体 QNode,表示队列中的节点
// 其中包含一个数据域 data,用于存储节点的数据(类型为 QDataType,即int)
// 以及一个指针域 next,用于指向下一个节点,从而构成链式结构
typedef struct QNode
{QDataType data;struct QNode* next;
}QNode;// 定义结构体 Queue,用于表示队列
// 包含指向队头节点的指针 head、指向队尾节点的指针 tail,以及记录队列中元素个数的 size
typedef struct Queue
{QNode* head;QNode* tail;int size;
}Queue;// 初始化队列的函数
// 接收一个指向 Queue 结构体的指针 q,用于对队列进行初始化操作
void QInit(Queue* q)
{// 断言传入的指针不为空,若为空则表示出现了错误情况,因为后续要通过该指针操作队列结构体assert(q);// 初始化时,队头和队尾指针都设为 NULL,表示队列为空q->head = q->tail = NULL;// 队列中元素个数初始化为 0q->size = 0;
}// 销毁队列的函数,用于释放队列及其节点所占用的内存资源等清理工作
void QDestroy(Queue* q)
{// 断言传入的指针不为空,确保操作的合法性assert(q);// 从队头开始遍历队列的每个节点QNode* cur = q->head;while (cur){// 保存当前节点的下一个节点指针,方便后续释放当前节点内存后能继续遍历下一个节点QNode* next = cur->next;// 释放当前节点所占用的内存空间free(cur);// 将指针更新为下一个节点的指针,继续循环释放下一个节点内存cur = next;}// 释放完所有节点后,将队头和队尾指针都置为 NULL,表示队列已被销毁q->head = q->tail = NULL;// 队列元素个数也重置为 0q->size = 0;
}// 判断队列是否为空的函数
// 接收一个指向 Queue 结构体的指针 q
bool QEmpty(Queue* q)
{// 断言传入的指针不为空,确保操作的合法性assert(q);// 通过判断队列元素个数是否为 0 来确定队列是否为空,返回相应的布尔值return (q->size == 0);
}// 获取队列中元素个数的函数
// 接收一个指向 Queue 结构体的指针 q
int QSize(Queue* q)
{// 断言传入的指针不为空,确保操作的合法性assert(q);// 直接返回队列中元素个数 size 的值return (q->size);
}// 向队列中插入元素的函数(队尾插入操作)
// 接收一个指向 Queue 结构体的指针 q 以及要插入的元素 x(类型为 QDataType,即 int)
void QPush(Queue* q, QDataType x)
{// 断言传入的指针不为空,保证后续操作能正常进行assert(q);// 申请一个新的队列节点空间QNode* newnode = (QNode*)malloc(sizeof(QNode));// 如果内存分配失败(返回的指针为 NULL)if (newnode == NULL){// 输出错误信息,提示 malloc 分配内存失败perror("malloc fail");// 直接返回,不再进行元素插入操作return;}// 给新节点的数据域赋值为要插入的元素 xnewnode->data = x;// 新节点的 next 指针初始化为 NULL,因为它目前是队尾节点,后面没有其他节点newnode->next = NULL;// 如果队列当前为空(队头指针为 NULL)if (q->head == NULL){// 断言队尾指针也必然为 NULL,确保队列状态的一致性assert(q->tail == NULL);// 将队头和队尾指针都指向新创建的节点,因为此时队列中只有这一个节点q->head = q->tail = newnode;}else{// 将当前队尾节点的 next 指针指向新节点,即将新节点连接到队列末尾q->tail->next = newnode;// 更新队尾指针为新插入的节点,使其始终指向队尾q->tail = q->tail->next;}// 队列元素个数自增 1,表示插入了一个新元素++q->size;
}// 从队列中弹出元素的函数(队头删除操作)
// 接收一个指向 Queue 结构体的指针 q
void QPop(Queue* q)
{// 断言传入的指针不为空,保证操作的合法性assert(q);// 断言队列不能为空,若为空则不能进行弹出操作,否则会出现错误情况assert(!QEmpty(q));// 进行队头删除操作// 如果队列中只有一个元素(元素个数为 1)if (q->size == 1){// 释放队头节点所占用的内存空间free(q->head);// 将队头和队尾指针都置为 NULL,因为此时队列已为空q->head = q->tail = NULL;}else{// 保存队头节点的下一个节点指针,方便后续更新队头指针QNode* next = q->head->next;// 释放当前队头节点所占用的内存空间free(q->head);// 更新队头指针为之前保存的下一个节点指针,实现队头节点的删除q->head = next;}// 队列元素个数自减 1,表示弹出了一个元素--q->size;
}// 获取队列队头元素的函数
// 接收一个指向 Queue 结构体的指针 q
QDataType QFront(Queue* q)
{// 断言传入的指针不为空,保证操作的合法性assert(q);// 断言队列不能为空,若为空则没有队头元素可供获取,会出现错误情况assert(!QEmpty(q));// 返回队头节点的数据域的值,即获取队头元素return (q->head->data);
}// 获取队列队尾元素的函数(但不会删除队尾元素)
// 接收一个指向 Queue 结构体的指针 q
QDataType QBack(Queue* q)
{// 断言传入的指针不为空,保证操作的合法性assert(q);// 断言队列不能为空,若为空则没有队尾元素可供获取,会出现错误情况assert(!QEmpty(q));// 返回队尾节点的数据域的值,即获取队尾元素return (q->tail->data);
}

用队列实现栈

// 定义一个结构体 MyStack,它内部包含两个 Queue 类型的成员 q1 和 q2
// 这里是通过组合两个队列来模拟实现栈的功能
typedef struct 
{Queue q1;Queue q2;
} MyStack;// 创建一个 MyStack 结构体实例的函数,并进行初始化操作
// 返回指向新创建的 MyStack 结构体的指针
MyStack* myStackCreate() 
{// 动态分配内存来存储一个 MyStack 结构体大小的空间MyStack* obj = (MyStack*)malloc(sizeof(MyStack));// 如果内存分配失败(返回的指针为 NULL)if(obj == NULL){// 输出错误信息,提示 malloc 分配内存失败perror("malloc fail");// 返回 NULL,表示创建失败return NULL;}// 初始化 MyStack 结构体中的 q1 队列QInit(&(obj->q1));// 初始化 MyStack 结构体中的 q2 队列QInit(&(obj->q2));// 返回指向初始化好的 MyStack 结构体的指针return obj;
}// 向模拟栈( MyStack 结构体表示)中压入元素的函数
// 参数 obj 是指向 MyStack 结构体的指针,x 是要压入的元素(int 类型)
void myStackPush(MyStack* obj, int x) 
{// 如果 q1 队列不为空if(!QEmpty(&(obj->q1))){// 将元素 x 压入q1队列QPush(&(obj->q1),x);}else{// 否则将元素 x 压入 q2 队列QPush(&(obj->q2),x);}
}// 从模拟栈( MyStack 结构体表示)中弹出元素的函数
// 参数 obj 是指向 MyStack 结构体的指针,返回弹出的栈顶元素( int 类型)
int myStackPop(MyStack* obj) 
{// 先假设 q1 队列为空队列,q2 队列为非空队列(后续会根据实际情况调整)Queue* emptyq = &(obj->q1);Queue* noemptyq = &(obj->q2);// 如果实际情况是 q1 队列不为空if(!QEmpty(&(obj->q1))){// 则交换假设,让 q2 队列为空队列,q1 队列为非空队列emptyq = &(obj->q2);noemptyq = &(obj->q1); }// 将非空队列(除了最后一个元素外)中的元素依次转移到空队列中while(QSize(noemptyq) > 1){// 取出 非空队列 的队头元素,并将其压入 空队列QPush(emptyq,QFront(noemptyq));// 弹出非空队列的队头元素(完成转移操作)QPop(noemptyq);}// 获取非空队列此时剩下的最后一个元素(即 栈顶 元素)int top = QFront(noemptyq);// 弹出这个最后元素,完成 出栈 操作QPop(noemptyq);// 返回弹出的 栈顶元素return top;
}// 获取模拟栈( MyStack 结构体表示)的栈顶元素的函数(但不弹出元素)
// 参数 obj 是指向 MyStack 结构体的指针,返回栈顶元素( int 类型)
int myStackTop(MyStack* obj) 
{// 如果 q1 队列不为空if(!QEmpty(&(obj->q1))){// 返回 q1 队列的队尾元素作为栈顶元素(因为模拟栈的栈顶元素相当于非空队列的队尾元素)return QBack(&(obj->q1));}    else{// 否则返回 q2 队列的队尾元素作为栈顶元素return QBack(&(obj->q2));}
}// 判断模拟栈( MyStack 结构体表示)是否为空的函数
// 参数 obj 是指向 MyStack 结构体的指针,返回布尔值表示栈是否为空
bool myStackEmpty(MyStack* obj) 
{// 当 q1 队列和 q2 队列都为空时,模拟栈为空,返回 true,否则返回falsereturn QEmpty(&(obj->q1)) && QEmpty(&(obj->q2));    
}// 释放模拟栈( MyStack 结构体表示)所占用的内存资源的函数
// 参数 obj 是指向 MyStack 结构体的指针
void myStackFree(MyStack* obj) 
{// 先销毁 MyStack 结构体中的 q1 队列,释放其占用的内存QDestroy(&(obj->q1));// 再销毁 MyStack 结构体中的 q2 队列,释放其占用的内存QDestroy(&(obj->q2));// 释放 MyStack 结构体本身所占用的内存空间free(obj);
}

三、用栈实现队列

(1)题目描述

下面是该题的链接🔗

用栈实现队列

(2)代码示例

写一个 顺序 栈:

// 定义一个类型别名,将 char 类型重命名为 STDataType,方便后续代码中使用,提高代码可读性和可维护性
typedef char STDataType;// 定义一个结构体,用于表示栈结构
// 其中包含一个指向存储栈元素的数组指针 a,栈顶索引 top,以及栈的容量 capacity
typedef struct Stack
{STDataType* a;int top;int capacity;
}ST;// 初始化栈的函数
// 接收一个指向栈结构体的指针 ps,用于对栈进行初始化操作
void STInit(ST* ps)
{// 断言传入的指针不为空,若为空则表示出现了错误情况,因为后续要通过该指针操作栈结构体assert(ps);// 初始设置栈的容量为 4ps->capacity = 4;// 初始时 栈顶索引 为 0,表示栈为空ps->top = 0;// 动态分配内存来存储栈元素,根据初始容量分配相应大小的内存空间// 将分配的内存地址强转为 STDataType* 类型后赋值给临时指针 tmpSTDataType* tmp = (STDataType*)malloc(ps->capacity * sizeof(STDataType));// 如果内存分配失败(返回的指针为NULL)if (tmp == NULL){// 输出错误信息,提示malloc分配内存失败perror("malloc fail");// 直接返回,不再进行后续初始化操作return;}// 将成功分配内存的地址赋值给栈结构体中的数组指针 a,使得栈可以使用这块内存来存储元素ps->a = tmp;
}// 销毁栈的函数,用于释放栈所占用的内存资源等清理工作
void STDestroy(ST* ps)
{// 断言传入的指针不为空,确保操作的合法性assert(ps);// 释放栈中存储元素的数组所占用的内存空间free(ps->a);// 将栈结构体中的数组指针 a 置为 NULL,防止出现野指针情况ps->a = NULL;// 将 栈顶索引 和 容量 都重置为 0,恢复到初始的 “空” 状态表示ps->top = ps->capacity = 0;
}// 向栈中压入元素的函数
// 接收一个指向栈结构体的指针 ps 以及要压入的元素 x(类型为 STDataType)
void STPush(ST* ps, STDataType x)
{// 断言传入的指针不为空,保证后续操作能正常进行assert(ps);// 检查栈是否已满(即当前元素个数等于栈的容量),如果已满则需要进行扩容操作if (ps->capacity == ps->top){// 使用 realloc 对栈的存储空间进行扩容,扩容为原来的 2 倍大小// 将重新分配后的内存地址强转为STDataType*类型后赋值给临时指针 tmpSTDataType* tmp = (STDataType*)realloc(ps->a, ps->capacity * 2 * sizeof(STDataType));// 如果扩容失败(返回的指针为 NULL)if (tmp == NULL){// 输出错误信息,提示 realloc 扩容失败perror("realloc fail");// 直接返回,不进行元素压入操作了return;}// 将扩容后成功分配的内存地址赋值给栈结构体中的数组指针 a,更新栈的存储空间ps->a = tmp;// 将栈的容量更新为原来的 2 倍ps->capacity *= 2;}// 将元素 x 存放到栈顶位置,然后栈顶索引 top 自增 1,指向下一个空闲位置ps->a[ps->top++] = x;
}// 判断栈是否为空的函数
// 接收一个指向栈结构体的指针 ps
bool STEmpty(ST* ps)
{// 断言传入的指针不为空,确保操作的合法性assert(ps);// 通过判断 栈顶索引 是否为 0 来确定栈是否为空,返回相应的布尔值return (ps->top == 0);
}// 获取栈中元素个数的函数
// 接收一个指向栈结构体的指针 ps
int STSize(ST* ps)
{// 断言传入的指针不为空,确保操作的合法性assert(ps);// 直接返回 栈顶索引 的值,因为 栈顶索引 的值就代表了当前栈中元素的个数return (ps->top);
}// 弹出栈顶元素的函数(只是将 栈顶索引 减 1,逻辑上表示栈顶元素被移除了)
// 接收一个指向栈结构体的指针 ps
void STPop(ST* ps)
{// 断言传入的指针不为空,保证操作的合法性assert(ps);// 断言栈不能为空,若为空则不能进行弹出操作,否则会出现错误情况assert(!STEmpty(ps));// 将 栈顶索引 减 1,实现逻辑上的弹出栈顶元素操作--ps->top;
}// 获取栈顶元素的函数(但不会弹出栈顶元素)
// 接收一个指向栈结构体的指针 ps
STDataType STTop(ST* ps)
{// 断言传入的指针不为空,保证操作的合法性assert(ps);// 断言栈不能为空,若为空则没有栈顶元素可供获取,会出现错误情况assert(!STEmpty(ps));// 返回栈顶元素的值(通过 栈顶索引 减 1 的索引来获取,因为数组下标从 0 开始)return (ps->a[ps->top - 1]);
}

用栈实现队列:

// 定义一个结构体 MyQueue,它内部包含两个 ST 类型的结构体成员 pushst 和 popst
// 这里通过两个栈来模拟实现队列的功能
typedef struct 
{ST pushst;ST popst;
} MyQueue;// 创建一个 MyQueue 结构体实例的函数,并进行初始化操作
// 返回指向新创建的 MyQueue 结构体的指针
MyQueue* myQueueCreate() 
{// 动态分配内存来存储一个 MyQueue 结构体大小的空间MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));// 如果内存分配失败(返回的指针为 NULL)if(obj == NULL){// 输出错误信息,提示 malloc 分配内存失败perror("malloc fail");// 返回 NULL,表示创建失败return NULL;}// 初始化 MyQueue 结构体中的 pushst 栈STInit(&(obj->pushst));// 初始化 MyQueue 结构体中的 popst 栈STInit(&(obj->popst));// 返回指向初始化好的 MyQueue 结构体的指针return obj;
}// 向模拟队列( MyQueue 结构体表示)中插入元素的函数
// 参数 obj 是指向 MyQueue 结构体的指针,x 是要插入的元素( int 类型)
void myQueuePush(MyQueue* obj, int x) 
{// 调用栈的入栈函数,将元素 x 压入 pushst 栈,模拟队列的入队操作STPush(&(obj->pushst),x);
}// 获取模拟队列( MyQueue 结构体表示)队头元素的函数
// 参数 obj 是指向 MyQueue 结构体的指针,返回队头元素( int 类型)
int myQueuePeek(MyQueue* obj) 
{// 如果 popst 栈为空if(STEmpty(&(obj->popst))){// 当 pushst 栈不为空时,将 pushst 栈中的元素依次弹出并压入popst 栈while(!STEmpty(&(obj->pushst))){// 取出 pushst 栈的栈顶元素STDataType top = STTop(&(obj->pushst));// 将该元素压入 popst 栈STPush(&(obj->popst), top);// 弹出 pushst 栈的栈顶元素STPop(&(obj->pushst));}}// 获取 popst 栈的栈顶元素,即为模拟队列的队头元素int front = STTop(&(obj->popst)); // 返回队头元素return front;
}// 从模拟队列( MyQueue 结构体表示)中删除队头元素的函数
// 参数 obj 是指向 MyQueue 结构体的指针,返回被删除的队头元素( int 类型)
int myQueuePop(MyQueue* obj) 
{// 先调用 myQueuePeek 函数获取队头元素(同时也会在 popst 栈为空时进行元素转移操作)int front = myQueuePeek(obj);// 弹出 popst 栈的栈顶元素,模拟队列的出队操作STPop(&(obj->popst));// 返回被删除的队头元素return front;
}// 判断模拟队列(MyQueue结构体表示)是否为空的函数
// 参数 obj 是指向 MyQueue 结构体的指针,返回布尔值表示队列是否为空
bool myQueueEmpty(MyQueue* obj) 
{// 当 pushst 栈和 popst 栈都为空时,模拟队列为空,返回 true,否则返回 falsereturn STEmpty(&(obj->pushst)) && STEmpty(&(obj->popst));    
}// 释放模拟队列( MyQueue 结构体表示)所占用的内存资源的函数
// 参数 obj 是指向 MyQueue 结构体的指针
void myQueueFree(MyQueue* obj) 
{// 销毁 MyQueue 结构体中的 pushst 栈,释放其占用的内存STDestroy(&(obj->pushst));// 销毁 MyQueue 结构体中的 popst 栈,释放其占用的内存STDestroy(&(obj->popst));    // 释放 MyQueue 结构体本身所占用的内存空间free(obj);
}

四、设计循环队列

(1)题目描述

下面是该题的链接🔗

设计循环队列

(2)代码示例

// 定义一个循环队列的结构体
typedef struct 
{int k;          // 队列的容量(最大元素个数)int* a;         // 指向队列数组的指针int head;       // 队列的头部索引int tail;       // 队列的尾部索引
} MyCircularQueue;// 创建一个循环队列的函数
MyCircularQueue* myCircularQueueCreate(int k) 
{// 分配内存空间给队列结构体MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));if(obj == NULL){perror("malloc fail");  // 如果分配失败,输出错误信息return NULL;}// 分配内存空间给队列数组,容量为 k+1(多一个空位用于区分空和满)int* tmp = (int*)malloc((k+1) * sizeof(int));if(tmp == NULL){perror("malloc fail");  // 如果分配失败,输出错误信息return NULL;}obj->a = tmp;  // 将数组指针赋值给结构体的a成员obj->k = k;    // 设置队列的容量obj->head = obj->tail = 0;  // 初始化头尾索引为 0return obj;  // 返回创建的队列对象
}// 判断队列是否为空的函数
bool myCircularQueueIsEmpty(MyCircularQueue* obj) 
{return (obj->head == obj->tail);  // 如果头尾索引相同,则队列为空
}// 判断队列是否已满的函数
bool myCircularQueueIsFull(MyCircularQueue* obj) 
{// 如果尾部索引加1后模(k+1)等于头部索引,则队列已满return ((obj->tail + 1) % (obj->k + 1) == obj->head);    
}// 向队列中插入元素的函数
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) 
{if(myCircularQueueIsFull(obj))  // 如果队列已满return false;else{obj->a[obj->tail++] = value;  // 将元素插入尾部,并将尾部索引加 1obj->tail %= (obj->k + 1);    // 尾部索引模(k+1)以循环return true;}
}// 从队列中删除元素的函数
bool myCircularQueueDeQueue(MyCircularQueue* obj) 
{if(myCircularQueueIsEmpty(obj))  // 如果队列为空return false;else{++obj->head;  // 将头部索引加 1obj->head %= (obj->k + 1);    // 头部索引模(k+1)以循环return true;}
}// 获取队列头部元素的函数
int myCircularQueueFront(MyCircularQueue* obj) 
{if(myCircularQueueIsEmpty(obj))  // 如果队列为空return -1;return obj->a[obj->head];  // 返回头部元素
}// 获取队列尾部元素的函数
int myCircularQueueRear(MyCircularQueue* obj) 
{if(myCircularQueueIsEmpty(obj))  // 如果队列为空return -1;else{// 计算尾部元素的索引,考虑循环的情况return (obj->a[(obj->tail-1 + obj->k + 1) % (obj->k + 1)]);}
}// 释放队列内存的函数
void myCircularQueueFree(MyCircularQueue* obj) 
{free(obj->a);  // 释放队列数组的内存free(obj);     // 释放队列结构体的内存    
}

END

每天都在学习的路上!
On The Way Of Learning


http://www.ppmy.cn/news/1562160.html

相关文章

【爬虫】单个网站链接爬取文献数据:标题、摘要、作者等信息

源码链接: https://github.com/Niceeggplant/Single—Site-Crawler.git 一、项目概述 从指定网页中提取文章关键信息的工具。通过输入文章的 URL,程序将自动抓取网页内容 二、技术选型与原理 requests 库:这是 Python 中用于发送 HTTP 请求…

Git 的引用规格(refspec)语法

目录 引用规格语法格式常见用法强制 -f 和 的区别git fetch origin remote-branch:local-branch 和 git push origin local-branch:remote-branch 区别 引用规格语法格式 格式如下&#xff1a;[]<src>:<dst> 常见用法 # fetch git fetch origin <remote-bra…

【linux系统】mysql 数据库迁移至新服务器

文章目录 前言一、新服务器停止数据库服务&#x1f6d1;二、旧服务器打包数据库的data目录&#x1f9f3;三、进入新服务器中打包整个数据库的 data 目录&#xff08;备份&#xff09;四、在新服务器中解压旧服务器打包数据库的 data 目录到数据库data 目录中五、修改新数据库 m…

如何在 Ubuntu 24.04 上安装 Memcached 服务器教程

简介 Memcached 是一个高性能、分布式的内存缓存系统&#xff0c;旨在通过减少数据库负载来加速动态 Web 应用程序。它通过将数据和对象缓存在 RAM 中来实现这一点&#xff0c;从而最大限度地减少了从数据库或其他慢速存储层重复获取数据的需要。 本教程的目标是手把手教你如…

电压控制环与电流控制环

电压控制环和电流控制环是电力电子系统和电机控制中常见的两种控制策略。 一、电压控制环与电流控制环的比较 电压控制环&#xff1a; 特点&#xff1a;电压控制环通常用于稳压应用&#xff0c;通过调整输出电压以维持其稳定在设定值。由于电压是二阶系统&#xff0c;具有滞后…

Kafka核心参数与使用02

一、从基础的客户端说起 Kafka 提供了非常简单的生产者&#xff08;Producer&#xff09;和消费者&#xff08;Consumer&#xff09;API。通过引入相应依赖后&#xff0c;可以快速上手编写生产者和消费者的示例。 1. 消息发送者主流程 一个最基础的 Producer 发送消息的步骤…

【每日学点鸿蒙知识】跳转三方地图、getStringSync性能、键盘避让模式等

1、跳转三方地图导航页 类似于Android 跳转到地图APP 导航页面&#xff1a; // 目标地点的经纬度和名称 double destinationLat 36.547901; double destinationLon 104.258354; String destinationName "目的地名称"; // 构建URI Uri uri Uri.parse("…

运行vue项目,显示“npm”无法识别为 cmdlet、函数、脚本文件或可操作程序的名称

PS D:\weduproject\wedu1\wedu\wedu-fast-vue> npm run dev&#xff0c;运行时出现像下面这样的报红信息&#xff0c; npm : The term npm is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or …