首页 > 其他分享 >数据结构——栈和队列的模拟实现

数据结构——栈和队列的模拟实现

时间:2024-11-15 20:44:53浏览次数:3  
标签:ps pq 队列 void ST Queue 数据结构 模拟

在这里插入图片描述

文章目录

前言

继上篇博客,已经把链表的有关习题完成,链表也已经收尾啦。
今天来学习新的数据结构——栈和队列,fellow me

一、栈

1.1 概念与结构

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

在这里插入图片描述

我们要用什么来实现栈这个数据结构呢?
前面我们学习了顺序表和链表,感觉两者都行,仔细想想,还是用顺序表来实现,也就是数组,因为数组在尾上的插入更优一些,更加贴合后进后出的特殊性


1.2 栈的实现

关于栈的实现,主要是入栈和出栈的操作,以及取栈顶元素。
既然用顺序表来实现,想必大家已经熟练操作了,跟着我来实现这些函数吧

typedef int STDataType;
//定义栈的数据结构
typedef struct Stack
{
	STDataType* arr;
	int top;          //指向栈顶位置
	int capacity;     //容量
}ST;

void STInit(ST* ps); 	//   栈的初始化

void STDestroy(ST* ps);  // 栈的销毁

void STPush(ST* ps, STDataType x);	//入栈--栈顶

void STPop(ST* ps);	//出栈--栈顶

STDataType STTop(ST* ps);	//取栈顶元素

bool STEmpty(ST* ps);	//栈是否为空

int STSize(ST* ps);		//获取栈中有效元素个数

void STPrint(ST* ps);   //  打印   栈

老样子,实现一个东西,必然是要初始化,想必大家已经对这代码再也熟悉不过了。

void STInit(ST* ps)   //  初始化
{
	assert(ps);
	ps->arr = NULL; 
	ps->capacity = ps->top = 0;  
}

入栈和出栈也大相径庭,这里就没有单独写扩容函数了,因为栈的实现只有入栈需要插入数据

void STPush(ST* ps, STDataType x)   //  入栈  以及容量的扩展的获取
{
	assert(ps);
	if (ps->top == ps->capacity)   //  容量不够,扩容
	{
		int newcapacity = ps->top == 0 ? 4 : ps->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(ps->arr, sizeof(STDataType) * newcapacity);
		ps->capacity = newcapacity;
		ps->arr = tmp;      
	}
	ps->arr[ps->top++] = x;   //  直接在数组的末尾赋值就好
}

在出栈之前,肯定是要判断数组是否为空的

bool STEmpty(ST* ps)  //  判断栈是否为空  
{
	assert(ps);
	return ps->top == 0;  
}

你没有看错,出栈就是这么简单

void STPop(ST* ps)   //  出栈   
{
	assert(!STEmpty(ps));
	ps->top--;   //  只接让top--即可  
}

后面就是取栈顶元素和有效元素个数了

STDataType StackTop(ST* ps)  //  取栈顶元素  
{
	assert(!STEmpty(ps));
	return ps->arr[ps->top - 1];  // top代表元素个数  所以要返回下标为top减一的数据
}	
int STSize(ST* ps)    //   获取栈的元素个数   
{
	assert(ps);
	return ps->top;    
}

再写一个打印函数,方便测试的时候观察数据处理过程

void STPrint(ST* ps)   //  打印  测试函数  
{
	assert(ps);
	for (int i = 0; i < ps->top; i++)
	{
		cout << ps->arr[i] << ' ';
	}
	cout << endl;
}

最后就是销毁栈了。

void STDestroy(ST* ps)   ///   有借有还  再借不难 
{
	if (ps->arr != NULL)
		free(ps->arr);
	ps->arr = NULL;
	ps->capacity = ps->top = 0;
}

下面来测试测试我这个栈实现的在怎么样吧,话不多说,上图。

在这里插入图片描述

基本上是没什么问题的,栈的实现就结束啦


二、队列

2.1 概念与结构

概念:只允许在⼀端进⾏插⼊数据操作,在另⼀端进⾏删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)
⼊队列:进⾏插⼊操作的⼀端称为队尾
出队列:进⾏删除操作的⼀端称为队头

在这里插入图片描述

队列这个数据结构,我感觉还是链表结构实现更好一些,因为涉及到出队列,如果使用顺序表的话,出队列需要整体往前移,效率太低。
我们把链表的头设为队列的头,链表的尾设置为队尾。入队列就尾插,出队列就头删
想到这些,那队列的实现岂不是 洒洒水 啦。

2.2 队列的实现

关于队列的实现,无非就是入队和出队列以及获取队头、队尾的元素。
用链表来实现,大家也应该不陌生,毕竟上一篇可是对链表又熟练了一些。
一起来实现队列吧

typedef int QDataType;
typedef struct QueueNode  //  队列内每个元素用链式结构 一个一个结点连接
{
	QDataType data;
	struct QueueNode* next;
}QueueNode;

typedef struct Queue   //  队列  
{
	QueueNode* phead;     // 队头
	QueueNode* ptail;     // 队尾
	int size;  
}Queue;

void QueueInit(Queue* pq);  //  队列初始化  

void QueuePush(Queue* pq, QDataType x);   //  入队 

void QueuePop(Queue* pq);	//  出队    

bool QueueEmpty(Queue* pq);	// 判空函数  

QDataType QueueFront(Queue* pq);  //  获取对头元素  

QDataType QueueBack(Queue* pq);		//  获取队尾元素

