当前位置: 首页 > news >正文

嵌入式学习笔记 D22:栈与队列

  • 栈的概念及链栈的基本操作
  • 队列的概念及其基本操作

一、栈的概念及链栈的基本操作

1. 栈的概念

        栈是限定仅在表尾进行插入和删除操作的线性表。允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom),不含任何数据元素的栈称为空栈。

        注:线性表中的栈在堆区(因为是malloc来的);系统中的栈区存储局部变量、函数形参、函数返回值地址。

        LIFO 结构:栈又称为后进先出(LastInFirst0ut)的线性表。

        栈对线性表的插入和删除的位置进行了限制,并没有对元素进出的时间进行限制,

也就是说,在不是所有元素都进栈的情况下,事先进去的元素也可以出栈,只要保证是

栈顶元素出栈就可以。

        应用:解决的问题要回溯、递归可以用链栈;有优先级问题的用栈处理。

2. 链栈的基本操作

        创建链栈:

LinkStack* CreateLinkStack() 

    // 分配链栈结构体空间,void* 强转为 LinkStack* 
    LinkStack* ls = (LinkStack*)malloc(sizeof(LinkStack)); 
    if(NULL == ls) 
    { 
        // 打印错误信息到标准错误流 
        fprintf(stderr,"CreateLinkStack malloc\n"); 
        return NULL; // 分配失败返回空 
    } 
    ls->top = NULL; // 初始化栈顶指针为空(空栈) 
    ls->clen = 0; // 初始化栈长度为0 
    return ls; // 返回创建好的链栈指针 
}

        入栈:

int PushLinkStack(LinkStack* ls, DATATYPE* data) 

    // 分配新节点空间 
    LinkStackNode* newnode = malloc(sizeof(LinkStackNode)); 
    if(NULL == newnode) 
    { 
        fprintf(stderr,"PushLinkStack malloc\n"); // 打印内存分配失败信息 
        return 1; // 失败返回错误码1 
    } 
    // 将数据拷贝到新节点的数据域 
    memcpy(&newnode->data, data, sizeof(DATATYPE)); 
    newnode->next = NULL; // 新节点初始next指针为空 
    newnode->next = ls->top; // 新节点next指向原栈顶节点(头插法) 
    ls->top = newnode; // 栈顶更新为新节点 
    ls->clen++; // 栈长度加1 
    return 0; // 成功返回0(原代码缺失return,需补充)
}

        出栈:

int PopLinkStack(LinkStack* ls) 

    if(IsEmptyLinkStack(ls)) // 检查栈是否为空 
    { 
        return 1; // 空栈返回错误码1 
    } 
    LinkStackNode* tmp = ls->top; // 保存当前栈顶节点指针 
    ls->top = ls->top->next; // 栈顶指针后移一位(指向原次栈顶) 
    free(tmp); // 释放原栈顶节点内存 
    ls->clen--; // 栈长度减1 
    return 0; // 成功返回0 
}

        判断栈空:

int IsEmptyLinkStack(LinkStack* ls) 

    // 栈长度为0时返回1(真),否则返回0(假) 
    return 0 == ls->clen; 
}

        获取栈长度:

int GetSizeLinkStack(LinkStack* ls) 

    // 直接返回结构体中记录的栈长度(O(1)时间复杂度) 
    return ls->clen; 
}

        获取栈顶元素:

DATATYPE* GetTopLinkStack(LinkStack* ls) 

    if(IsEmptyLinkStack(ls)) // 检查栈是否为空 
    { 
        return NULL; // 空栈返回空指针 
    } 
    // 返回栈顶节点数据域的地址(需确保调用时不为空) 
    return &ls->top->data; 
}

        销毁链栈:

int DestroyLinkStack(LinkStack* ls) 

    int len = GetSizeLinkStack(ls); // 获取栈当前长度 
    for(int i = 0; i < len; ++i) 
    { 
        PopLinkStack(ls); // 循环调用出栈函数释放所有节点 
    } 
    free(ls); // 释放链栈结构体本身的内存 
    return 0; // 成功返回0 
}

        注:查看是否内存泄漏:valgrind  ./app

二、队列的概念及其基本操作

1. 队列的概念

        队列是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。

        FIFO结构:队列是一种先进先出(FirstInFirst0ut)的线性表。允许插入的一 端称为队尾,允许删除的一端称为队头。

        clen = (尾巴 - 头 + 长度)。

        应用:计算机做缓冲用队列;

        循环队列(圆环):(求余就循环起来),把队列这种头尾相接的顺序存储结构称为循环队列。

        面试问题:满队判断条件:尾巴+1==头   (tail + 1 ) % tlen == head

                               空队:尾巴==头   tail == head

2. 队列的基本操作

        创建队列:

