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

数据结构 栈和队列

目录

  • 1. 栈
    • 1.1 栈的概念及结构
    • 1.2 栈的实现
  • 2. 队列
    • 2.1 队列的概念及结构
    • 2.2 队列的实现


正文开始

1. 栈

1.1 栈的概念及结构

栈是线性表的一种,这种数据结构只允许在固定的一端进行插入和删除元素的操作,进行数据插入和删除的一端称为栈顶,另一端称为栈底

这种数据结构的操作方式可以类比为弹匣,存取子弹只能在固定的一端(图源网络,侵删)
在这里插入图片描述


栈对应的两个操作:

  • 压栈:栈的插入操作,又叫进栈/压栈/入栈,插入的数据在栈顶
  • 出栈:栈的删除操作,删除的数据同样在栈顶

栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则
在这里插入图片描述

1.2 栈的实现

下面我们通过c语言来实现栈的结构以及相关操作。

实现栈的结构,我们可以通过顺序表或链表来实现,相对而言通过顺序表实现更好一些,因为顺序表对于尾部的操作效率更高一些。

对于栈我们提供出栈、入栈、判空等接口,下面来看具体代码:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef int STDataType;

//通过顺序表来实现栈
typedef struct Stack {
	STDataType* _a;
	int _top;		//栈顶
	int _capacity;	//容量
}Stack;

//初始化栈
void StackInit(Stack* ps) {
	assert(ps);
	ps->_a = NULL;
	ps->_capacity = ps->_top = 0;
}

//检查空间是否足够
void CheckCapacity(Stack* ps)
{
	if (ps->_top == ps->_capacity)
	{
		int NewCapacity = ps->_capacity == 0 ? 4 : 2 * ps->_capacity;
		STDataType* NewA = (STDataType*)realloc(ps->_a, sizeof(STDataType) * NewCapacity);
		if (NewA == NULL)
		{
			perror("realloc fail");
		}
		ps->_capacity = NewCapacity;
		ps->_a = NewA;
	}
}

//入栈
void StackPush(Stack* ps, STDataType data) {
	assert(ps);
	CheckCapacity(ps);
	*(ps->_a + ps->_top) = data;
	ps->_top++;
}

//出栈
void StackPop(Stack* ps)
{
	assert(ps && ps->_top > 0);
	ps->_top--;
}

//获取栈顶元素
STDataType StackTop(Stack* ps)
{
	assert(ps && ps->_top > 0);
	return *(ps->_a + ps->_top - 1);
}

//获取栈中有效元素个数
int StatckSize(Stack* ps) {
	assert(ps);
	return ps->_top;
}

//检测栈是否为空,若为空则返回非零结果
//若不为空则返回0
int StackEmpty(Stack* ps) {
	return ps->_top == 0;
}

//输出栈
void PrintStack(Stack* ps)
{
	for (int i = 0; i < ps->_top; i++)
	{
		printf("%d ", *(ps->_a + i));
	}
	printf("\n");
}

//销毁栈
void StackDestroy(Stack* ps) {
	assert(ps);
	free(ps->_a);
	ps->_a = NULL;
	ps->_capacity = ps->_top = 0;
}


值得注意的是,关于_top指向问题,有两种情况:

  • _top指向栈顶元素:初始化时应将_top指向 -1 的位置,因为它若指向 0 的位置,无法判断它是否为空。
  • _top指向栈顶元素的下一个位置:初始化时应将_top指向 0 的位置,这样就代表栈为空。上述代码就是按照这种方式的实现的。

2. 队列

2.1 队列的概念及结构

队列:一种只允许在一端进行插入数据操作,在另一端进行删除数据操作的线性表,队列符合先进先出FIFO(First In First Out)

这种数据结构可以类比为排队出门,先进队伍的先出门。

队列对应的两个操作:

  • 入队列:进行插入操作的一端称为队尾
  • 出队列:进行删除操作的一端称为队头

在这里插入图片描述

2.2 队列的实现

队列也可以通过顺序表或链表来实现,相对而言使用链表更优一些,因为使用顺序表在队头出队列时效率较低。

下面我们通过c语言来实现对应的结构和相关操作:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef int QDataType;

