栈与队列的操作
栈与队列
具有的操作:
- 初始化栈(队列)
- 判断栈(队列)是否为空
- 判断栈(队列)是否已满
- 入栈(队列)
- 出栈(队列)
- 遍历栈(队列)
栈满足的特性
- 先进后出 后进先出
队列满足的特性
- 先进先出,后进后出
顺序栈(数组形式)
-
定义数据类型 默认以int类型为主,可以使用模板封装任意类型的栈
//存int类型数据的顺序栈 int* pStack; //指向栈的指针 int size; //存储栈中的元素个数 -
栈的操作
//初始化栈 void InitStack(); //入栈 void push(int data); //出栈 void pop(); //判断栈是否为空 bool isEmpty(); //获取栈顶元素,只能获取栈顶元素 int getTop(); //遍历元素 void _travel(); -
初始化栈
//初始化栈 void InitStack() { pStack = NULL; } -
入栈操作: 分两种方式
-
当栈为空的时候,
void push() { if (pStack == NULL) { //1. 开辟新的空间 pNew = (int*)malloc(sizeof(int)* (size+1)); //2. 原来的内存指向新的开辟的内存 pStack = pNew; //3. 插入数据 pStack[size++] = data; } -
当栈不为空的时候
- 即需要在数组的最后添加元素,首先要开辟一块新的内存区域,在新开辟的空间进行数组元素的增加
//栈不为空 操作步骤: else { //1.为后面的开辟新的内存 int* pNew = (int*)malloc(sizeof(int) * (size + 1)); //2.将原有的内存数据的元素拷贝到新的内存里 memcpy(pNew, pStack, sizeof(int) * size); //3.释放原有的内存空间 free(pStack); //4.原来的内存指向新的开辟的内存 pStack = pNew; //5.插入数据 pStack[size++] = data; }
-
-
出栈操作
-
对于栈,先进的元素后出,后进的元素先出,即首先删除数组末尾的元素,然后依次往前删除
void pop() { if (isempty()) { printf("栈为空\n"); return; } int* pNew = (int*)malloc(sizeof(int) * (size - 1)); memcpy(pNew, pStack, sizeof(int) * (size - 1)); free(pStack); pStack = pNew; size--; }
-
-
栈的其他操作
//判断栈是否为空 bool isEmpty() { return (size == 0); } //获取栈顶元素,只能获取栈顶元素 int getTop() { return pStack[size-1]; } //遍历元素 void _travel() { printf("size(%d):", size); for (int i = 0; i < size; i++) { printf("%d ", pStack[i]); } printf("\n"); } -
栈的测试
int main() { InitStack(); //测试 for (int i = 5; i < 15; i++) { push(i); _travel(); } while (!isEmpty()) { printf("当前栈顶:%d\n", getTop()); pop(); //出栈 } return 0; }
顺序队列(数组形式)
-
队列的操作与栈基本一致 只有出队的时候与出栈不同
-
队列先进先出 后进后出 先删除数组的第一个元素,在依次往后删除数组元素
-
出队
//出队 int pop() { if (isEmpty()) { printf("队列为空,出队失败\n"); return -1; } /* 队列: 先进先出 要删除第一个元素 */ //释放第一个元素 int ret = pQueue[0]; //1. 开辟一个新的内存段 int* pNew = (int*)malloc(sizeof(int) * (size - 1)); //2. 原有内存段的数据拷贝到新的内存段 要删除第一个 旧的内存区块跳过第一个元素 memcpy(pNew, pQueue + 1, sizeof(int) * (size - 1)); //3. 释放原有的内存段 free(pQueue); //4. 原有的内存段指向新开辟的内存 pQueue = pNew; //5. size减少 size--; //6. 返回每次释放的元素 return ret; } -
队列测试
int main() { InitQueue(); //测试 for (int i = 5; i < 15; i++) { push(i); _travel(); } int ret = 0; while (ret != -1) { printf("队列顶:%d\n", ret = pop()); } return 0; }
``
链式栈 (无头节点)
链表的形式存储栈的节点 操作和链表的操作基本一致
-
这里以结构体类型描述栈的结构
//栈节点的数据类型 struct Student { char name[50]; int age; float score; }; typedef struct Student STU; #define STU_SIZE sizeof(struct Student) //存储链式栈的链表 struct List { STU data; struct List* next; }; typedef struct List Node; -
链式栈的操作
//创建节点 Node* CreateNode(STU* data); //尾插法 入栈 void push(Node** pHead,STU* data); //出栈 Node* pop(Node** pHead); //遍历栈 void travel(Node* head); //打印 void Printf(STU* p); -
创建栈节点
//创建节点 Node* CreateNode(STU* data) { Node* pNew = (Node*)malloc(sizeof(Node)); if (pNew == NULL) { printf("创建失败\n"); return 0; } strcpy(pNew->data.name, data->name); pNew->data.age = data->age; pNew->data.score = data->score; pNew->next = NULL; //返回节点 return pNew; } -
入栈 链表的尾插法入栈
- 分两种情况,看他是空链表还是非空链表
//尾插法 入栈 void push(Node** pHead, STU* data) { if (pHead == NULL) { return; } //创建新的节点 Node* pNew = CreateNode(data); //空链表 新节点要成为当前节点的第一个几点 if (*pHead == NULL) { *pHead = pNew; } else { //找到链表的尾部 插入节点 Node* pTemp = *pHead; while (pTemp->next) { pTemp = pTemp->next; } //在尾部插入 pTemp->next = pNew; } } -
出栈
- 删除链表的最后一个节点,依次往前删除
//出栈 删除末尾节点 Node* pop(Node** pHead) { if (pHead == NULL || *pHead == NULL) { return NULL; } //找到链表的最后一个节点 Node* pTail = *pHead; while (pTail->next) { pTail = pTail->next; } //1. 如果链表只有一个节点,第一个就等于末尾节点 if (pTail == *pHead) { *pHead = NULL; } //2. 如果有多个节点 找到最后一个的前一个并且删除最后一个 else { Node* pPreTail = *pHead; while (pPreTail->next != pTail) { pPreTail = pPreTail->next; } //最后一个节点的前一个节点next置空 实现删除最后一个 pPreTail->next = NULL; } return pTail; } -
遍历及打印
//遍历栈 void travel(Node* pHead) { if (pHead == NULL) { printf("栈为空\n"); return; } Node* pTemp = pHead; while (pTemp) { //传入地址 Printf(&(pTemp->data)); pTemp = pTemp->next; } } //打印 void Printf(STU* p) { printf("姓名:%s 年龄:%d 成绩:%.2f\n", p->name, p->age, p->score); } -
链式栈测试
int main() { STU info[5] = { {"关羽",55,55.55}, {"张飞",44,44.44}, {"赵云",33,33.33}, {"马超",22,22.22}, {"黄忠",11,11.11}, }; Node* pHead = NULL; //入栈 for (int i = 0; i < 5; i++) { push(&pHead, &info[i]); } travel(pHead); printf("\n\n"); //出栈 Node* pStackTemp = NULL; while (1) { pStackTemp = pop(&pHead); if (pStackTemp == NULL) { printf("出栈失败\n"); break; } Printf(&pStackTemp->data); //释放内存 free(pStackTemp); printf("\n\n"); } return 0; }
链式队列(无头节点)
- 操作和链式栈基本一致,除了出栈和出队
- 出队: 先进先出 后进后出 先删除首元节点,再依次往后删除节点
//出队 删除头节点 Node* pop(Node** pHead) { if (pHead == NULL || *pHead == NULL) { printf("出队失败\n"); return NULL; } Node* pTemp = *pHead; //只有一个节点 if (( * pHead)->next == NULL) { *pHead = NULL; } else { //有多个节点,则跳过第一个 *pHead = ( * pHead)->next; } return pTemp; }
本文来自博客园,作者:hugeYlh,转载请注明原文链接:https://www.cnblogs.com/helloylh/p/17209752.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)