本期我们来讲解栈和队列的实现,相比之前的变的简洁了,但整体变化不大,大家也可以看看之前写的

(1条消息) 栈和队列及其多种接口实现-c语言_KLZUQ的博客-CSDN博客

目录

栈的结构

栈的初始化

栈的销毁

入栈

出栈

栈内元素个数

判断栈是否为空

取栈顶元素

队列的结构

队列的初始化

队列的销毁

入队列

出队列

返回队列的元素个数

判断队列是否为空

取队头元素

取队尾元素

全部代码


栈的结构

我们先来看栈,栈是一种特殊的数据结构,他是后进先出的数据结构,即只能从栈尾入数据和删数据,就像我们将物品放在箱子里一样,最后放进去的物品在最上层,也就可以最先拿到,如果想要拿到最下面的,也就是最开始放进去的,就要把上面的物品全部拿走才行

typedef int STDataType;
typedef struct Stack
{STDataType* a;int top;int capacity;
}ST;

我们实现栈最好是用数组来实现,而不是链表,因为栈只需要进行入栈出栈,如果用链表的话,就是尾插尾删,但是尾删是不好处理的,所以我们使用数组更好

栈的初始化

void STInit(ST* ps) {assert(ps);ps->a = (STDataType*)malloc(sizeof(STDataType) * 4);if (ps->a == NULL) {perror("malloc fail");return;}ps->capacity = 4;ps->top = 0;  //给0代表栈顶元素的下一个//ps->top = -1;//给-1代表栈顶元素的位置
}

因为我们的栈是结构体,数据是在数组里,所以我们需要进行断言,初始空间我们选择给4(大家给几个都可以),接着将容量赋值,然后就是top的取值了,-1和0大家都可以选择

栈的销毁

void STDestroy(ST* ps) {assert(ps);free(ps->a);ps->a = NULL;ps->capacity = 0;ps->top = 0;
}

销毁我们只需释放数组的空间,然后将这些变量置为0即可

入栈

void STPush(ST* ps, STDataType x) {assert(ps);if (ps->top == ps->capacity) {STDataType* tmp = (STDataType*)realloc(ps->a,sizeof(STDataType)*ps->capacity*2);if (ps->a == NULL) {perror("realloc fail");return;}ps->a = tmp;ps->capacity *= 2;}ps->a[ps->top] = x;ps->top++;
}

入栈我们需要判断栈是否已满,满了的话我们需要扩容,我们扩2倍即可,接着就就是将数据放入栈顶,top++即可

出栈

void STPop(ST* ps) {assert(ps);assert(!STEmpty(ps));ps->top--;
}

出栈我们只需让top--即可,但是不能一直减下去,如果为空的话就不行,所以我们需要判断一下,这里我直接使用了暴力检查,大家也可以用温和一点的

栈内元素个数

int STSize(ST* ps) {assert(ps);return ps->top;
}

因为我们选择了top给0,所以这里直接返回,如果top选择了-1,这里返回+1即可

判断栈是否为空

bool STEmpty(ST* ps) {assert(ps);return ps->top == 0;
}

因为我们选则了top最初给0,所以top为0就是空,top选择-1的话等于-1就是空

取栈顶元素

STDataType STTop(ST* ps) {assert(ps);assert(!STEmpty(ps));return ps->a[ps->top-1];
}

根据top最初值的不同,这里填写的也不同,另外我们也要断言栈是否为空

我们对栈进行一下测试

这样我们的栈就完成了,是不是非常简单?

接下来我们来看队列

队列的结构

队列是一种先进先出的结构,即队列只能从队尾入数据,队头删数据

那么为了实现队列,我们是应该像栈一样继续使用数据,还是说应该使用链表呢?

我们发现,队列的删除是在头,队列的插入是在尾,所以这里使用链表更好一点,我们选择用单链表即可,我们只需要加一个尾指针

typedef int QDatatype;
typedef struct QueueNode {struct QueueNode* next;QDatatype data;
}QNode;
typedef struct Queue {QNode* head;QNode* tail;int size;
}Queue;

到这里可能就有人将链表,栈和队列的结构搞混了,为什么一会是一个结构,一会是两个结构,我们来对比一下就明白了

