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

news2024/9/23 15:29:50

写在前面:

        栈和队列是两种重要的线性结构。其也属于线性表,只是操作受限,本节主要讨论的是栈和队列的定义、表示方法以及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  5

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 ;
}
//入栈
	//判断栈是否满了
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;
	else
		return 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;
	else
		return 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;
	else
		return 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;
	else
		return 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;
	else
		return 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.coloradmin.cn/o/1932455.html

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

相关文章

【Elasticsearch7.11】reindex问题

参考博文链接 问题&#xff1a;reindex 时出现如下问题 原因&#xff1a;数据量大&#xff0c;kibana的问题 解决方法&#xff1a; 将DSL命令转化成CURL命令在服务上执行 CURL命令 自动转化 curl -XPOST "http://IP:PORT/_reindex" -H Content-Type: application…

防洪墙的安全内容检测+http请求头

1、华为的IAE引擎&#xff1a;内部工作过程 IAE引擎主要是针对2-7层进行一个数据内容的检测 --1、深度检测技术 (DPI和DPF是所有内容检测都必须要用到的技术) ---1、DPI--深度包检测&#xff0c;针对完整的数据包&#xff0c;进行内容的识别和检测 1、基于特征子的检…

Spark算子--take(访问量前十网站)

1.题目需求 利用数据集SogouQ2012.mini.tar.gz 将数据按照访问次数进行排序&#xff0c;求访问量前10的网址&#xff0c;每一行数据代表一个url被访问1次 2.代码 from pyspark import SparkContext, SparkConfdef main():conf SparkConf().setMaster("local[*]").s…

【操作系统】文件管理——文件存储空间管理(个人笔记)

学习日期&#xff1a;2024.7.17 内容摘要&#xff1a;文件存储空间管理、文件的基本操作 在上一章中&#xff0c;我们学习了文件物理结构的管理&#xff0c;重点学习了操作系统是如何实现逻辑结构到物理结构的映射&#xff0c;这显然是针对已经存储了文件的磁盘块的&#xff0…

连锁零售门店分析思路-人货场 数据分析

连锁零售门店分析思路 以下是一个连锁零售门店的分析思路&#xff1a; 一、市场与竞争分析 二、门店运营分析&#xff08;销售分析&#xff09; 三、销售与财务分析 四、客户分析 五、数字化与营销分析 最近帮一个大学生培训&#xff0c;就门店销售分析 &#xff0c;说到门店…

尚品汇-(二十)

目录&#xff1a; 一&#xff1a;商品详情页面优化 &#xff08;1&#xff09;思路 &#xff08;2&#xff09;整合redis到工程 &#xff08;3&#xff09;使用redis进行业务开发相关规则 &#xff08;4&#xff09;缓存常见问题 二&#xff1a;分布式锁 本地锁的局限性…

【BUG】已解决:java.lang.reflect.InvocationTargetException

已解决&#xff1a;java.lang.reflect.InvocationTargetException 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;武汉城市开发…

【STL详解 —— map和set的使用】

STL详解 —— map和set的使用 关联式容器键值对setset的介绍set的使用set的模板参数列表set的构造set的迭代器set的容量set的修改操作 mapmap的介绍map的使用map的模板参数列表map的构造map的迭代器map的容量与元素访问map中元素的修改 multisetmultimap 关联式容器 在初阶阶段…

Mindspore框架CycleGAN模型实现图像风格迁移|(一)Cycle神经网络模型构建

Mindspore框架&#xff1a;CycleGAN模型实现图像风格迁移算法 Mindspore框架CycleGAN模型实现图像风格迁移|&#xff08;一&#xff09;CycleGAN神经网络模型构建Mindspore框架CycleGAN模型实现图像风格迁移|&#xff08;二&#xff09;实例数据集&#xff08;苹果2橘子&#…

彻底搞定C指针系列

1.指针是什么&#xff1f; 运行一下代码 #include <stdio.h> int main() { int i 39; printf("%d\n", i); printf("%d\n",&i); return 0; } 运行结果&#xff1a; 39 618561996 运行测试代码&#xff1a; #include <stdio.…