int QueueSize(Queue* pq);		//  队内有效元素

void QueueDestory(Queue* pq);    //  销毁队列   

void QueuePrint(Queue* pq);   //  打印  方便测试代码 

先来个初始化

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

简简单单的入队操作

void QueuePush(Queue* pq, QDataType x)   //  入队 
{
	assert(pq);
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));  //  获取新结点
	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;    //  和尾插一样  
	}
	pq->size++;   
}

在出队实现之前,还是老样子,先来一个判空函数

bool QueueEmpty(Queue* pq)	// 判空函数  
{
	assert(pq);
	return pq->size == 0;
}

出队来咯,是不是和头删大相径庭呢

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

入队和出队都觉得轻轻松松,接下来就是取队头队尾元素了,感觉没有难度嘛。

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);
	return pq->size;
}

void QueuePrint(Queue* pq)  //  打印  方便测试代码 
{
	assert(pq);
	QueueNode* pcur = pq->phead;
	while (pcur)
	{
		cout << pcur->data << ' ';
	}
	cout << endl;
}

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

至此,队列的实现就完成啦,接下来就是测试代码咯。

在这里插入图片描述

测试是没什么问题的,队列就完结啦。

总结

感觉学过了顺序表和链表之后,实现栈和队列感觉轻轻松松。
有了前面的基础,感觉今天的内容让我爽歪歪,今天的学习就到这里了
下一篇博客让我们来迎接栈和队列的习题吧,小编持续更新中

在这里插入图片描述

标签:ps,pq,队列,void,ST,Queue,数据结构,模拟
From: https://blog.csdn.net/daily_233/article/details/143805208

相关文章

  • 初级数据结构——栈题库(c++)
    目录前言1.杭电oj——Bitset2.杭电oj——进制转换[3.力扣——LCR123.图书整理I](https://leetcode.cn/problems/cong-wei-dao-tou-da-yin-lian-biao-lcof/description/)[4.力扣——LCR027.回文链表](https://leetcode.cn/problems/aMhZSa/)[5.力扣——1614.括号的......
  • 数据结构程序设计(C语言)校园导游系统
    使用队列以及深度搜索算法,加上dos命令调用图片的校园导游系统#define_CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<stdlib.h>#include<string.h>#include<Windows.h>structgraph{ intnode_num;//顶点数 intedge_num;//边数 charnode_name[20][50......
  • 2024.11.15 NOIP 模拟 - 模拟赛记录
    返乡(home)不给大样例是怕我找规律出答案吗?但是我还是找到规律了。题解说是结论题,但是这个结论即使观察小样例也很好猜(如果我是出题人就把样例打乱一下顺序)。首先考虑只有二维偏序时的最优放置方法:首先第一个数是不能重复的,因为一旦重复,第二个数无论怎么选,都会构成偏序;第二个......
  • Redis深入底层数据结构(万字详细)
    RedisRedis基本数据类型Redis支持5种数据类型:string(字符串)hash(哈希)list(列表)set(集合)zset(sortedset:有序集合)Stringstring:一个key对应一个value。string类型是二进制安全的,可以存储任何类型的数据常用命令:get,set,incr,decr,mget等hashhash:一个string类型的field......
  • NOIP2024模拟赛#21 总结
    坐牢3h+。赛时开T1,发现好唐啊,10min切了。过了全部大样例。开T2,现在是8:10。?现在是8:27,我怎么把T2大样例全过了。是不是太水了。我只是胡了一个贪心啊。开T3,现在是8:30。草,T1加样例了,做法假了。先不管T1了,先去看T3。感觉保证每次操作后都会满足对于\(i......
  • 241115 noip 模拟赛
    省流:\(90+100+25+10\)。T1题意:给定一个长为\(n\)的排列,定义一次操作为选出排列中至多\(4\)个不同的数,将它们任意重排,求最少操作次数让这个排列单调递增。\(n\leq10^6\)。找出排列的所有置换环,设环长为\(t_1,t_2,t_3,\cdots,t_m\),则答案为:\[\sum_{i=1}^m\lflo......
  • NOIP模拟赛 #11
    A一个\(R\timesC\)的矩阵\(A\),有\(N\)个位置已知,第\(i\)个为\(A_{r_i,c_i}=a_i\)。求是否存在一种填写剩下数字的方案,满足每个数字都非负且对于任意\(i,j(1\lei\leR-1,1\lej\leC-1)\)都有\(A_{i,j}+A_{i+1,j+1}=A_{i,j+1}+A_{i+1,j}......
  • [2024.11.15]NOIP 模拟赛
    赛后的思路永远比赛时清晰。赛时T1玩了一会发现\(a_3\sima_7\)一定是相邻的,所以只需要考虑两个数字即可。答案显然有单调性,所以考虑先二分\(a_2\),再二分\(a_1\)。两个二分的思路都很简单,第二个二分用lower_bound即可。第一个的话其实就是模拟lower_bound内置,赛时调......
  • 【数据结构副本篇】顺序表 链表OJ
    ......
  • CW 11.15 模拟赛记录
    看到说不按题目难度排序,先读下题初看\(\rm{T1}\)没什么思路\(\rm{T2}\)感觉像是\(\rm{dp}\),可能能多骗点?\(\rm{T3}\)又是计数\(\rm{T4}\)没思路感觉要寄,\(\rm{lhs}\)多半又要\(\rm{AK}\)\(\rm{T2}\)观察到这个类型的题比较熟,先开\(\rm{T2}\)简化题意......