数据结构——栈和队列(C语言实现)

写在前面:

        栈和队列是两种重要的线性结构。其也属于线性表,只是操作受限,本节主要讨论的是栈和队列的定义、表示方法以及C语言实现。

一、栈和队列的定义与特点

栈:是限定仅在表尾进行插入和删除的线性表。对栈来说,表尾有着特殊的含义,称为栈顶,表头称为栈底,不含元素的空表称为空栈;

栈的特点就是:按后进先出的原则进行的,栈又称为后进先出的线性表;

      与栈相反的是队列,队列是一种先进先出的特点。它只允许在标的一段进行插入,在另一端进行删除。允许插入的一段称为队尾,允许删除的一段称为队头。

二、栈

2.1顺序栈

        顺序栈是指利用顺序存储结构实现的栈,即利用一组地址连续的存储单元依次存放在自栈底到栈顶的数据元素。

        设指针top指向栈顶元素在顺序表中的位置,base指针指向栈底元素在顺序栈中的位置。

2.1.1初始化

typedef struct Node
{int *base;int *top;int stacksize;
}Node;
//初始化栈
void  InitStack(Node *S)
{S->base = (int *)malloc(sizeof(int)*MAXSIZE);S->top = S->base ;
}

初始化,创建一个结构体类型,其中变量为栈顶指针、栈底指针,以及栈的最大空间;

使栈顶和栈底都指向空间的基地址;

2.1.2入栈

int PushStack(Node* S,int data)
{if (S->top - S->base == MAXSIZE){return -1;}	else{*(S->top) = data;(S->top)++;}
}

判断栈是否满,不满将新元素压入栈顶,栈顶指针+1; 

2.1.3出栈

int PopStack(Node * S)
{if (S->top == S->base)return -1;else{(S->top)--;int i = *(S->top);return i;}
}

判断栈顶是否为空,若不为空,栈顶指针减1,栈顶元素出栈; 

2.1.4 打印

void PrintStack(Node S)
{int len = (S.top-S.base);for (int i = 0; i < len; i++){(S.top)--;printf("%d->", *(S.top));}printf("NULL\n");
}

先计算栈的空间长度,再依次从栈顶打印除栈的元素; 

2.1.5案例 

#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE  5typedef struct Node
{int *base;int *top;int stacksize;
}Node;
//初始化栈
void  InitStack(Node *S)
{S->base = (int *)malloc(sizeof(int)*MAXSIZE);S->top = S->base ;
}
//入栈//判断栈是否满了
int PushStack(Node* S,int data)
{if (S->top - S->base == MAXSIZE){return -1;}else{*(S->top) = data;(S->top)++;}
}
//出栈//判断栈是否为空
int PopStack(Node * S)
{if (S->top == S->base)return -1;else{(S->top)--;int i = *(S->top);return i;}
}
//打印
void PrintStack(Node S)
{int len = (S.top-S.base);for (int i = 0; i < len; i++){(S.top)--;printf("%d->", *(S.top));}printf("NULL\n");
}int  main()
{Node S;InitStack(&S);PushStack(&S, 1);PrintStack(S);PushStack(&S, 2);PrintStack(S);PushStack(&S, 3);PrintStack(S);PushStack(&S, 4);PrintStack(S);PushStack(&S, 5);PrintStack(S);int i = PopStack(&S);printf("delete:%d\n",i);i = PopStack(&S);printf("delete:%d\n", i);PrintStack(S);return 0;
}

运行结果: 

2.2链栈 

链栈是指采用链式存储结构实现的栈,通常采用单链表实现;

2.2.1初始化 

//新建结点
typedef struct Node
{int data;struct Node* next;
}Node;
//初始化
Node * StackIint()
{Node * head = (Node *)malloc(sizeof(Node));head->data=0;head->next = NULL;return head;
}

 初始化,首先创建一个结构体代表一个节点,然后创建一个空栈,即只有头结点的链表。

 2.2.2入栈

void push(Node * node,int data)
{Node * S = (Node *)malloc(sizeof(Node));S->data = data;S->next = node->next;node->next = S;node->data++;	
}

和链表的头插法一样,为入栈元素动态分配一个结点空间; 

2.2.3出栈

//判断是否为栈空
int isEmpty(Node * node)
{if (node->data == 0 || node->next == NULL)return 1;elsereturn 0;
}
//出栈
int pop(Node * node)
{if (isEmpty(node))return -1;else{Node *S = node->next;int i = S->data;node->next = S->next;free(S);node->data--;return i;}
}

        出栈,出栈前需要判断其栈是否为空,如果为空就无法进行出栈。出栈时需要把栈顶元素进行输出,并且释放栈顶空间。

