【数据结构】栈和队列超详解!(Stack Queue)

文章目录

  • 前言
  • 一、栈
    • 1、栈的基本概念
    • 2、栈的实现(数组实现)
    • 3、栈的基本操作
      • 3.1 栈的结构设计
      • 3.2 栈常见的基本函数接口
    • 4、栈的实现
      • 4.1 初始化栈
      • 4.2 栈的销毁
      • 4.3 入栈
      • 4.4 出栈
      • 4.5 判空
      • 4.6 长度
      • 4.7 获取栈顶元素
  • 完整代码
      • Stack.h
      • Stack.c
      • Test.c
  • 二、队列
    • 1、队列的结构及概念
    • 2、队列的实现(单链表实现)
      • 1、队列的链式结构设计
      • 2、常用的功能接口
        • 2.1、初始化队列
        • 2.2、销毁队列
        • 2.3、入队列
        • 2.4、出队列
        • 2.5、获取队列头部元素
        • 2.6、获取队列尾部元素
        • 2.7、判空
        • 2.8、获取有效元素个数
    • 完整代码
      • Queue.h
      • Queue.c
      • Test.c


前言

在这里插入图片描述


一、栈

1、栈的基本概念

:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则
压栈栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈栈的删除操作叫做出栈。出数据也在栈顶

在这里插入图片描述

2、栈的实现(数组实现)

栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小
在这里插入图片描述

3、栈的基本操作

压栈:栈的插入操作,也叫进栈/入栈/压栈,在栈顶进行数据操作。
出栈:栈的删除操作,也是在栈顶进行数据删除的。

3.1 栈的结构设计

typedef int STDataType;//方便修改类型
typedef struct Stack
{STDataType* a;int top;int capacity;
}ST;

3.2 栈常见的基本函数接口

//初始化
void STInit(ST* pst);
//销毁栈
void STDestroy(ST* pst);
//入栈
void STPush(ST* pst, STDataType x);
//出栈
void STPop(ST* pst);
//判空
bool STEmpty(ST* pst);
//长度
int STSize(ST* pst);
//栈顶
STDataType STTop(ST* pst);

4、栈的实现

4.1 初始化栈

//初始化
void STInit(ST* pst)
{assert(pst);pst->a = NULL;pst->top = 0;//指向栈顶下一个元素,若等于-1则指向栈顶元素,两种任选pst->capacity = 0;
}

4.2 栈的销毁

//销毁栈
void STDestroy(ST* pst)
{assert(pst);tree(pst->a);pst->a = NULL;pst->top = 0;pst->capacity = 0;
}

4.3 入栈

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

void STPush(ST* pst, STDataType x)
{assert(pst);//判断栈是否已满,满了就扩容if (pst->top == pst->capacity){//使用三目运算符进行第一次开辟空间和后续扩容空间int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;STDataType* tmp = (STDataType*)realloc(pst->a, sizeof(STDataType) * newcapacity);//判断realloc是否开辟成功if (tmp == NULL){perror("realloc fail");return;}//赋新值pst->a = tmp;pst->capacity = newcapacity;}//插入pst->a[pst->top] = x;pst->top++;
}

4.4 出栈

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

//出栈
void STPop(ST* pst)
{assert(pst);assert(pst->top > 0);pst->top--;
}

4.5 判空

//判空
bool STEmpty(ST* pst)
{assert(pst);  //返回值为0为假,非零为真return pst->top == 0;
}

4.6 长度

//长度
int STSize(ST* pst)
{assert(pst);return pst->top;
}

4.7 获取栈顶元素

注意:若栈顶指针初始化为pst->top = 0,即栈顶指针指向栈顶元素的下一个位置,则入栈操作变为pst->a[pst->top++],出栈操作为pst->a[- -pst->top]。因为栈顶指针若初始化为 0 时,则栈顶指针始终指向顺序栈将要入栈的位置,也就是栈顶指针的下标就是入栈元素的下标。

//栈顶
STDataType STTop(ST* pst)
{assert(pst);return pst->a[pst->top - 1];
}

