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

数据结构与算法——栈和队列

文章目录

  • 一、前言
  • 二、栈
    • 栈的概念
    • 栈的结构
  • 三、用数组实现栈
    • 3.1栈的初始化
    • 3.2入栈
    • 3.3栈的判空
    • 3.4出栈
    • 3.5取栈顶元素
    • 3.6获取栈中有效元素个数
    • 3.7栈的销毁
  • 四、栈的整体代码分析
    • 4.1头文件——Stack.h及代码展示
    • 4.2主体代码文件Stack.c及代码展示
    • 4.3测试文件test.c及代码展示
      • 4.3.1初始化测试
      • 4.3.2入栈测试
      • 4.3.3出栈测试
      • 4.3.4取栈顶元素测试
      • 4.3.5获取有效个数测试
      • 4.3.6栈的销毁测试
      • 4.3.7test.c整体代码
  • 五、队列
    • 5.1队列的概念
    • 5.2队列的结构
  • 六、用链表实现队列
    • 6.1队列的初始化
    • 6.2入队
    • 6.3队列的判空
    • 6.4出队
    • 6.5取队头元素
    • 6.6取队尾元素
    • 6.7获取队列中有效元素个数
    • 6.8队列的销毁
  • 七、队列的整体代码分析
    • 7.1头文件——Queue.h及代码展示
    • 7.2主体代码文件——Queue.c及代码展示
    • 7.3测试文件——test.c及代码展示
      • 7.3.1初始化测试
      • 7.3.2入队测试
      • 7.3.3出队列测试
      • 7.3.4取队头元素测试
      • 7.3.5取队尾元素测试
      • 7.3.6获取有效个数测试
      • 7.3.7队列的销毁测试
      • 7.3.8test.c整体代码
  • 八、总结

一、前言

Hello啊!还是那句老掉牙的开场白——今天的你还在努力学习吗?可不能半途而废哦! 如果你正在迷茫,请看看下面这句话——未知的领域是学习的源泉,保持好奇,永远在学习的路上。现在你是否又满血复活了呢?ok那现在我们接着继续学习数据结构与算法,今天up要给大家介绍的内容则是——栈和队列

二、栈

栈的概念

栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。。
压栈:向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素,入的数据在栈顶。
出栈:从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素,出的数据也在栈顶。
栈满足后进先出或者先进后出的原则。

栈的结构

在这里插入图片描述

三、用数组实现栈

3.1栈的初始化

在我们用数组来实现栈的时候,那我们该如何初始化呢?
代码展示:

void StackInit(ST* ps)//栈的初始化
{ps->arr = NULL;//初始化数组ps->top = 0;//栈顶ps->capacity = 0;//栈的容量大小
}

栈的初始化实质把数组arr初始化为NULL,栈顶指针初始化为0,栈的空间大小也初始化为0。

3.2入栈

画图展示:
在这里插入图片描述
代码展示:

void StackPush(ST* ps, STDataType x)//入栈
{assert(ps);if (ps->top == ps->capacity)//判断栈空间是否已满{int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;STDataType* tmp = (STDataType*)realloc(ps->arr, newcapacity*sizeof(STDataType));//增容if (tmp == NULL){printf("realloc fail!");exit(1);}ps->arr = tmp;ps->capacity = newcapacity;}ps->arr[ps->top++] = x;
}

入栈的实质在栈空间未满的情况下,直接把元素插入栈顶即可;在栈空间已满的情况下,先进行二倍增容,在把元素插入栈顶,top++。

3.3栈的判空

画图展示:
在这里插入图片描述
代码展示:

bool Stackempty(ST* ps)//判空
{assert(ps);return ps->top == 0;
}

栈的判空实质:在栈这块空间指向不为空的情况下:看栈顶指针top是否为0即可,为0则为空,反之不为空。

3.4出栈

画图展示:
在这里插入图片描述
代码展示:

void StackPop(ST* ps)//出栈
{assert(!Stackempty(ps));--ps->top;
}

出栈的实质:在判断栈不为空的情况下:直接把元素从栈顶删除即可,top–。

3.5取栈顶元素

代码展示:

STDataType StackTop(ST* ps)//取栈顶元素
{assert(!Stackempty(ps));return ps->arr[ps->top - 1];
}

取栈顶元素实质:在判断栈不为空的情况下,直接返回栈顶元素即可。

3.6获取栈中有效元素个数

代码展示:

int Stacksize(ST* ps)//获取栈中元素个数
{assert(ps);return ps->top;
}

获取栈中有效个数实质:top的值的大小就是栈中元素个数的大小,直接返回top值即可。