2.2.4取栈顶元素

//判断是否为栈空
int isEmpty(Node * node)
{if (node->data == 0 || node->next == NULL)return 1;elsereturn 0;
}
//获取栈元素
int getvalue(Node * node)
{if (isEmpty(node)){return -1;}else{return(node->next->data);}
}

与出栈一样,需要判断栈是否为空,如果不为空,则输出栈顶元素;

2.2.5案例

#include <stdio.h>
#include <stdlib.h>typedef struct Node
{int data;struct Node* next;
}Node;//初始化
Node * StackIint()
{Node * head = (Node *)malloc(sizeof(Node));head->data=0;head->next = NULL;return head;
}//判断是否为栈空
int isEmpty(Node * node)
{if (node->data == 0 || node->next == NULL)return 1;elsereturn 0;
}
//获取栈元素int getvalue(Node * node)
{if (isEmpty(node)){return -1;}else{return(node->next->data);}
}//出栈
int pop(Node * node)
{if (isEmpty(node))return -1;else{Node *S = node->next;int i = S->data;node->next = S->next;free(S);node->data--;return i;}
}//入栈
void push(Node * node,int data)
{Node * S = (Node *)malloc(sizeof(Node));S->data = data;S->next = node->next;node->next = S;node->data++;	
}
void printStack(Node * node)
{Node * S = node->next;while (S){printf("%d->", S->data);S = S->next;}printf("NULL\n");
}
int main()
{Node * S = StackIint();push(S, 1);push(S, 2);push(S, 3);push(S, 4);printStack(S);int i=pop(S);printf(" top data:%d\n", i);printStack(S);return 0;
}

运行结果:

三、队列

        有与栈结构相同,队列也有两种存储表示,顺序表示与链式表示;

3.1顺序队列(循环队列)

        在顺序队列中。除了设置一组地址连续的存储空间依次存放元素外,另外需要两个正向变量,分别指示队列头元素和队列尾元素的位置。

        在初始化空队列时,令front=rear=0;每当插入新的队列尾元素时,尾指针rear增1;每当删除队列头元素时,头指针front增1;在非空队列中,头指针始终指向队列头元素,而尾指针始终指向尾元素的下一个位置。但是这种操作会使得队列的指针最终越界处理,围殴了限制这种越界处理,我们提出循环队列的形式;

        循环队列的头尾以及队列元素之间的关系不变,只是在循环队列中,头指针、尾指针,依次环状增1的操作可以取模进行运算。通过取模运算,头指针和尾指针可以在顺序变种以头尾衔接的方式“循环”移动;

        对于循环队列 种,不能以头指针、尾指针的值是否相等来判断,队列的空间是“满”还是“空”,采取的方式是:

        少用一个元素空间,即队列空间为m时,有m-1个元素就认为时队满,这样设置的意义在于:当头尾指针相等时,队列为空,当尾指针加1等于头指针时,则认为队列满;

队空条件:front==rear;

队满条件:(rear+1)%MAXQSIZE==front;

3.1.1初始化

//新建一个结构体
typedef struct Queue
{int front;int rear;int data[MAXSIZE];
}Queue;
//1、初始化队列
Queue * initQueue()
{Queue * Q = (Queue *)malloc(sizeof(Queue));Q->front = Q->rear = 0;return Q;
}

创建一个结构体类型,结构体类型中有三个元素:数据数组、头指针地址、尾指针地址。然后初始化创建一个空队列;

3.1.2入队

//判断是否队满
int isFULL(Queue * Q)
{if ((Q->rear +1) % MAXSIZE == Q->front){return 1;}else{return 0;}
}//入队
int  enQueue(Queue * Q, int data)
{if (isFULL(Q)){return -1;}else{Q->data[Q->rear] = data;Q->rear = (Q->rear + 1) % MAXSIZE;return 1;}
}

首先判断队列是否满,如果没满进行入队,并且操作的都是尾指针; 

3.1.3出队

int isNULL(Queue * Q)
{if (Q->rear == Q->front){return 1;}else{return 0;}
}int deQueue(Queue * Q)
{if (isNULL(Q)){return -1;}else{int e = Q->data[Q->front];Q->front = (Q->front + 1) % MAXSIZE;return e;}
}

首先判断是否队列为空,如果没有为空,就从队头出队,操作的都是队头指针;

3.1.4打印队列