完整代码

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* pst);
//销毁栈
void STDestroy(ST* pst);
//入栈
void STPush(ST* pst, STDataType x);
//出栈
void STPop(ST* pst);
//判空
bool STEmpty(ST* pst);
//长度
int STSize(ST* pst);
//栈顶
STDataType STTop(ST* pst);

Stack.c

#include"Stack.h"//初始化
void STInit(ST* pst)
{assert(pst);pst->a = NULL;pst->top = 0;//指向栈顶下一个元素pst->capacity = 0;
}
//销毁栈
void STDestroy(ST* pst)
{assert(pst);tree(pst->a);pst->a = NULL;pst->top = 0;pst->capacity = 0;
}
//入栈
void STPush(ST* pst, STDataType x)
{assert(pst);if (pst->top == pst->capacity){int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;STDataType* tmp = (STDataType*)realloc(pst->a, sizeof(STDataType) * newcapacity);if (tmp == NULL){perror("realloc fail");return;}pst->capacity = newcapacity;pst->a = tmp;}pst->a[pst->top] = x;pst->top++;	
}
//出栈
void STPop(ST* pst)
{assert(pst);assert(pst->top > 0);pst->top--;
}
//判空
bool STEmpty(ST* pst)
{assert(pst);return pst->top == 0;
}
//长度
int STSize(ST* pst)
{assert(pst);return pst->top;
}
//栈顶
STDataType STTop(ST* pst)
{assert(pst);return pst->a[pst->top - 1];
}

Test.c

#include"Stack.h"int main()
{ST st;//初始化STInit(&st);//插入+删除STPush(&st, 1);STPush(&st, 2);STPush(&st, 3);STPush(&st, 4);STPush(&st, 5);STPop(&st);STPop(&st);//长度STSize(&st);//栈顶STTop(&st);//销毁STDestroy(&st);return 0;
}

二、队列

1、队列的结构及概念

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头
在这里插入图片描述

2、队列的实现(单链表实现)

队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。
在这里插入图片描述
下面话不多说,直接开始代码实现

1、队列的链式结构设计

//链式结构 表示队列
typedef int QDataType;
typedef struct QueueNode
{struct QueueNode* next;QDataType val;                                                                          
}QNode;
//队列的结构
typedef struct Queue
{QNode* phead;QNode* ptail;int size;
}Queue;

2、常用的功能接口

//初始化
void QueueInit(Queue* pq);
//销毁队列
void QueueDeatroy(Queue* pq);
//队尾入列
void QueuePush(Queue* pq, QDataType x);
//队头出列
void QueuePop(Queue* pq);
//获取队列头部元素
QDataType QueueFront(Queue* pq);
//获取队列尾部元素
QDataType QueueBack(Queue* pq);
//检测队列是否为空,如果为空返回非零结果,如果非空返回0 
bool QueueEmpty(Queue* pq);
//获取队列中有效元素个数
int QueueSize(Queue* pq);
2.1、初始化队列

只需要将头尾指针都指向空即可,元素个数为零

//初始化
void QueueInit(Queue* pq)
{assert(pq);pq->phead = NULL;pq->ptail = NULL;pq->size = 0;
}
2.2、销毁队列

遍历链表,从头到尾依次删除结点,最后将头尾指针指向空,元素个数为0。

//销毁队列
void QueueDeatroy(Queue* pq)
{assert(pq);QNode* cur = pq->phead;while (cur){QNode* next = cur->next;free(cur);cur = next;}pq->phead = NULL;pq->ptail = NULL;pq->size = 0;}
2.3、入队列

创建新节点,若队列为空,则将头指针和尾指针都指向新创建的节点,若不为空,则尾插,因为是链式存储,所以和单链表的尾插一样,将尾指针的next指向该节点,再把该节点设为新的尾节点

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->ptail = pq->phead = newnode;}else{pq->ptail->next = newnode;pq->ptail = newnode;}pq->size++;
}
2.4、出队列