我们的链表,不管是不是带哨兵位,都需要一个指针即可,指向第一个指针,所以我们看到,这些链表都只需指向头节点即可,那么栈我们可以写成栈的指针吗?可以是可以,但是没必要,如果我们将栈写成指针,那么STInit就需要malloc

而需要malloc,这里就会需要传二级指针,非常麻烦,现在我们将结构体创建到了外部,已经有了结构体,所以不需要malloc,而且已经有了结构体,只需要结构体指针就可以了,数据结构是非常灵活的,写成指针的话,我们可以采用malloc传二级指针,也可以采用返回值的方式,不过相比我们写的结构来说,会比较麻烦一点

回过头来继续看我们的队列结构,队列也是一个一个的节点,所以我们定义了QNode,接着我们将QNode包装起来变为Queue,这样我们的队列就完成了,Queue里有两个指针,一个指向队列的头,一个指向队列的尾,最后我们可以加一个size,也是有好处的

队列的初始化

void QueueInit(Queue* pq) {assert(pq);pq->head = pq->tail = NULL;pq->size = 0;
}

我们传的是结构体的指针,所以是绝对不会为空,所以我们要进行断言,后续同理,就不再啰嗦

队列的销毁

void QueueDestroy(Queue* pq) {assert(pq);QNode* cur = pq->head;while (cur) {QNode* next = cur->next;free(cur);cur = next;}pq->head = pq->tail = NULL;pq->size = 0;
}

队列的销毁和链表的销毁很像,我们一个一个释放即可

入队列

void QueuePush(Queue* pq, QDatatype x) {QNode* newnode =(QNode*) malloc(sizeof(QNode));if (newnode == NULL) {perror("malloc fail");return;}newnode->data = x;newnode->next = NULL;if (pq->head == NULL) {assert(pq->tail==NULL);pq->head = pq->tail = newnode;}else {pq->tail->next = newnode;pq->tail = newnode;} pq->size++;
}

入队列就是尾插,我们创建新节点,新节点初始化后,连接到队列的尾部,再更新尾即可,但是基于我们队列最开始时head和tail都可能为空,所以我们要进行判断,如果队列是空,我们将新节点赋给头尾即可,我们在判断队列是否为空时,判断头或者尾有一个为空即可,两个都判断也可以,我这里就是两个都判断了,先判断了头,如果头为空,但是尾不是空,那就说明出问题了

出队列

void QueuePop(Queue* pq) {assert(pq);assert(pq->head!=NULL);/*Queue* next = pq->head->next;free(pq->head);pq->head = next;if (pq->head == NULL) {pq->tail = NULL;}*/if (pq->head->next == NULL) {free(pq->head);pq->head = pq->tail = NULL;}else {Queue* next = pq->head->next;free(pq->head);pq->head = next;}pq->size--;
}

出队列就是头删,我们保存头节点的下一个然后进行删除即可,但是如果是最后一个节点的话,tail就会变为野指针,所以我们需要单独判断,这里有两种写法,大家选一种喜欢的即可

返回队列的元素个数

void QueueSize(Queue* pq) {assert(pq);return pq->size;
}

因为我们最开始定义了size,所以这里非常简单,如果没有定义的话,只能遍历去数

判断队列是否为空

bool QueueEmpty(Queue* pq) {assert(pq);return pq->size == 0;
}

同样的,这里也可以使用size来判断,或者对队列的头和尾均为空来判断也是可以的

取队头元素

QDatatype QueueFront(Queue* pq) {assert(pq);assert(!QueueEmpty(pq));return pq->head->data;
}

我们要对队列进行判空,不为空我们才能取数据

取队尾元素

QDatatype QueueBack(Queue* pq) {assert(pq);assert(!QueueEmpty(pq));return pq->tail->data;
}

与取队头元素同理

接着我们对队列进行测试

以上皆为本期全部内容,希望大家可以有所收获,最后附上全部代码

全部代码