3.7栈的销毁

画图展示:
在这里插入图片描述

代码展示:

void Stackdestroy(ST* ps)//栈的销毁
{if (ps->arr){free(ps->arr);}ps->arr = NULL;ps->top = 0;ps->capacity = 0;
}

栈的销毁实质:在数组不为空的情况下,先把数组置为空(NULL),再把top和capacity也置为0即可。

四、栈的整体代码分析

4.1头文件——Stack.h及代码展示

在这里插入图片描述
代码展示:

//Stack.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
typedef int STDataType;
typedef struct Stack
{STDataType* arr;int top;int capacity;
}ST;
void StackInit(ST* ps);//栈的初始化
void Stackdestroy(ST* ps);//栈的销毁
void StackPush(ST* ps, STDataType x);//入栈
bool Stackempty(ST* ps);//判空
void StackPop(ST* ps);//出栈
STDataType StackTop(ST* ps);//取栈顶元素
int Stacksize(ST* ps);//获取栈中元素个数

4.2主体代码文件Stack.c及代码展示

在这里插入图片描述
代码展示:

//stack.c
#include "Stack.h"
void StackInit(ST* ps)//栈的初始化
{ps->arr = NULL;//初始化数组ps->top = 0;//栈顶ps->capacity = 0;//栈的容量大小
}
void Stackdestroy(ST* ps)//栈的销毁
{if (ps->arr){free(ps->arr);}ps->arr = NULL;ps->top = 0;ps->capacity = 0;
}
void StackPush(ST* ps, STDataType x)//入栈
{assert(ps);if (ps->top == ps->capacity)//判断栈空间是否已满{int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;STDataType* tmp = (STDataType*)realloc(ps->arr, newcapacity*sizeof(STDataType));//增容if (tmp == NULL){printf("realloc fail!");exit(1);}ps->arr = tmp;ps->capacity = newcapacity;}ps->arr[ps->top++] = x;
}
bool Stackempty(ST* ps)//判空
{assert(ps);return ps->top == 0;
}
void StackPop(ST* ps)//出栈
{assert(!Stackempty(ps));--ps->top;
}
STDataType StackTop(ST* ps)//取栈顶元素
{assert(!Stackempty(ps));return ps->arr[ps->top - 1];
}
int Stacksize(ST* ps)//获取栈中元素个数
{assert(ps);return ps->top;
}

4.3测试文件test.c及代码展示

4.3.1初始化测试

在这里插入图片描述

	StackInit(&st);//初始化

4.3.2入栈测试

在这里插入图片描述

StackPush(&st, 1);//入栈
StackPush(&st, 2);
StackPush(&st, 3);
StackPush(&st, 4);

4.3.3出栈测试

在这里插入图片描述

StackPop(&st);//出栈
StackPop(&st);
StackPop(&st);

4.3.4取栈顶元素测试

在这里插入图片描述

if(!Stackempty(&st))//判空+取栈顶元素
{int top = StackTop(&st);printf("%d\n", top);
}

4.3.5获取有效个数测试

在这里插入图片描述

	int size = Stacksize(&st);//获取有效个数printf("%d\n", size);

4.3.6栈的销毁测试

在这里插入图片描述

	Stackdestroy(&st);//栈的销毁

4.3.7test.c整体代码

请根据自己的需求合理注释再进行测试。

test.c
#include "Stack.h"
void test01()
{ST st;StackInit(&st);StackPush(&st, 1);StackPush(&st, 2);StackPush(&st, 3);StackPush(&st, 4);//StackPop(&st);//StackPop(&st);//StackPop(&st);//if(!Stackempty(&st))//{//	int top = StackTop(&st);//	printf("%d\n", top);//}//int size = Stacksize(&st);//printf("%d\n", size);Stackdestroy(&st);
}
int main()
{test01();return 0;
}

五、队列

5.1队列的概念

队列是一种特殊的线性表,他只允许在一端插入数据,在另一端删除数据。
入队列:在队尾进行插入操作。
出队列:在对头进行删除操作。
因此,队列满足先进先出的原则。

5.2队列的结构

在这里插入图片描述
在这里插入图片描述

六、用链表实现队列

6.1队列的初始化

void QueueInit(Queue* pq)//队列初始化
{assert(pq);pq->phead = NULL;pq->ptail = NULL;
}

队列的初始化实质:当队列这块空间指向不为空的情况下:把对头结点指针和队尾结点指针都置为NULL即可。

6.2入队

画图展示:
在这里插入图片描述
在这里插入图片描述

代码展示:

void QueuePush(Queue* pq, QDataType x)//入队
{assert(pq);QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));//创建新结点if (newnode == NULL){printf("malloc fail!");exit(1);}newnode->data = x;newnode->next = NULL;if (pq->phead == NULL){pq->phead = pq->ptail = newnode;}else{pq->ptail->next = newnode;pq->ptail = pq->ptail->next;}
}

入队的实质:在队列这块空间指向不为空的情况下:将新节点newnode的地址放入队尾ptail结点的ptail->next中,再让新节点newnode成为新的队尾ptail即可。

6.3队列的判空

代码展示:

bool Queueempty(Queue* pq)//判空
{assert(pq);return pq->phead == NULL;
}

判空的实质:当队列指向的这块空间不为空的情况下:判断队头是否为空,若队头为空则队列为空,反之队列不为空。

6.4出队

画图展示:

在这里插入图片描述

代码展示:

void QueuePop(Queue* pq)//出队
{assert(!Queueempty(pq));if (pq->phead == pq->ptail){free(pq->phead);pq->phead = pq->ptail = NULL;}else{QueueNode* next = pq->phead->next;free(pq->phead);pq->phead = next;}
}

出队的实质:在判断栈不为空的情况下:如果队列只有一个结点,直接将这个结点释放掉,队头(pq->phead)和队尾(pq->ptail)都置为空即可;如果队列不止一个结点,先把队头的下一个结点的地址用next指针保存下来,再将队头给释放掉,最后再让next指针成为新的队头指针即可。

6.5取队头元素

代码展示:

QDataType QueueFront(Queue* pq)//取对头数据
{assert(!Queueempty(pq));return pq->phead->data;
}

取队头元素实质:在判断队列不为空的情况下:直接返回队头所指向的数据值pq->phead->data即可。

6.6取队尾元素

代码展示:

QDataType QueueBack(Queue* pq)//取队尾数据
{assert(!Queueempty(pq));return pq->ptail->data;
}

取队尾元素实质:在判断队列不为空的情况下:直接返回队尾所指向的数据值pq->ptail->data即可。

6.7获取队列中有效元素个数

代码展示:

int Queuesize(Queue* pq)//计算队列有效个数
{assert(pq);QueueNode* pcur = pq->phead;int size = 0;while (pcur){size++;pcur = pcur->next;}return size;
}

获取队列中有效元素个数实质:在队列所指向的这块空间不为空的情况下:定义一个开始指针pcur从队头开始,再定义一个size值来累计元素个数,依次遍历整个队列,只要pcur不为空,size就累加,反之停止。

6.8队列的销毁

画图展示:
在这里插入图片描述
代码展示:

void QueueDestroy(Queue* pq)//队列的销毁
{assert(pq);QueueNode* pcur = pq->phead;while (pcur){QueueNode* next = pcur->next;free(pcur);pcur = next;}pq->phead = NULL;pq->ptail = NULL;
}

队列的销毁实质:当队列所指向的空间这块不为空的情况下:定义一个开始指针pcur从队头开始,再定义一个next指针保存队头的下一个结点,当pcur不为空时,将队头直接释放掉,然后让next成为新的队头,依次循环遍历整个队列,直到pcur为空时停止

七、队列的整体代码分析

7.1头文件——Queue.h及代码展示

在这里插入图片描述

//Queue.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
typedef int QDataType;
typedef struct QueueNode//定义结点
{QDataType data;struct QueueNode* next;
}QueueNode;
typedef struct Queue
{QueueNode* phead;//定义队头队尾指针QueueNode* ptail;
}Queue;
void QueueInit(Queue* pq);//队列初始化
void QueueDestroy(Queue* pq);//队列的销毁
void QueuePush(Queue* pq, QDataType x);//入队
bool Queueempty(Queue* pq);//判空
void QueuePop(Queue* pq);//出队
QDataType QueueFront(Queue* pq);//取对头数据
QDataType QueueBack(Queue* pq);//取队尾数据
int Queuesize(Queue* pq);//计算队列有效个数

7.2主体代码文件——Queue.c及代码展示

在这里插入图片描述