注意:出列要考虑队列是空还是只有一个结点又或者有多个结点,为空则在代码第一步就报错,若只有一个结点,则直接删除该结点,并将头尾俩指针指向空,若不止一个结点,可以创建一个临时指针来记录当前头指针,然后尾指针往后遍历,再free掉创建的临时指针,并置空

void QueuePop(Queue* pq)
{assert(pq);assert(pq->phead);QNode* del = pq->phead;pq->phead = pq->phead->next;free(del);del = NULL;if (pq->phead == NULL)pq->ptail = NULL;pq->size--;
}
2.5、获取队列头部元素

断言,然后直接返回队头指针指向的节点元素

//获取队列头部元素
QDataType QueueFront(Queue* pq)
{assert(pq);assert(pq->phead);return pq->phead->val;
}
2.6、获取队列尾部元素

也是一样的,直接返回队尾指针指向的节点元素

//获取队列尾部元素
QDataType QueueBack(Queue* pq)
{assert(pq);assert(pq->phead);return pq->ptail->val;
}
2.7、判空

检测队列是否为空,如果为空返回非零结果,如果非空返回0


bool QueueEmpty(Queue* pq)
{assert(pq);return pq->phead == NULL;
}
2.8、获取有效元素个数
//获取队列中有效元素个数
int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}

完整代码

Queue.h

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>//链式结构 表示队列
typedef int QDataType;
typedef struct QueueNode
{struct QueueNode* next;QDataType val;                                                                          
}QNode;
//队列的结构
typedef struct Queue
{QNode* phead;QNode* ptail;int size;
}Queue;
//初始化
void QueueInit(Queue* pq);
//销毁队列
void QueueDeatroy(Queue* pq);
//队尾入列
void QueuePush(Queue* pq, QDataType x);
//队头出列
void QueuePop(Queue* pq);
//获取队列头部元素
QDataType QueueFront(Queue* pq);
//获取队列尾部元素
QDataType QueueBack(Queue* pq);
//检测队列是否为空,如果为空返回非零结果,如果非空返回0 
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 QueueDeatroy(Queue* pq)
{assert(pq);QNode* cur = pq->phead;while (cur){QNode* 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");exit(-1);}newnode->next = NULL;newnode->val = x;if (pq->ptail == NULL){pq->phead = pq->ptail = newnode;}else{//现在newnode是新的尾结点pq->ptail->next = newnode;pq->ptail = newnode;}pq->size++;
}
//队头出列
void QueuePop(Queue* pq)
{assert(pq);assert(pq->phead); //保存当前节点QNode* tmp = pq->phead;//phead往下走pq->phead = pq->phead->next;free(tmp);tmp = NULL;if (pq->phead = NULL){pq->ptail = NULL;}pq->size--;
}
//获取队列头部元素
QDataType QueueFront(Queue* pq)
{assert(pq);assert(pq->phead);return pq->phead->val;
}
//获取队列尾部元素
QDataType QueueBack(Queue* pq)
{assert(pq);assert(pq->phead);return pq->ptail;
}
//检测队列是否为空,如果为空返回非零结果,如果非空返回0 
bool QueueEmpty(Queue* pq)
{assert(pq);return pq->phead == NULL;
}
//获取队列中有效元素个数
int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}

Test.c

#include"Queue.h"int main()
{Queue q;QueueInit(&q);QueuePush(&q, 1);QueuePush(&q, 2);QueuePush(&q, 3);while (!QueueEmpty(&q)){printf("%d ", QueueFront(&q));QueuePop(&q);}QueueDeatroy(&q);return 0;}

在这里插入图片描述

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

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

相关文章

iOS ApplePay 支付汇总一二

一、前端发起支付的参考例子&#xff1a; import UIKit import MMKV import StoreKit import Alamofire import SVProgressHUD/// ApplePay 工具类 class ApplePayUtils : NSObject {static let shareInstance ApplePayUtils.init()/// 丢单存储集Key,验证成功从集合中移除le…

建行账单导出的手工操作