//stack.h
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
typedef int STDataType;
typedef struct Stack
{STDataType* a;int top;int capacity;
}ST;
void STInit(ST* ps);
void STDestroy(ST* ps);
void STPush(ST* ps, STDataType x);
void STPop(ST* ps);
int STSize(ST* ps);
bool STEmpty(ST* ps);
STDataType STTop(ST* ps);
//stack.c
#include"stack.h"void STInit(ST* ps) {assert(ps);ps->a = (STDataType*)malloc(sizeof(STDataType) * 4);if (ps->a == NULL) {perror("malloc fail");return;}ps->capacity = 4;ps->top = 0;  //给0代表栈顶元素的下一个//ps->top = -1;//给-1代表栈顶元素的位置
}
void STDestroy(ST* ps) {assert(ps);free(ps->a);ps->a = NULL;ps->capacity = 0;ps->top = 0;
}
void STPush(ST* ps, STDataType x) {assert(ps);if (ps->top == ps->capacity) {STDataType* tmp = (STDataType*)realloc(ps->a,sizeof(STDataType)*ps->capacity*2);if (ps->a == NULL) {perror("realloc fail");return;}ps->a = tmp;ps->capacity *= 2;}ps->a[ps->top] = x;ps->top++;
}
void STPop(ST* ps) {assert(ps);assert(!STEmpty(ps));ps->top--;
}
int STSize(ST* ps) {assert(ps);return ps->top;
}
bool STEmpty(ST* ps) {assert(ps);return ps->top == 0;
}
STDataType STTop(ST* ps) {assert(ps);assert(!STEmpty(ps));return ps->a[ps->top-1];
}
//queue.h
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>typedef int QDatatype;
typedef struct QueueNode {struct QueueNode* next;QDatatype data;
}QNode;
typedef struct Queue {QNode* head;QNode* tail;int size;
}Queue;void QueueInit(Queue* pq);
void QueueDestroy(Queue* pq);
void QueuePush(Queue* pq,QDatatype x);
void QueuePop(Queue* pq);
void QueueSize(Queue* pq);
bool QueueEmpty(Queue* pq);
QDatatype QueueFront(Queue* pq);
QDatatype QueueBack(Queue* pq);
//queue.c
#include"queue.h"void QueueInit(Queue* pq) {assert(pq);pq->head = pq->tail = NULL;pq->size = 0;
}
void QueueDestroy(Queue* pq) {assert(pq);QNode* cur = pq->head;while (cur) {QNode* next = cur->next;free(cur);cur = next;}pq->head = pq->tail = NULL;pq->size = 0;
}
void QueuePush(Queue* pq, QDatatype x) {QNode* newnode =(QNode*) malloc(sizeof(QNode));if (newnode == NULL) {perror("malloc fail");return;}newnode->data = x;newnode->next = NULL;if (pq->head == NULL) {assert(pq->tail==NULL);pq->head = pq->tail = newnode;}else {pq->tail->next = newnode;pq->tail = newnode;}pq->size++;
}
void QueuePop(Queue* pq) {assert(pq);assert(pq->head!=NULL);/*Queue* next = pq->head->next;free(pq->head);pq->head = next;if (pq->head == NULL) {pq->tail = NULL;}*/if (pq->head->next == NULL) {free(pq->head);pq->head = pq->tail = NULL;}else {Queue* next = pq->head->next;free(pq->head);pq->head = next;}pq->size--;
}
void QueueSize(Queue* pq) {assert(pq);return pq->size;
}
bool QueueEmpty(Queue* pq) {assert(pq);return pq->size == 0;
}
QDatatype QueueFront(Queue* pq) {assert(pq);assert(!QueueEmpty(pq));return pq->head->data;
}
QDatatype QueueBack(Queue* pq) {assert(pq);assert(!QueueEmpty(pq));return pq->tail->data;
}

如有错误,还请指正