// 链式结构:表示队列的节点
typedef struct QListNode
{
	struct QListNode* _next;// 指针域
	QDataType _data;        // 数据
}QNode;

// 在处理队列时,需要用到队列的队头指针和队尾指针
// 所以直接将描述一个队列的信息封装到一个结构体中
// 这样在处理队列时,只需要一个结构体变量就足够了
// 队列的结构
typedef struct Queue
{
	QNode* _front; // 队头
	QNode* _rear;  // 队尾
	int size;      // 节点个数
}Queue;

// 初始化队列
void QueueInit(Queue* q) {
	assert(q);
	q->_front = q->_rear = NULL;
	q->size = 0;
}

// 申请节点
QNode* QListBuyNode(QDataType x)
{
	QNode* newNode = (QNode*)malloc(sizeof(QNode));
	if (newNode == NULL)
	{
		perror("malloc fail");
		exit(1);
	}
	newNode->_data = x;
	newNode->_next = NULL;
	return newNode;
}

// 队尾入队列
void QueuePush(Queue* q, QDataType data)
{
	assert(q);
	QNode* newNode = QListBuyNode(data);
	if (q->size == 0)
	{
		q->_front = q->_rear = newNode;
	}
	else {
		q->_rear->_next = newNode;
		q->_rear = q->_rear->_next;
	}
	q->size++;
}

// 队头出队列 
void QueuePop(Queue* q)
{
	assert(q && q->size);
	if (q->size == 1)
	{
		free(q->_front);
		q->_front = q->_rear = NULL;
	}
	else {
		QNode* PopNode = q->_front;
		q->_front = q->_front->_next;
		free(PopNode);
		PopNode = NULL;
	}
	q->size--;
}

// 获取队列头部元素 
QDataType QueueFront(Queue* q) {
	assert(q && q->size);
	return q->_front->_data;
}

// 获取队列队尾元素 
QDataType QueueBack(Queue* q) {
	assert(q && q->size);
	return q->_rear->_data;
}

// 获取队列中有效元素个数 
int QueueSize(Queue* q) {
	assert(q);
	return q->size;
}

// 检测队列是否为空
// 如果为空返回非零结果
// 如果非空返回0 
int QueueEmpty(Queue* q) {
	assert(q);
	return q->size == 0;
}

// 销毁队列 
void QueueDestroy(Queue* q)
{
	assert(q);
	while (q->_front) {
		QueuePop(q);
	}
	q->_front = NULL;
	q->_rear = NULL;
}



http://www.kler.cn/a/390361.html

相关文章:

  • HarmonyOS Next星河版笔记--界面开发(4)
  • 【秋招笔试-支持在线评测】11.13花子秋招(已改编)-三语言题解
  • 【2024最新】math-expression-evaluator 动态计算表达式的使用
  • MySQL数据库:SQL语言入门 【上】(学习笔记)
  • 鸿蒙next版开发:订阅应用事件(ArkTS)
  • Matlab自学笔记四十一:介绍日期时间型的显示格式:年‘y‘ 月‘M‘ 日‘d‘ 周‘e‘ 时‘h‘ 分‘m‘ 秒‘s‘
  • kafka面试题解答(四)
  • 软件测试学习记录 Day1
  • Mysql中数据添加,修改,删除
  • python实战(七)——基于LangChain的RAG实践
  • Simulink对仿真数据进行FFT频谱分析
  • Unity中IK动画与布偶死亡动画切换的实现
  • 【学习记录丨UVM】2.1uvm_component 与uvm_object
  • 人到一定年纪,要学会远离多巴胺
  • 群控系统服务端开发模式-应用开发-前端框架
  • 必应 Bing 国内广告开户及代运营服务的优势有哪些?
  • UE5.3 CineCameraRigRail组件实测
  • 实现3D热力图
  • VPN相关学习笔记
  • 企业级工位管理:Spring Boot实践
  • wget命令之Tomcat(三)
  • JVM垃圾回收详解二(重点)
  • 【数据结构】线性表——链表
  • 区块链技术在电子政务中的应用
  • 5 分钟内最多允许用户尝试登录3次,如果错误次数超过限制,需要对该用户进行锁定。如何实现?
  • 《Django 5 By Example》阅读笔记:p1-p16