void printfQueue(Queue * Q)
{//要知道队列当前有多少个元素int len = (MAXSIZE + Q->rear - Q->front) % MAXSIZE;int index = Q->front;for (int i =0; i <len; i++){printf("%d->", Q->data[index]);index = (index + 1) % MAXSIZE;}printf("NULL\n");
}

进行队列元素的遍历,然后依次进行打印; 

3.1.5案例 

#include <stdio.h>
#include <stdlib.h>#define MAXSIZE 6
//新建一个结构体
typedef struct Queue
{int front;int rear;int data[MAXSIZE];
}Queue;
//1、初始化队列
Queue * initQueue()
{Queue * Q = (Queue *)malloc(sizeof(Queue));Q->front = Q->rear = 0;return Q;
}int isFULL(Queue * Q)
{if ((Q->rear +1) % MAXSIZE == Q->front){return 1;}else{return 0;}
}
//2、入队
int  enQueue(Queue * Q, int data)
{if (isFULL(Q)){return -1;}else{Q->data[Q->rear] = data;Q->rear = (Q->rear + 1) % MAXSIZE;return 1;}
}
//3、出队
int isNULL(Queue * Q)
{if (Q->rear == Q->front){return 1;}else{return 0;}
}int deQueue(Queue * Q)
{if (isNULL(Q)){return -1;}else{int e = Q->data[Q->front];Q->front = (Q->front + 1) % MAXSIZE;return e;}
}
//4、打印队列
void printfQueue(Queue * Q)
{//要知道队列当前有多少个元素int len = (MAXSIZE + Q->rear - Q->front) % MAXSIZE;int index = Q->front;for (int i =0; i <len; i++){printf("%d->", Q->data[index]);index = (index + 1) % MAXSIZE;}printf("NULL\n");
}
int main()
{Queue * Q = initQueue();enQueue(Q, 1);printfQueue(Q);enQueue(Q, 2);printfQueue(Q);enQueue(Q, 3);printfQueue(Q);enQueue(Q, 4);printfQueue(Q);int i = deQueue(Q);printf(" delete	Queue:%d\n",i);printfQueue(Q);i = deQueue(Q);printf(" delete	Queue:%d\n",i);printfQueue(Q);return 0;
}

 运行结果:

3.2链队

3.2.1初始化

//定义结构体类型
typedef struct Node
{int data;struct Node* next;
}Node;
//初始化
Node * QueueInit()
{Node * head = (Node *)malloc(sizeof(Node));head->data = 0;head->next = NULL;return head;
}

与栈操作相同,先创建一个结构类型,再创建一个空的队列,只含有一个头结点的队列。 

3.2.2入队

//入队
void Queueen(Node *Q,int data)
{Node * node = (Node *)malloc(sizeof(Node));node->data = data;Node * q = Q;while (q->next != NULL){q = q->next;}node->next = q->next;q->next = node;Q->data++;
}

入队操作和链表的尾插法是一样的,需要再队尾进行插入; 

3.2.3出队

//判断
int isEmpty(Node * Q)
{if (Q->data)return 1;elsereturn 0;
}
//出队
int dequeue(Node * Q)
{if (isEmpty(Q)){Node * node = Q->next;int i = node->data;Q->next = node->next;free(node);Q->data--;return i;}else{return -1;}
}

        出队,首先要判断队列是否为空,而且还有遵循先进先出的原则。 

3.2.4打印队列

//打印队列
void printQueue(Node * node)
{Node* p = node->next;while (p){printf("%d->", p->data);p = p->next;}printf("NULL\n");
}

遍历队列,然后打印,同链表操作基本一致; 

3.2.5案例

#include <stdio.h>
#include <stdlib.h>//定义结构体类型
typedef struct Node
{int data;struct Node* next;
}Node;
//初始化
Node * QueueInit()
{Node * head = (Node *)malloc(sizeof(Node));head->data = 0;head->next = NULL;return head;
}
//入队
void Queueen(Node *Q,int data)
{Node * node = (Node *)malloc(sizeof(Node));node->data = data;Node * q = Q;while (q->next != NULL){q = q->next;}node->next = q->next;q->next = node;Q->data++;
}
//判断
int isEmpty(Node * Q)
{if (Q->data)return 1;elsereturn 0;
}
//出队
int dequeue(Node * Q)
{if (isEmpty(Q)){Node * node = Q->next;int i = node->data;Q->next = node->next;free(node);Q->data--;return i;}else{return -1;}
}//打印队列
void printQueue(Node * node)
{Node* p = node->next;while (p){printf("%d->", p->data);p = p->next;}printf("NULL\n");
}int main()
{Node * Q = QueueInit();Queueen(Q, 1);printQueue(Q);Queueen(Q, 2);printQueue(Q);Queueen(Q, 3);printQueue(Q);Queueen(Q, 4);printQueue(Q);Queueen(Q, 5);printQueue(Q);int i = dequeue(Q);printf("delete queue:%d\n", i);printQueue(Q);return 0;
}