栈和队列-----重制版相关推荐

  1. 《大话数据结构》读书笔记-栈与队列

    写在前面:本文仅供个人学习使用.<大话数据结构>通俗易懂,适合整体做笔记输出,构建体系.并且文中很多图片来源于该书. 文章目录 4.2栈的定义 4.2.1 栈的定义 4.2.2 进栈出栈变 ...

  2. 用栈实现队列与用队列实现栈

    一.用栈实现队列 用栈实现队列的思路是用两个栈,只是在出队的时候,将第一个栈中的元素移动到另一个栈中,在从第二个栈中出栈就可以了. import java.util.Stack;public clas ...

  3. 笨办法学 Python · 续 练习 15:栈和队列

    练习 15:栈和队列 原文:Exercise 15: Stacks and Queues 译者:飞龙 协议:CC BY-NC-SA 4.0 自豪地采用谷歌翻译 当处理数据结构时,你将经常遇到类似于另一 ...

  4. 数据结构——栈和队列

    目录 1.栈 1.1栈的基本概念 1.2栈的顺序存储实现 1.3共享栈 1.4栈的链式存储实现 1.5栈在括号匹配中的应用 1.6栈在表达式求值中的应用 1.6.1中.前.后缀表达式 1.6.2后缀表 ...

  5. 数据结构 (3)栈与队列之粗心的人如何写oj血的教训

    栈 栈是种特殊的线性表,他先入后出,后进先出 入数据为压栈,且在栈顶入,出数据为弹栈或者出栈,且在栈顶出 栈好比是枪,压子弹为入栈,射击为出栈 压栈 出栈 就像你啃鸡爪子一样,你从包装袋里拿出来,从上 ...

  6. 栈和队列---算法题目

    1.设计一个有getMin功能的栈 1.解题思路 方案一: push:将每次插入的新值和stackMin的栈顶元素比较,如果新值较小就插入到stackMin,否则什么也不干 pop:stackData ...

  7. 【数据结构】栈和队列

    目录 前言 一.栈 1.理解栈 栈的特点 2.实现栈 实现思路 C语言实现 ★Stack.h(头文件)代码实现: ★Stack.c(实现功能文件)代码实现: 测试代码: 二.队列 1.理解队列 队列的 ...

  8. 迷宫(栈、队列、递归3种方法)和八皇后(栈和递归2种方法)的C/C++描述(上)

    ***迷宫: 栈是只能在一端进行添加元素和删除元素的表,分顺序栈和链式栈.程序里变量命名应该长一些,做到见名知意.提高程序阅读性.本文用栈的方法存储路径中每一步,栈中每个元素是结构体变量,包含每一步的 ...

  9. 数据结构(一)——链表与邻接表、栈与队列、KMP

    前言 重学算法第3天,希望能坚持打卡不间断,从基础课开始直到学完提高课. 预计时长三个月内,明天再来!肝就完了 2月15日,day03 打卡 今日已学完y总的 算法基础课-2.1-第二章 数据结构(一 ...

最新文章

  1. 形象解释Momentum
  2. matlab氢原子杂化轨道,网络版原子和分子结构可视化程序的开发
  3. 解决Genymotion下载设备失败的方法(Connection Timeout)
  4. 与Min_25筛有关的一些模板
  5. python必背语法_python常用语法合集
  6. 使用Web API ASP.NET Core 2.2部署Angular 8应用程序
  7. tex中让公式和文字在一行_1行代码搞定LaTeX公式编写,这个4.6M的Python小插件,堪称论文必备神器...
  8. 海德薇格:我很期待看到 数字货币将如何改变人民币支付市场
  9. android Intent的介绍
  10. hive排序:distribute by 、sort by 、cluster by 、order by 区别
  11. maven项目对象模型(二)
  12. 如何在JPG或BMP图片上显示输入的订单数据内容,并在报表打印时显示出来,后台数据库是SQL SERVER 2000 ,先谢了.高分!...
  13. 图像任意角度旋转和翻转(C#)
  14. ps3本服务器维修中,PS3大拆解图文详解!降低成本为目的
  15. linux系统无线网卡驱动安装,在linux上怎么安装无线网卡驱动?
  16. ROS简介(新手入门须知)
  17. 替代满足、稀缺冲动、从众效应、思考快与慢就不怕退货吗?
  18. easypoi导入图片_原生POI / EasyPOI 简单上手使用
  19. HDU5142 NPY and arithmetic progression BestCoder Round #23 1002
  20. php报表插件,excel插件

热门文章

  1. SpringBoot使用Redis清除所有缓存
  2. python设置文件名长度对齐
  3. 数据结构:栈的实现及应用场景
  4. B - Better Students Are Needed!
  5. lab12——幽灵攻击
  6. DQN算法流程及原理
  7. 长文对话实录:国内物联网10年沉浮,AIoT技术如何破局?| AIoT+智慧城市峰会
  8. centos中用C/C++语言连接MySQL/MariaDB数据库
  9. 引导宝宝好状态拍摄?
  10. 三位数的排列组合排列