数据结构·栈和队列

1. 栈

1.1 栈的概念及结构

        栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一段称为栈顶,另一端称为栈底。

        栈中的数据元素遵守 后进先出 LIFO(Last In First Out)的原则,后进来的数据先出去

        压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶

        出栈:栈的删除操作叫做出栈。出数据也在栈顶

                        

1.2  栈的实现

        我们先分析一下,栈我们应该用顺序表还是链表实现?

        栈中的数据的插入和删除都是在栈顶实现的,不需要随机位置的插入删除,此时链表的优势就不大了。相比之下顺序表还有内存命中率高的优点,所以最后我们选择用顺序表实现栈

                                

        头文件,源文件,测试文件这里我就不展示了,直接写栈中功能的实现

1.2.1 栈的初始化和销毁

        这个没什么好说的,直接上代码

1.2.2 判断栈是否真是空

        

1.2.3 压栈

        压栈涉及到扩容,如果栈内空间不够就要扩容,栈满的判断标准就是 栈顶top 和 总空间大小capacity 数值相同,然后压完之后不要忘记top++

1.2.4 出栈

        这个很简单,让栈顶回退一个位置就行了

                ​​​​​​​        

1.2.5 取栈顶元素

        这里要注意我们在取栈顶的时候要取 top-1 因为我们在初始化的时候设定的top为0,实际上此时的栈顶指向了一个空的位置,之后我们每压一次栈top都会向后移动一下,指向下一个空的位置,所以我们实际取栈顶的时候要 top-1 或者说,top是指向了栈顶的下一个元素

        ​​​​​​​​​​​​​​        ​​​​​​​        

1.2.6 返回栈的大小(多少有效数据)

        这没啥好说的,上代码

        

1.3 栈的完整代码

        Stack.h

#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include<assert.h>typedef int STDataType;
typedef struct Stack
{STDataType* a;int top;	//栈顶int capacity;
}ST;void STInit(ST* ps);
void STDestory(ST* ps);//压栈
void STPush(ST* ps, STDataType x);
//出栈
void STPop(ST* ps);//取栈顶元素
STDataType STTop(ST* ps);int STSize(ST* ps);bool STEmpty(ST* ps);

        Stack.c

#include"Stack.h"//初始化
void STInit(ST* ps)
{assert(ps);ps->a = NULL;ps->top = 0;ps->capacity = 0;
}//销毁
void STDestory(ST* ps)
{free(ps->a);ps->a = NULL;ps->top = ps->capacity = 0;
}//压栈
void STPush(ST* ps, STDataType x)
{assert(ps);//满了,要扩容if (ps->top == ps->capacity){//防止是第一次扩容,所以要判断一下int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;	STDataType* tmp = (STDataType*)realloc(ps->a, newcapacity * sizeof(STDataType));if (tmp == NULL){perror("realloc fail");exit(-1);}ps->a = tmp;ps->capacity = newcapacity;}ps->a[ps->top] = x;ps->top++;
}//出栈
void STPop(ST* ps)
{assert(ps);//栈不为空才能删assert(!STEmpty(ps));ps->top--;
}//取栈顶元素
STDataType STTop(ST* ps)
{assert(ps);assert(!STEmpty(ps));return ps->a[ps->top-1];
}//返回栈的大小(多少有效数据)
int STSize(ST* ps)
{assert(ps);return ps->top;
}//判断栈是否真是空
bool STEmpty(ST* ps)
{assert(ps);//如果真是空就返回真//如果不是空就返回假return ps->top == 0;
}

2. 队列

2.1 队列的概念及结构

        队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(first in first out)特点

        入队列:进行插入操作的一端为队尾

        出队列:进行删除操作的一端为队头

        ​​​​​​​        ​​​​​​​        