运行结果: 

四、总结

        本次主要介绍了两个特殊的线性表:栈和队列;

1、栈是限定仅在表尾进行插入或者删除的线性表,又称为后进先出的线性表。栈有两种存储结构表示方式,顺序表示(顺序栈)和链式表示(链栈);栈的主要操作是入栈和出栈,注意入栈和出栈时需要分别判断栈满和栈空;

2、队列是一种先入先出的线性表,它只允许在表的一端进行插入,在另一端删除元素。队列也有两种存储表示,顺序表示(循环队列)和链式表示(链队)。队列主要的操作是进队和出队,对于顺序的循环队列的进队和出队需要注意判断队满或队空。凡是涉及到队头和队尾指针的都要对其进行求模;

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

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

相关文章

【经验分享】关于静态分析工具排查 Bug 的方法

文章目录 编译器的静态分析cppcheck安装 cppcheck运行 cppcheck 程序员的日常工作&#xff0c;不是摸鱼扯皮&#xff0c;就是在写 Bug。虽然这是一个梗&#xff0c;但也可以看出&#xff0c;程序员的日常一定绕不开 Bug。而花更少的时间修复软件中的 Bug&#xff0c;且不引入新…

lightgbm

lightGBM 1.sklearn 使用代码 【机器学习基础】XGBoost、LightGBM与CatBoost算法对比与调参 首先&#xff0c;XGBoost、LightGBM和CatBoost都是目前经典的SOTA&#xff08;state of the art&#xff09;Boosting算法&#xff0c;都可以归类到梯度提升决策树算法系列。三个模…

5. JavaSE ——【适合小白的数组练习题】

&#x1f4d6;开场白 亲爱的读者&#xff0c;大家好&#xff01;我是一名正在学习编程的高校生。在这个博客里&#xff0c;我将和大家一起探讨编程技巧、分享实用工具&#xff0c;并交流学习心得。希望通过我的博客&#xff0c;你能学到有用的知识&#xff0c;提高自己的技能&a…

【区块链 + 智慧政务】澳门:智慧城市建设之证书电子化项目 | FISCO BCOS应用案例

2019 年 2 月 27 日&#xff0c;澳门政府设立的澳门科学技术发展基金与微众银行达成合作&#xff0c;通过区块链、人工智能、大数据、 云计算等创新技术&#xff0c;共同推进澳门特区的智慧城市建设与未来型城市发展&#xff0c;提升粤港澳大湾区的科创能力。在澳 门智慧城市建…

【数学建模】高温作业专用服装设计(2018A)隐式差分推导

为方便计算&#xff0c;对区域进行离散化处理&#xff0c;采用隐式差分格式进行离散计算。隐式差分格式如图&#xff1a; 每层材料内部 对第 j j j层材料: 其中&#xff0c; λ j \lambda_j λj​表示第 j j j层的热扩散率&#xff0c; c j c_j cj​表示第 j j j层的比热容…

linux需要熟悉的命令理解记忆

(1)光标插入 (1)一般模式下: i 插入到光标前方 记忆方法:在一般模式下, 光标选中字符, 我们按下 i, 就会插入光标的前方, insert, 表示插队 (2)一般模式下: a 插入到光标后方 记忆方法: 在一般模式下, 光标选中字符,a表示append, 添加或者附加的意思 (3) 如果要在行首或者行…

css实现每个小盒子占32%,超出就换行

代码 <div class"visitors"><visitor class"item" v-for"(user,index) in userArr" :key"user.id" :user"user" :index"index"></visitor></div><style lang"scss" scoped&…

java乱码问题

文章目录 1.eclipse所有修改编码的地方2.io读取文件乱码问题1.读写统一2.转换字符编码&#xff1a; 3.http请求返回乱码 1.eclipse所有修改编码的地方 2.io读取文件乱码问题 1.读写统一 如果文件是以UTF-8编码保存的&#xff0c;那么在读取文件时也应使用UTF-8编码。 2.转换…

Apple Vision Pro 和其商业未来