文章目录 建行账单导出的手工操作概述笔记END 建行账单导出的手工操作 概述 自己的电商账单分析程序初步搞定. 支付宝/微信/京东导出的账单都是csv格式. 我开始做的时候, 建行的账单选的是xls(旧版excel)格式. 没注意看. 程序中用的excel库操作, 只能处理.xlsx格式(新版exce…

10--面向对象OOP--05

1、代码块 如果成员变量想要初始化的值不是一个硬编码的常量值&#xff0c;而是需要通过复杂的计算或读取文件、或读取运行环境信息等方式才能获取的一些值&#xff0c;该怎么办呢&#xff1f;此时&#xff0c;可以考虑代码块&#xff08;或初始化块&#xff09;。 代码块(或…

使用xshell连接虚拟机(服务器)

作者&#xff1a;余小小 Xshell Xshell [1] 是一个强大的安全终端模拟软件&#xff0c;它支持SSH1, SSH2, 以及Microsoft Windows 平台的TELNET 协议。Xshell 通过互联网到远程主机的安全连接以及它创新性的设计和特色帮助用户在复杂的网络环境中享受他们的工作。 Xshell可以…

neuq-acm预备队训练week 8 P8794 [蓝桥杯 2022 国 A] 环境治理

题目描述 输入格式 输出格式 输出一行包含一个整数表示答案。 输入输出样例 解题思路 最短路二分 AC代码 #include<bits/stdc.h> using namespace std; long long temp,n, Q; long long f[105][105],min_f[105][105],cut[105],dis[105][105];//cut为减少多少&#x…

mapstruct个人学习记录

mapstruct核心技术学习 简介入门案例maven依赖 IDEA插件单一对象转换测试结果 mapping属性Spring注入的方式测试 集合的映射set类型的映射测试map类型的映射测试 MapMappingkeyDateFormatvalueDateFormat 枚举映射基础入门 简介 在工作中&#xff0c;我们经常要进行各种对象之…

Sql Server关于表的建立、修改、删除

表的创建&#xff1a; &#xff08;1&#xff09;在“对象资源管理器”面板中展开“数据库”节点&#xff0c;可以看到自己创建的数据库&#xff0c;比如Product。展开Product节点&#xff0c;右击“表”节点&#xff0c;在弹出的快捷菜单中选择“新建表”项&#xff0c;进入“…

JMS(Java Message Service)使用指南

介绍 JMS即Java消息服务&#xff08;Java Message Service&#xff09;应用程序接口&#xff0c;是一个Java平台中关于面向消息中间件&#xff08;MOM&#xff09;的API&#xff0c;用于在两个应用程序之间&#xff0c;或分布式系统中发送消息&#xff0c;进行异步通信。它是一…

SwinIR: Image Restoration Using Swin Transformer

SwinIR 简介 论文地址&#xff1a;SwinIR: Image Restoration Using Swin Transformer 代码&#xff1a;SwinIR ​ 本文提出了一个基于swin transformer的图像超分模型swinIR。其中SwinIR分为三部分&#xff1a;浅层特征提取、深层特征提取和高质量图像重建模块。 现阶段问…

【C++11(三)】智能指针详解--RAII思想循环引用问题

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:C从入门到精通⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习C   &#x1f51d;&#x1f51d; C11 1. 前言2. 为什么要有智能指针?3. RAII思想…

使用Python提取PDF文件中指定页面的内容

在日常工作和学习中&#xff0c;我们经常需要从PDF文件中提取特定页面的内容。在本篇文章中&#xff0c;我们将介绍如何使用Python编程语言和两个强大的库——pymupdf和wxPython&#xff0c;来实现这个任务。 1. 准备工作 首先&#xff0c;确保你已经安装了以下两个Python库&…

保姆级 | XSS Platform环境搭建

0x00 前言 XSS Platform 平台主要是用作验证跨站脚本攻击。该平台可以部署在本地或服务器环境中。我们可以使用 XSS Platfrom 平台搭建、学习或验证各种类型的 XSS 漏洞。 0x01 环境说明 HECS(云耀云服务器)xss platformUbuntu 22.04Nginx 1.24.0MySQL 5.6.51Pure-Ftpd 1.0.49…