SeqQueue* CreateSeqQue(int len) 

    // 分配顺序队列结构体空间,强转为 SeqQueue* 
    SeqQueue* sq = (SeqQueue*)malloc(sizeof(SeqQueue)); 
    if(NULL == sq) 
    { 
        // 打印结构体内存分配失败信息到标准错误流 
        fprintf(stderr,"CreateSeqQue malloc\n"); 
        return NULL; // 失败返回空 
    } 
    // 分配队列数据存储数组空间(容量为len) 
    sq->array = malloc(sizeof(DATATYPE)*len); 
    if(NULL == sq->array) 
    { 
        // 打印数组内存分配失败信息 
        fprintf(stderr,"CreateSeqQue malloc\n"); 
        free(sq); // 释放已分配的结构体空间(避免内存泄漏) 
        return NULL; 
    } 
    sq->head = 0; // 初始化头指针(指向队头元素前一个位置) 
    sq->tail = 0; // 初始化尾指针(指向队尾元素位置) 
    sq->tlen = len; // 记录队列总长度(容量) 
    return sq; // 返回创建好的顺序队列指针 
}

        判断队空及队满:

//   //  队空

int IsEmptySeqQue(SeqQueue* sq) 

    // 头指针等于尾指针时队列为空(返回1表示真,0表示假) 
    return sq->head == sq->tail; 
}

//  //  队满

int IsFullSeqQue(SeqQueue* sq) 

    // 尾指针下一个位置(循环取模)等于头指针时队满 
    return (sq->tail + 1) % sq->tlen == sq->head; 
}

        入队:

int EnterSeqQue(SeqQueue* sq, DATATYPE* data) 

    if(IsFullSeqQue(sq)) 
    { 
        // 打印队满错误信息 
        fprintf(stderr,"EnterSeqQue,SeqQueue full\n"); 
        return 1; // 失败返回错误码1 
    } 
    // 将数据拷贝到尾指针当前位置的数组元素中 
    memcpy(&sq->array[sq->tail], data, sizeof(DATATYPE)); 
    // 尾指针后移一位(循环队列,取模实现环形) 
    sq->tail = (sq->tail + 1) % sq->tlen; 
    return 0; // 成功返回0 
}

        出队:

int QuitSeqQue(SeqQueue* sq) 

    if(IsEmptySeqQue(sq)) 
    { 
        // 打印队空错误信息 
        fprintf(stderr,"QuitSeqQue SeqQueue empty\n"); 
        return 1; // 失败返回错误码1 
    } 
    // 头指针后移一位(指向实际队头元素,取模实现环形) 
    sq->head = (sq->head + 1) % sq->tlen; 
    return 0; // 成功返回0 
}

        获取队头元素:

DATATYPE* GetHeadSeqQue(SeqQueue* sq) 

    if(IsEmptySeqQue(sq)) 
    { 
        return NULL; // 队空返回空指针 
    } 
    // 返回队头元素地址(头指针当前指向的是队头元素的位置) 
    return &sq->array[sq->head]; 
}

        销毁顺序队列:

int DestroySeqQue(SeqQueue* sq) 

    free(sq->array); // 先释放数据存储数组的内存 
    free(sq); // 再释放队列结构体的内存 
    return 0; // 成功返回0 
}

相关文章:

  • 板凳-------Mysql cookbook学习 (四)
  • GPU硬件计数器深度用法:通过NVIDIA Nsight Compute定位隐藏的性能瓶颈——以DRAM访问模式对带宽利用率影响分析为例
  • 第2篇 水滴穿透:IGBT模块的绝对防御体系
  • Python数据可视化初探——“十八般兵器”介绍
  • 嵌入式系统中,检测链路层(物理层)状态变化时,选择中断驱动还是定时轮询
  • 【每天一个知识点】embedding与representation
  • 为什么上传大量大文件推荐是使用 app 应用为不是 web 浏览器下载上传呢?
  • PLC组网的方法、要点及实施全解析
  • 网络传输(ping命令,wget命令,curl命令),端口
  • 代码随想录算法训练营第四十四天
  • 开发体育比分网站,有哪些坑需要注意的
  • 创建型:抽象工厂模式
  • C#:多线程
  • Ubuntu Desktop QEMU/KVM中使用Ubuntu Server 22.04配置k8s集群
  • 阿里云web端直播(前端部分)
  • 最小质因子之和(JAVA)线性筛
  • 王树森推荐系统公开课 排序03:预估分数融合
  • java bean 和map相互转换
  • 蓝桥杯国赛第十五届(JAVAB组)
  • 基于 STC89C52 的料仓物位监测系统设计与实现
  • 国家主席习近平任免驻外大使
  • 人民网:激发博物馆创新活力,让“过去”拥有“未来”
  • 盐城经济技术开发区党工委书记王旭东接受纪律审查和监察调查
  • 当智慧农场遇见绿色工厂:百事如何用科技留住春天的味道?
  • 女生“生理期请病假要脱裤子证明”?高校回应:视频经处理后有失真等问题
  • 从近200件文物文献里,回望光华大学建校百年