机器人、人工智能相关领域 news/events &#xff08;专栏目录&#xff09; 本文目录 一、Vision Pro 生态系统二、Apple Vision Pro 的营销用例 随着苹果公司备受期待的进军可穿戴计算领域&#xff0c;新款 Apple Vision Pro 承载着巨大的期望。 苹果公司推出的 Vision Pro 售…

百分点科技签约潍坊市数据产业发展战略合作

近日&#xff0c;潍坊市数据产业发展战略合作签约仪式举行&#xff0c;潍坊市人民政府副市长张震生&#xff0c;潍坊市财政局党组书记、局长王金祥&#xff0c;潍坊市大数据局党组书记陈强出席大会并致辞。百分点科技受邀进行战略合作签约&#xff0c;共同见证潍坊市数据要素市…

生成式人工智能(AI)的未来

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

深度学习模型快速开发平台推荐

前言 本文面向深度学习初学者或者工程师&#xff0c;推荐几个常用的深度学习模型快速开发平台。可以帮助初学者快速跑通模型&#xff0c;帮助工程师快速对模型进行部署和应用。 huggingface 简介 不多介绍&#xff0c;全球最大的模型托管平台&#xff0c;该平台最大的特点是…

全网超详细Redis主从部署(附出现bug原因)

主从部署 整体架构图 需要再建两个CentOs7,过程重复单机部署 http://t.csdnimg.cn/zkpBE http://t.csdnimg.cn/lUU5gLinux环境下配置redis 查看自己ip地址命令 ifconfig 192.168.187.137 进入redis所在目录 cd /opt/software/redis cd redis-stable 进入配置文件 vim redi…

JavaWeb入门程序解析(Spring官方骨架、配置起步依赖、SpringBoot父工程、内嵌Tomcat)

3.3 入门程序解析 关于web开发的基础知识&#xff0c;我们可以告一段落了。下面呢&#xff0c;我们在基于今天的核心技术点SpringBoot快速入门案例进行分析。 3.3.1 Spring官方骨架 之前我们创建的SpringBoot入门案例&#xff0c;是基于Spring官方提供的骨架实现的。 Sprin…

勘测院如何实现可控便捷的图纸安全外发?

勘测院&#xff0c;也称为勘测设计研究院或勘测设计院&#xff0c;是进行与地质、地形和地貌有关的勘察测量的单位&#xff0c;为各类工程项目提供准确的地质数据和设计依据。 勘测院会产生各类包括图纸在内的文件&#xff0c;如&#xff1a; 1、项目相关文件&#xff1a;项目…

c++模板初阶----函数模板与类模板

目录 泛型编程 函数模板 函数模板的概念 函数模板的格式 函数模板的原理 函数模板的实例化 函数模板的匹配原则 类模板 类模板的定义格式 类模板的实例化 c的模板大致可以分为&#xff1a; 函数模板类模板 首先在我们引入模板之前&#xff0c;先进行介绍泛型编程 泛…

期权黑天鹅怎么应对?近期很有可能发生的事情!

今天带你了解期权黑天鹅怎么应对&#xff1f;在当今世界&#xff0c;投资者们不断地寻找着各种策略来应对市场的波动和不确定性。其中&#xff0c;黑天鹅策略在近年来逐渐受到了广泛的关注&#xff0c;这种策略主要是利用极端事件&#xff0c;例如突发事件或自然灾害等难以预测…

【React笔记初学总结一】React新手的学习流程笔记总结,掰开了揉碎了,下载安装基础结构学习

REACT学习记录 一、React是什么&#xff1a;二、尝试安装下载&#xff1a;三、理解都有什么四、基础网页学习&#xff1a;1.几个比较重要的资源包例子2.第一个react示例&#xff1a;&#xff08;掰开了揉碎了&#xff0c;咱们先看懂它最简单的结构&#xff09;3.第二个react示例…

C++链接FTP服务器并下载数据(在qt中编写)

.pro文件 #------------------------------------------------- # # Project created by QtCreator 2024-07-16T13:19:03 # #-------------------------------------------------QT core gui networkgreaterThan(QT_MAJOR_VERSION, 4): QT widgetsTARGET untitled TE…

Qt实现IP地址输入框-自定义控件

在 许多应用程序中&#xff0c;我们经常需要使用IP地址。为了方便用户输入和处理&#xff0c;一个好的解决方案是使用自定义控件。本示例代码使用Qt编写一个名为“IPAddress”的自定义控件来实现IP地址的输入功能。通过使用此控件&#xff0c;用户可以方便地输入和处理IP地址。…