【从零开始的嵌入式生活】数据结构4——栈与队列
前言这周因为不能出去就尽量把数据结构更完,每天一篇文章发布,请大家监督我,如果我没法请@我催更0.0三连即可提高学习效率0.0🧑🏻作者简介:一个学嵌入式的年轻人✨联系方式:2201891280(QQ)📔源码地址:https://gitee.com/xingleigao/study_qianrushi⏳全文大约阅读时间: 120min
前言
这周因为不能出去就尽量把数据结构更完,每天一篇文章发布,请大家监督我,如果我没法请@我催更0.0
三连即可提高学习效率0.0
🧑🏻作者简介:一个学嵌入式的年轻人
✨联系方式:2201891280(QQ)
📔源码地址:https://gitee.com/xingleigao/study_qianrushi
⏳全文大约阅读时间: 120min
栈
栈是限制在一端进行插入操作和删除操作的线性表(俗称堆栈)。
相关的术语:
- 允许进行操作的一端成为栈顶
- 另一固定端成为栈底
- 当栈中没有元素时成为空栈
特点:后进先出
顺序栈
他是顺序表的一种,具有顺序表永阳的存储结构,由数组定义,配合用数组下标表示的栈顶指针top(相对指针)完成各种操作。
定义方式如下:typedef int data_t; //定义栈中数据元素的数据类型 typedef struct{ data_t *data; //用指针指向栈的存储空间 int maxlen; //当前栈的最大元素大小 int top; //只是栈顶元素位置 }sqstack;
创建
示例代码:sqstack * stack_create(int len){ sqstack * s; if ((s = (sqstack *)malloc(sizeof(sqstack)))== NULL){ printf("malloc sqstack failed\n"); return NULL; } if((s->data = (data_t *)malloc(sizeof(data_t) * len))==NULL){ printf("malloc data failed\n"); free(s); return NULL; } memset(s->data, 0 , len * sizeof(data_t)); s->maxlen = len; s->top = -1; return s; }
入栈
示例代码:int stack_push(sqstack * s, data_t value){ if(s == NULL){ puts("stack is null"); return -1; } if(s->top == s->maxlen - 1){ //判断是否为空 puts("stack is full"); return -1; } s->top++; s->data[s->top] = value; return 0; }
出栈
示例代码:data_t stack_pop(sqstack * s){ s->top--; return (s->data[s->top+1]); }
其他的操作相对比较简单,建议直接看我gitee上的代码。
链式栈
插入操作和删除操作均在链表头部进行,链表尾部就是栈底,栈顶指针就是头指针。
数据类型定义:typedef int data_t; typedef struct node_t{ data_t data; struct node_t *next; }linkstack_t;
这部分比较简单就直接给相关实现的源码了:
linkstack stack_create(){
linkstack s;
s = (linkstack)malloc(sizeof(listnode));
if(s == NULL){
puts("malloc failed");
return NULL;
}
s->data = 0;
s->next = NULL;
return s;
}
int stack_push(linkstack s, data_t value){
linkstack p;
if(s == NULL){
puts("s is null");
return -1;
}
p = (linkstack)malloc(sizeof(listnode));
if(p == NULL){
puts("malloc failed");
return -1;
}
p->data = value;
//p->next = NULL;
p->next = s->next;
s->next = p;
return 0;
}
data_t stack_pop(linkstack s){
linkstack p;
p = s->next;
s->next = p->next;
data_t t = p->data;
free(p);
p = NULL;
return t;
}
int stack_empty(linkstack s){
if(s == NULL){
puts("s is null");
return -1;
}
return (s->next == NULL ? 1 : 0);
}
data_t stack_top(linkstack s){
return (s->next->data);
}
linkstack stack_free(linkstack s){
linkstack p;
if(s == NULL){
puts("s is null");
return NULL;
}
while(s != NULL){
p = s;
s = s->next;
printf("free:%d\n", p->data);
free(p);
}
return NULL;
}
队列
队列是限制在两端进行插入操作和删除操作的线性表
- 允许进行存入操作的一端称为队尾
- 允许进行删除操作的一端称为队头
- 当线性表中没有元素时,成为空队
特点:先入先出(FIFO)
队列的操作
- 创建队列:CreateQueue()
- 清空队列:ClearQueue(Q)
- 判断队列空:EmptyQueue(Q)
- 判断队列满:FullQueue(Q)
- 入队:EnQueue(Q,x)
- 出队:DeQueue(Q)
顺序队列
顺序队列的数据结构
typedef int datatype; #define N 128 typedef struct{ datatype data[]; int front; int rear; }
因为之前相关操作都是差不多的,需要注意的只有是循环队列,所以判断条件不太一样,这里相关操作我也直接给代码了:
sequeue *queue_create(){
sequeue *sq;
if((sq = (sequeue *)malloc(sizeof(sequeue))) == NULL){
printf("malloc failed\n");
return NULL;
}
memset(sq->data,0,sizeof(sq->data));
sq->front = sq->rear = 0;
return sq;
}
int enqueue(sequeue *sq, datatype x){
if(sq == NULL){
printf("sq is null\n");
return -1;
}
if ((sq->rear + 1) % N == sq->front){
printf("sequeue is full\n");
return -1;
}
sq->data[sq->rear] = x;
sq->rear = (sq->rear + 1) % N;
return 0;
}
datatype dequeue(sequeue *sq){
if(sq == NULL){
printf("sq is null\n");
return -1;
}
datatype ret;
ret = sq->data[sq->front];
sq->front = (sq->front + 1) % N;
return ret;
}
int queue_empty(sequeue *sq){
if(sq == NULL){
printf("sq is null\n");
return -1;
}
return (sq->front == sq->rear ? 1 : 0);
}
int queue_full(sequeue *sq){
if(sq == NULL){
printf("sq is null\n");
return -1;
}
if ((sq->rear + 1) % N == sq->front){
return -1;
}
return 0;
}
int queue_clear(sequeue *sq){
if(sq == NULL){
printf("sq is null\n");
return -1;
}
sq->front = sq->rear = 0;
return 0;
}
sequeue * queue_free(sequeue *sq){
if(sq == NULL){
printf("sq is null\n");
return NULL;
}
free(sq);
sq = NULL;
return sq;
}
一般队列的使用不会声明这么多的结构体啥的,一般都是直接使用一个数组来当作队列使用。出队入队都是一行代码。可以想想怎么写,有时间写个demo。
链式队列
插入操作在队尾进行,删除操作在队头进行,由队头指针和队尾指针控制队列的操作。
结构体定义:
相关操作
linkqueue * queue_create(){
linkqueue *lq;
if((lq = (linkqueue *)malloc(sizeof(linkqueue))) == NULL){
printf("malloc linkqueue failed\n");
return NULL;
}
lq->front = lq->rear = (linklist)malloc(sizeof(listnode));
if(lq->front == NULL){
printf("malloc node failed\n");
free(lq);
return NULL;
}
lq->front->data = 0;
lq->front->next = NULL;
return lq;
}
int enqueue(linkqueue *lq, datatype x){
linklist p;
if(lq == NULL){
printf("lq is null\n");
return -1;
}
if((p = (linklist)malloc(sizeof(listnode))) == NULL){
printf("malloc node failed\n");
return -1;
}
p->data = x;
p->next = NULL;
lq->rear->next = p;
lq->rear = p;
return 0;
}
datatype dequeue(linkqueue *lq){
linklist p;
if(lq == NULL){
printf("lq is null\n");
return -1;
}
p = lq->front;
lq->front = p->next;
free(p);
return lq->front->data;
}
int queue_empty(linkqueue *lq){
if(lq == NULL){
printf("lq is null\n");
return -1;
}
return (lq->front == lq->rear ? 1: 0);
}
int queue_clear(linkqueue *lq){
linklist p;
if(lq == NULL){
printf("lq is null\n");
return -1;
}
if(!lq->front){
return 0;
}
while(lq->front->next){
p = lq->front;
lq->front = p->next;
printf("free:%d\n",p->data);
free(p);
}
return 0;
}
linkqueue * queue_free(linkqueue *lq){
linklist p;
if(lq == NULL){
printf("lq is null\n");
return lq;
}
while(lq->front){
p = lq->front;
lq->front = p->next;
printf("free :%d\n" ,p->data);
free(p);
}
free(lq);
return NULL;
}
栈和队列的应用
球钟是一个利用球的移动来记录时间的的简单装置。
它有三个可以容纳若干球的指示器:分钟指示器,五分钟指示器,小时指示器
如:分钟指示器有2个球,五分钟指示器6个球,小时指示器有5个球,则时间为5:32
工作原理:
每过一分钟,球钟就会从一个队列的队首取出一个球放入分钟指示器,分钟指示器最多可以容纳4个球。
当放入第5个球时,在分钟指示器的4个球就会按照他们被放入时的顺序加入球队列的队尾。而第五个球就会进入五分钟指示器。
按此类推,五分钟指示器最多可放11个球,小时指示器最多可以放11个球。
问题:
现设初始时队列的球数为27,球钟的三个指示器初始状态均为空。问:要经过多久,球队列才能回复到原来的顺序?
解决代码
#include <stdio.h>
#include "linkqueue.h"
#include "sqstack.h"
int check(linkqueue *lq);
int main(int argc, const char *argv[]){
linkqueue *lq;
sqstack *s_hour, *s_five, *s_min;
int i, min = 0;
int value;
if((lq = queue_create()) == NULL){
return -1;
}
for(i = 1; i <= 27; ++i){
enqueue(lq,i);
}
if((s_hour = stack_create(11)) == NULL) return -1;
if((s_five = stack_create(11)) == NULL) return -1;
if((s_min = stack_create(4)) == NULL) return -1;
while(1){
min++;
if(!queue_empty(lq)){
value = dequeue(lq);
if(!stack_full(s_min)){
stack_push(s_min, value);
}else{
while(!stack_empty(s_min)){
enqueue(lq, stack_pop(s_min));
}
if(!stack_full(s_five)){
stack_push(s_five,value);
}else{
while(!stack_empty(s_five)){
enqueue(lq, stack_pop(s_five));
}
if(!stack_full(s_hour)){
stack_push(s_hour,value);
}else{
while(!stack_empty(s_hour)){
enqueue(lq, stack_pop(s_hour));
}
enqueue(lq, value);
if(check(lq) == 1)
break;
}
}
}
}
}
printf("total:%d\n",min);
return 0;
}
int check(linkqueue *lq){
linklist p;
if(lq == NULL){
printf("lq is null\n");
return -1;
}
p = lq->front->next;
while(p && p->next){
if(p->data < p->next->data)
p = p->next;
else return 0;
}
return 1;
}
写在最后
栈和队列内容有点多,我失策了,导致昨天没正常更新,今天很多内容需要去gitee仓库里找我练习的代码跟着写来理解,大家加油,接下来的几天时间会继续了解各种数据结构,我尽量一天一更,大家和我一起变强呀!最后三连即可提高学习效率!!!
另外我在更新的就是算法笔记的一些例题笔记,这个系列是用于提高我的算法能力,如果有兴趣对算法领域感兴趣找不到合适的入门文章也可以追更,如果我更新的太慢了请大家点赞收藏,一键三连才能更有更新的动力呀0.0
更多推荐
所有评论(0)