//Queue.c
#include "Queue.h"
void QueueInit(Queue* pq)//队列初始化
{assert(pq);pq->phead = NULL;pq->ptail = NULL;
}
void QueueDestroy(Queue* pq)//队列的销毁
{assert(pq);QueueNode* pcur = pq->phead;while (pcur){QueueNode* next = pcur->next;free(pcur);pcur = next;}pq->phead = NULL;pq->ptail = NULL;
}
void QueuePush(Queue* pq, QDataType x)//入队
{assert(pq);QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));//创建新结点if (newnode == NULL){printf("malloc fail!");exit(1);}newnode->data = x;newnode->next = NULL;if (pq->phead == NULL){pq->phead = pq->ptail = newnode;}else{pq->ptail->next = newnode;pq->ptail = pq->ptail->next;}
}
bool Queueempty(Queue* pq)//判空
{assert(pq);return pq->phead == NULL;
}
void QueuePop(Queue* pq)//出队
{assert(!Queueempty(pq));if (pq->phead == pq->ptail){free(pq->phead);pq->phead = pq->ptail = NULL;}else{QueueNode* next = pq->phead->next;free(pq->phead);pq->phead = next;}
}
QDataType QueueFront(Queue* pq)//取对头数据
{assert(!Queueempty(pq));return pq->phead->data;
}
QDataType QueueBack(Queue* pq)//取队尾数据
{assert(!Queueempty(pq));return pq->ptail->data;
}
int Queuesize(Queue* pq)//计算队列有效个数
{assert(pq);QueueNode* pcur = pq->phead;int size = 0;while (pcur){size++;pcur = pcur->next;}return size;
}

7.3测试文件——test.c及代码展示

7.3.1初始化测试

在这里插入图片描述

Queue q;
QueueInit(&q);//初始化

7.3.2入队测试

在这里插入图片描述

QueuePush(&q, 1);//入队列
QueuePush(&q, 2);
QueuePush(&q, 3);
QueuePush(&q, 4);

7.3.3出队列测试

在这里插入图片描述

QueuePop(&q);//出队列
QueuePop(&q);

7.3.4取队头元素测试

在这里插入图片描述

	int front = QueueFront(&q);//取队头元素printf("%d\n", front);

7.3.5取队尾元素测试

在这里插入图片描述

	int rear = QueueBack(&q);//取队尾元素printf("%d\n", rear);

7.3.6获取有效个数测试

在这里插入图片描述

	int sizenum = Queuesize(&q);//获取有效个数printf("%d\n", sizenum);

7.3.7队列的销毁测试

在这里插入图片描述

QueueDestroy(&q);//队列销毁

7.3.8test.c整体代码

请根据自己的需求合理注释再进行测试。

//test.c
#include "Queue.h"
void test01()
{Queue q;QueueInit(&q);QueuePush(&q, 1);QueuePush(&q, 2);QueuePush(&q, 3);QueuePush(&q, 4);QueuePop(&q);QueuePop(&q);//int front = QueueFront(&q);//printf("%d\n", front);//int rear = QueueBack(&q);//printf("%d\n", rear);//int sizenum = Queuesize(&q);//printf("%d\n", sizenum);QueueDestroy(&q);
}
int main()
{test01();return 0;
}

八、总结

Ok啊兄弟们,随着你们看到总结的到来,数据结构与算法——栈和队列的讲解也就结束了。虽然这一节涉及到了两个数据结构,但是整体理解起来还是比较easy。希望大家好好消化,增强自身。I believe you!

错误经不起失败,但是真理却不怕失败。
在这里插入图片描述

相关文章:

  • 如何高效的处理海量数据?
  • mapbox基础,加载视频到地图
  • 贪心算法day11(用最少数量的箭引爆气球)
  • python脚本补充
  • 十二,<FastApi>中间件
  • GCC 使用说明:常用参数详解与最佳实践
  • 66.加1
  • js中显示为[object Object]
  • linux下使用php修改php.ini的session.save_path无效的解决办法
  • 6.(vue3.x+vite)动态挂载组件并传递参数和方法
  • RK3588RK3576实现 HW-ID DTB(动态加载不同的Kernel DTB)功能
  • 使用基数树优化高并发内存池(替代加锁访问的哈希表和红黑树)
  • 通过导入 Excel 的方式复制文件或文件夹
  • 面试题:C++11在C++98基础上增加了哪些内容?
  • ChatUI 3.0 正式发布,“对话式交互” 开源组件库
  • MCP 协议知识分享
  • python scikit-learn中常用的数据集
  • LeetCode算法题(Go语言实现)_50
  • 什么是车规级MCU?STM32也能上车规级场景?
  • 模拟电路需要了解的一些基础知识(部分)
  • 建设网站怎么学/上海网络推广服务
  • 宁波住房与城乡建设部网站/郑州竞价托管
  • 郑州网站公司排名/品牌推广运营策划方案
  • 昊源建设监理有限公司网站/怎么让百度搜出自己
  • 哪个做app的网站好/怎样推广自己的商城
  • 绍兴网站建设网站/实时热榜