2.2 队列的实现

        首先我们分析一下应该怎么实现队列

        如果用顺序表的话,数据从前向后依次存放,此操作还比较方便,但是到删除时,从前向后删除,每删一个元素,就要将后面的元素向前挪一位,时间复杂度O(N)

        所以推荐使用链表解决问题,尾插数据,头删数据,就像上面画的那个类似管道的示意图一样,此时问题又来了,尾插数据需要遍历链表,这样时间复杂度的问题依旧没解决,怎么办?

        解决方案就是我们再引入一个新的结构体,专门用来维护这条链表,新的结构体中存放这个链表的头节点和尾节点的地址,还有这个链表的长度,这样只需将新节点尾插到ptail后面就好了,不用遍历链表了。

        创建链表节点:

        ​​​​​​​        ​​​​​​​        

        创建新结构体用于维护链表:

                        

        之后在主函数中用也这个新结构体来代替链表头节点进行传参,或者说这个新结构体代替的整条链表,而链表头节点只是一个节点,孰强孰弱,一目了然。

2.2.1 队列的初始化和销毁

        因为我们创建的链表是不带头的,所以初始化都是无脑置空就好

        

        

2.2.2 队列中剩余元素

        ​​​​​​​        ​​​​​​​ 

2.2.3 入队列

2.2.4 出队列

        出队列要注意链表的三种状态,分别是链表尾空、链表只有一个节点、链表有多个节点。为空的情况用断言处理,多个节点就正常删除头节点就行,但是要注意只有一个节点的时候要处理ptail 否则它将变成野指针

        ​​​​​​​        

2.2.5 取队头、取队尾

        ​​​​​​​        

        ​​​​​​​        

2.2.6 判断队列为空

                

2.3 队列的完整代码

        Queue.h

#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>typedef int QDataType;
typedef struct QueueNode
{QDataType val;struct QueueNode* next;
}QNode;typedef struct Queue
{QNode* phead;QNode* ptail;int size;
}Queue;//初始化
void QueueInit(Queue* pq);//销毁
void QueueDestory(Queue* pq);//入队列
void QueuePush(Queue* pq, QDataType x);//出队列
void QueuePop(Queue* pq);//取队头
QDataType QueueFront(Queue* pq);//取队尾
QDataType QueueBack(Queue* pq);//判断队列为空
bool QueueEmpty(Queue* pq);//队列中剩余元素
int QueueSize(Queue* pq);

        Queue.c