计组 外围设备

外围设备 peripheral device 概述 基本组成部分&#xff1a;存储介质、驱动装置、控制电路 分类&#xff1a;输入设备、输出设备、外存设备、数据通信设备和过程控制设备 磁盘存储设备 磁化元/存储元&#xff1a;记录一个二进制信息位的最小单位 两个稳定的剩磁状态 读写磁…

2.javaWeb_请求和响应的处理(Request,Response)

2.请求和响应的处理 文章目录 2.请求和响应的处理一、动态资源和静态资源javax.servlet(包) 二、Servlet体系1.简介2.HttpServlet3.Servlet生命周期 三、Request对象1.ServletRequest1)ServletRequest主要功能有&#xff1a;2)ServletRequest类的常用方法: 2.HttpServletReques…

InterSystems IRIS Python 使用 DB-API连接 ,比odbc简单

1、下载安装驱动 同步的gitee下载地址&#xff1a;&#xff1a;于光/iris-driver-distribution - Gitee.com pip install intersystems_irispython-version-py3-none-any.whl 2、python代码测试 import iris as dbapi conn dbapi.connect(hostname127.0.0.1, port1972, names…

只讲干货!!自己喜欢的只能靠自己努力才能拿到!!今天拿下:IO流技术介绍

什么是IO 输入(Input) 指的是&#xff1a;可以让程序从外部系统获得数据&#xff08;核心含义是 “读 ” &#xff0c;读取外部数据&#xff09;。 输出(Output) 指的是&#xff1a;程序输出数据给外部系统从而可以操作外部 系统&#xff08;核心含义是“ 写 ” &#xff0c;将…

基于MindSpore实现BERT对话情绪识别

讲解视频&#xff1a; 基于MindSpore实现BERT对话情绪识别

防御笔记第七天(时需更新)

1.防火墙的可靠性&#xff1a; 因为防火墙不仅需要同步配置信息&#xff0c;还需要同步状态信息&#xff08;会话表等&#xff09;&#xff0c;所以防火墙不能像路由器那样单纯靠动态协议来进行切换&#xff0c;还需要用到双击热备技术。 双机---目前双机技术仅仅支持两台防火…

AI 大事件:超级明星 Andrej Karpathy 创立AI教育公司 Eureka Labs

&#x1f9e0; AI 大事件&#xff1a;超级明星 Andrej Karpathy 创立AI教育公司 Eureka Labs 摘要 Andrej Karpathy 作为前 OpenAI 联合创始人、Tesla AI 团队负责人&#xff0c;他的专业性和实力备受瞩目。Karpathy 对 AI 的普及和教育充满热情&#xff0c;从 YouTube 教程到…

一招轻松解决猫毛 最值得买的浮毛空气净化器排名

作为一名6年资深铲屎官&#xff0c;我常常被朋友问到关于宠物空气净化器的各种问题。有的人认为这是个神器&#xff0c;而有的人则认为这完全是花钱买智商税。其实我刚开始对购买宠物空气净化器也持怀疑态度&#xff0c;心想这么多钱花下去真的有效吗&#xff1f;但使用后&…

【Linux】将IDEA项目部署到云服务器上,让其成为后台进程(保姆级教学,满满的干货~~)

目录 部署项目到云服务器什么是部署一、 创建MySQL数据库二、 修改idea配置项三、 数据打包四、 部署云服务器五、开放端口号六 、 验证程序 部署项目到云服务器 什么是部署 ⼯作中涉及到的"环境" 开发环境:开发⼈员写代码⽤的机器.测试环境:测试⼈员测试程序使⽤…

Springboot整合MyBatis实现数据库查询(二)

目录 第一章、准备1.1&#xff09;准备数据库表1.2&#xff09;创建springboot项目&#xff0c;添加依赖1.3&#xff09;使用mybatis逆向工程 第二章、代码开发2.1&#xff09;建包并编写代码2.2&#xff09;application配置文件2.3&#xff09;设置编译位置 第三章、测试访问3…