C语言数据结构进阶之栈和队列的实现
目录
- 栈的实现:
- 一、栈的概念和性质
- 二、栈的实现思路
- 三、栈的相关变量内存布局图
- 四、栈的初始化和销毁
- 五、栈的接口实现:
- 1.入栈
- 2.出栈
- 3.获取栈顶的数据
- 4.获取栈的元素个数
- 5.判断栈是否为空
- 队列的实现:
- 一、队列的概念和性质
- 二、队列的实现思路
- 三、队列相关变量的内存布局图
- 四、队列的初始化和销毁
- 五、队列的接口实现:
- 1. 入数据
- 2.出数据
- 3.取队头数据
- 4.取队尾数据
- 5.获取队列元素个数
- 6.判断队列是否为空
- 总结
栈的实现:
一、栈的概念和性质
【C语言数据结构进阶之栈和队列的实现】栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在固定的一端进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶
文章图片
二、栈的实现思路
栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小这里我们用顺序表结构来实现栈。
顺序表可以把使用的空间写成固定值,也可以构建动态开辟内存;但是如果写成固定的数组形式当存的数据满了就不能再使用了,所以下面我们实现的是动态开辟内存的形式。
所以我们先创建一个顺序表结构体类型,结构体类型中有指针,下标,容量。
指针: 用来维护在堆上连续的一段空间,
下标:表示数据存放到哪一个位置了,因为数据只能一个接着一个地存放,要有个下标来记录我数据放到哪一个位置了。
容量:与下标相比较,当下标与容量相等就表示空间存储满了,要进行扩容处理。
创建类型如下:
typedef int STDataType; //对int类型重新起个名字叫DataType//创建一个栈结构体类型struct Stack{ STDataType* a; //数据的指针 int top; //栈顶 int capacity; //记录开辟空间的最大下标处}; //对顺序表类型struct Stack类型重新起个名字叫SLtypedef struct Stack ST; //当size 和 capacity相等时要进行扩容处理
三、栈的相关变量内存布局图
文章图片
四、栈的初始化和销毁
//初始化变量stvoid StackInit(ST* ps){ ps->a = NULL; ps->capacity = 0; ps->top = 0; }//栈的销毁void StackDestroy(ST* ps){ free(ps->a); ps->a = NULL; ps->top = 0; ps->capacity = 0; }
五、栈的接口实现:
1.入栈
//入栈void StackPush(ST* ps, STDataType x){ assert(ps); //内存满了要扩容 if (ps->capacity == ps->top) {ps->capacity = ps->capacity > 0 ? ps->capacity * 2 : 2; STDataType* tmp = (STDataType*)realloc(ps->a,sizeof(STDataType) * ps->capacity); if (tmp == NULL){perror("erron "); exit(-1); }ps->a = tmp; } //没有满就直接在后面入栈 ps->a[ps->top] = x; ps->top++; }
2.出栈
//出栈,要注意栈不能为空void StackPop(ST* ps){ assert(ps); //栈为空就不能再出栈了 assert(ps->top >= 1); ps->top--; }
3.获取栈顶的数据
//返回栈顶的元素STDataType StackTop(ST* ps){ assert(ps); //栈不能为空 assert(ps->top >= 1); return ps->a[ps->top - 1]; }
4.获取栈的元素个数
//获取栈的元素个数int StackSize(ST* ps){ assert(ps); assert(ps->top >= 1); return ps->top - 1; }
5.判断栈是否为空
//判断栈是否为空bool StackEmpty(ST* ps){ return ps->top == 0; }
队列的实现:
一、队列的概念和性质
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)的性质。
队列:进行插入操作的一端称为队尾
出队列: 进行删除操作的一端称为队头
文章图片
二、队列的实现思路
队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。
而链表我们采用双向链接结构,一个指针来维护头节点,一个指针维护尾部节点
文章图片
定义的结构体类型如下:
typedef int QDataType; //创建一个结点型结构体typedef struct QueueNode{ struct QueueNode* next; QDataType data; }QueueNode; //创建一个队列typedef struct Queue{ QueueNode* head; QueueNode* tail; }Queue;
三、队列相关变量的内存布局图
文章图片
四、队列的初始化和销毁
//初始化队列void QueueInit(Queue* pq){ assert(pq); pq->head = NULL; pq->tail = NULL; }//队列销毁void QueueDestroy(Queue* pq){ assert(pq); QueueNode* cur = pq->head; while (cur != NULL) {QueueNode* next = cur->next; free(cur); cur = next; } pq->head = NULL; pq->tail = NULL; }
五、队列的接口实现:
1. 入数据
//入数据有两种情况void QueuePush(Queue* pq,QDataType x){ assert(pq); QueueNode* newNode = (QueueNode*)malloc(sizeof(QueueNode)); if (newNode == NULL) {perror("erron "); exit(-1); } newNode->next = NULL; newNode->data = https://www.it610.com/article/x; //1.入队列时队列为空状态 if (pq->head == NULL) {pq->head = newNode; pq->tail = newNode; } //2.入队列,队列不为空,直接在尾指针后面链接即可 else {pq->tail->next = newNode; pq->tail = newNode; }}
2.出数据
//出数据,类似链表的头删void QueuePop(Queue* pq){ assert(pq); //要保证队列不能为空 assert(pq->head != NULL); QueueNode* next = pq->head->next; free(pq->head); pq->head = next; //防止野指针出现,当队列为空时要把tail指针置为空 if (pq->head == NULL) {pq->tail = NULL; }}
3.取队头数据
//取队头数据QDataType QueueFront(Queue* pq){ assert(pq); //检验队列不能为空 assert(pq->head != NULL); return pq->head->data; }
4.取队尾数据
//取队尾数据QDataType QueueBack(Queue* pq){ assert(pq); //同样要检验队列不能为空 assert(pq->head != NULL); return pq->tail->data; }
5.获取队列元素个数
//获取队列元素个数int QueueSize(Queue* pq){ assert(pq); int count = 0; QueueNode* cur = pq->head; while (cur != NULL) {count++; cur = cur->next; } return count; }
6.判断队列是否为空
//判断队列是否为空bool QueueEmpty(Queue* pq){ return pq->head == NULL; }
总结 以上就是栈和队列的实现内容了,其中前面我只有把源文件Stack.c 和Queue.c拆开来分析了。如果想要栈和队列的全部内容,阔以移步到gitee上获取
【栈的源码链接,点击即可】
【队列的源码链接,点击即可】
到此这篇关于C语言数据结构进阶之栈和队列的实现的文章就介绍到这了,更多相关C语言 数据结构 内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
推荐阅读
- 【生信技能树】R语言练习题|【生信技能树】R语言练习题 - 中级
- 一起来学习C语言的字符串转换函数
- C语言字符函数中的isalnum()和iscntrl()你都知道吗
- C语言浮点函数中的modf和fmod详解
- C语言中的时间函数clock()和time()你都了解吗
- C语言学习|第十一届蓝桥杯省赛 大学B组 C/C++ 第一场
- 推荐系统论文进阶|CTR预估 论文精读(十一)--Deep Interest Evolution Network(DIEN)
- C语言解方程的根和判断是否是闰年
- C语言的版本比较
- 普通人进阶的三个过程-很多人都知道,但却本末倒置