#include"Queue.h"//初始化
void QueueInit(Queue* pq)
{assert(pq);pq->phead = NULL;pq->ptail = NULL;pq->size = 0;
}//销毁
void QueueDestory(Queue* pq)
{assert(pq);QNode* cur = pq->phead;QNode* next = NULL;while (cur){next = cur->next;free(cur);cur = next;}pq->phead = NULL;pq->ptail = NULL;pq->size = 0;
}//入队列
void QueuePush(Queue* pq, QDataType x)
{assert(pq);QNode* newnode=(QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc fail");return;}newnode->val = x;newnode->next = NULL;if (pq->ptail == NULL){pq->phead = pq->ptail = newnode;}else{pq->ptail->next = newnode;pq->ptail = newnode;}pq->size++;
}//出队列
void QueuePop(Queue* pq)
{assert(pq);//保正头部有的删assert(pq->phead);QNode* next = pq->phead->next;//当只有一个节点时,要处理ptailif (pq->phead == pq->ptail){pq->ptail = NULL;}free(pq->phead);pq->phead = next;pq->size--;
}//取队头
QDataType QueueFront(Queue* pq)
{assert(pq);//取队头前提是有队头assert(pq->phead);return pq->phead->val;
}//取队尾
QDataType QueueBack(Queue* pq)
{assert(pq);//取队尾前提是有队尾assert(pq->ptail);return pq->ptail->val;
}//判断队列为空
bool QueueEmpty(Queue* pq)
{assert(pq);return pq->size == 0;
}//队列中剩余元素
int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/499377.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2023年上半年教师资格证考试《综合素质》(中学)题

1.杨老师经常担心的问题是&#xff1a;“这些内容是学生们需要的吗?”“我这样教&#xff0c;学生能接受吗?”这表明杨老师所处的教师专业发展阶段是&#xff08;C &#xff09;。 A虚拟关注阶段 B生存关注阶段 C自我更新关注阶段 D任务关注阶段 14.吴老师教学经验丰富&a…

腾讯云优惠:2024云服务器租用价格表,买前必看

一张表看懂腾讯云服务器租用优惠价格表&#xff0c;一目了然&#xff0c;腾讯云服务器分为轻量应用服务器和云服务器CVM&#xff0c;CPU内存配置从2核2G、2核4G、4核8G、8核16G、4核16G、8核32G、16核32G、16核64等配置可选&#xff0c;公网带宽1M、3M、5M、12M、18M、22M、28M…

2.1_6 线程的实现方式和多线程模型

文章目录 2.1_6 线程的实现方式和多线程模型&#xff08;一&#xff09;线程的实现方式&#xff08;1&#xff09;用户级线程&#xff08;2&#xff09;内核级线程 &#xff08;二&#xff09;多线程模型&#xff08;1&#xff09;一对一模型&#xff08;2&#xff09;多对一模…

内核打印应用程序出错信息,DEBUG_USER

前言 在 Linux 系统中&#xff0c;运行一个应用程序&#xff0c;突然提示段错误&#xff0c;并停止运行 # ./crash.out Segmentation fault如果这个时候操作系统能多提示点错误信息&#xff0c;那将会缩短我们 debug 的时间。 core dump 就是一个办法&#xff0c;可以查看我…

C# EF Core迁移数据库

现象&#xff1a; 在CodeFirst时&#xff0c;先写字段与表&#xff0c;创建数据库后&#xff0c;再添加内容 但字段与表会变更&#xff0c;比如改名删除增加等 需求&#xff1a; 当表字段变更时&#xff0c;同时变更数据库&#xff0c;执行数据库迁移 核心命令 Add-Migrat…

06|Mysql内部组件结构

1. 连接器 客户端要向mysql发起通信都必须先跟Server端建立通信连接&#xff0c;而建立连接的工作就是由连接器完成的 mysql -h host[数据库地址] -u root[用户] -p root[密码] -P 3306连接步骤: 1、如果用户名或密码不对&#xff0c;你就会收到一个"Access denied for us…

大道至简,聊聊工作中需注意的数据库开发规范

前言&#xff1a;最近要做一次数据访问组件的分享&#xff0c;想着趁此机会结合这几年的工作经历&#xff0c;好好梳理一下数据库相关的开发规范&#xff0c;之前我也写过很多这方面的文章了&#xff0c;且数据库相关的知识也没什么新意可言&#xff0c;但我之所以还是决定提笔…

Android Studio level过滤查看各个等级的日志

Android Studio level过滤查看各个等级的日志 旧版as可以在下方的日志输出框选择debug、info&#xff0c;warn、error日志&#xff0c;新版的需要通过在过滤框手动/联想输入 level:xxx&#xff0c;过滤相应等级的日志&#xff0c;如图&#xff1a; android studio/idea返回/前进…

ulimit命令

ulimit命令 ulimit 命令用于查看和设置 shell 运行时的资源限制。它可以控制各种资源&#xff0c;如文件打开数量、堆栈大小、CPU 时间等。ulimit 命令通常用于限制 shell 启动的进程的资源使用量&#xff0c;以防止系统资源被耗尽。ulimit命令的主要作用是提高系统的性能和稳…

RabbitMQ 面试八股题整理

前言&#xff1a;本文是博主网络自行收集的一些RabbitMQ相关八股文&#xff0c;还在准备暑期实习&#xff0c;后续应该会持续更新...... 参考&#xff1a;三天吃透RabbitMQ面试八股文_牛客网 目录 RabbitMQ概述 什么是 RabbitMQ&#xff1f; 说一说RabbitMQ中的AMQP 为什么…

【Vue】路由

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;Vue ⛺️稳中求进&#xff0c;晒太阳 目录 路由 单页应用程序 总结&#xff1a; VueRouter 核心步骤&#xff1a; 组件存放目录的问题 路由的封装 声明式导航 声明式导航 - 导航链…

​LeetCode解法汇总2476. 二叉搜索树最近节点查询

目录链接&#xff1a; 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目&#xff1a; GitHub - September26/java-algorithms: 算法题汇总&#xff0c;包含牛客&#xff0c;leetCode&#xff0c;lintCode等网站题目的解法和代码&#xff0c;以及完整的mode类&#…