数据结构 —— 栈 与 队列

1.栈

1.1栈的结构和概念

栈(Stack)是一种特殊的线性数据结构,它遵循后进先出(LIFO,Last In First Out)的原则。栈只允许在一端插入和删除数据,这一端被称为栈顶(top),另一端被称为栈底(bottom)。

就像弹匣一样,先压进去的子弹会最后被发射,最后压进去的子弹反而最先被发射

1.2栈的实现 (数组)

栈的基本功能:

  1. push(元素):将元素压入栈顶。
  2. pop():从栈顶删除元素,并返回该元素。如果栈为空,则此操作可能会导致错误。
  3. peek() 或 top():返回栈顶元素,但不删除它。
  4. Empty():检查栈是否为空。
  5. size():返回栈中元素的数量。

Stack.h

复制代码
#pragma once
// 支持动态增长的栈
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>

typedef int STDataType;
typedef struct Stack
{
	STDataType* _a;
	int _top;		// 栈顶
	int _capacity;  // 容量 
}Stack;

// 初始化栈 
void StackInit(Stack* ps);
// 入栈 
void StackPush(Stack* ps, STDataType data);
// 出栈 
void StackPop(Stack* ps);
// 获取栈顶元素 
STDataType StackTop(Stack* ps);
// 获取栈中有效元素个数 
int StackSize(Stack* ps);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
int StackEmpty(Stack* ps);
// 销毁栈 
void StackDestroy(Stack* ps);

Stack.c

复制代码
#include"Stack.h"

// 初始化栈 
void StackInit(Stack* ps) {
	assert(ps);

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

	//扩容
	if (ps->_top == ps->_capacity)
	{
		int newcapacity = ps->_capacity == 0 ? 2 : ps->_capacity * 2;
		STDataType* newa = (STDataType*)realloc(ps->_a,newcapacity * sizeof(STDataType));
		if (newa == NULL)
		{
			perror("realloc");
			return;
		}
		ps->_capacity = newcapacity;
		ps->_a = newa;
	}

	ps->_a[ps->_top] = data;
	ps->_top++;
}
// 出栈 
void StackPop(Stack* ps) {

	assert(ps);
	assert(ps->_top > 0);

	ps->_top--;
}
// 获取栈顶元素 
STDataType StackTop(Stack* ps) {
	assert(ps);
	assert(ps->_top > 0);
	return ps->_a[ps->_top - 1];
}
// 获取栈中有效元素个数 
int StackSize(Stack* ps) {
	assert(ps);
	return ps->_top;
}
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
int StackEmpty(Stack* ps) {
	assert(ps);

	return ps->_top == 0;//为空就是真,返回非0

}
// 销毁栈 
void StackDestroy(Stack* ps) {
	assert(ps);

	ps->_top = 0;
	ps->_capacity = 0;
	free(ps->_a);
	ps->_a = NULL;
}

2.队列(单链表)

2.1队列的概念和结构

队列(Queue)是一种特殊的线性表,它遵循先进先出(FIFO)的原则,即最早进入队列的元素将最先从队列中移除。队列只允许在表的前端(front)进行删除操作,称为出队,而在表的后端(rear)进行插入操作,称为入队。

先进先出,后进后出

2.2队列的实现(链表)

  1. 入队(Push):在队列的尾部添加一个元素。

  2. 出队(Pop):从队列的头部移除一个元素,并返回该元素。

  3. 判断队列是否为空(Empty):检查队列是否不包含任何元素。

  4. 获取队列大小(Size):返回队列中当前元素的数量。

  5. 查看队头元素(Front):返回队列头部的元素,但不从队列中移除它。

  6. 查看队尾元素(Back):返回队列尾部的元素,但不从队列中移除它

Queue.h

复制代码
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.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);
// 队尾入队列 
void QueuePush(Queue* q, QDataType data);
// 队头出队列 
void QueuePop(Queue* q);
// 获取队列头部元素 
QDataType QueueFront(Queue* q);
// 获取队列队尾元素 
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数 
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q);
// 销毁队列 
void QueueDestroy(Queue* q);

Queue.c

复制代码
#include"Queue.h"

// 初始化队列 
void QueueInit(Queue* q) {
	assert(q);

	q->size = 0;
	q->_front = NULL;
	q->_rear = NULL;
}
// 队尾入队列 
void QueuePush(Queue* q, QDataType data) {
	assert(q);

	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("QueuePush()::malloc()");
		return;
	}

	newnode->_data = data;
	newnode->_next = NULL;
	
	//队列为NULL
	if (q->_front == NULL)
	{
		q->_front = q->_rear = newnode;
	}
	else
	{
		q->_rear->_next = newnode;
		q->_rear = q->_rear->_next;
	}

	q->size++;
}
// 队头出队列 
void QueuePop(Queue* q) {
	assert(q);
	assert(q->size != 0);

	//单个节点
	if (q->_front == q->_rear)
	{
		free(q->_front);
		q->_front = q->_rear = NULL;
	}
	//多个节点
	else
	{
		QNode* next = q->_front->_next;
		free(q->_front);
		q->_front = next;
	}

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

	assert(q);
	assert(q->_front);//队头不能为NULL

	return q->_front->_data;
}
// 获取队列队尾元素 
QDataType QueueBack(Queue* q) {
	assert(q);
	assert(q->_rear);//队尾不能为NULL

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

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

	return q->size == 0;
}
// 销毁队列 
void QueueDestroy(Queue* q) {
	assert(q);

	QNode* cur = q->_front;
	while (cur)
	{
		QNode* next = cur->_next;
		free(cur);
		cur = next;
	}

	q->_front = q->_rear = NULL;
	q->size = 0;

	//这个应该留给用户去释放
	/*free(q);
	q = NULL;*/
}
相关推荐
Dovis(誓平步青云)22 分钟前
《QT学习第四篇:常见事件与UDP、TCP、文件系统、(锁、信号量、条件变量》
c语言·开发语言·汇编·qt
aWty_26 分钟前
实分析入门(11)--Cantor三分集
学习·数学·算法·实变函数
兰令水26 分钟前
leecodecode【二叉树递归+对称】【2026.6.1打卡-java版本】
算法
AI人工智能+电脑小能手7 小时前
【大白话说Java面试题 第87题】【Mysql篇】第17题:分布式事务的实现原理?
java·数据库·分布式·mysql·面试
来杯@Java8 小时前
图书管理系统(基于springboot+vue前后端分离的项目)计算机毕业设计java
java·spring boot·spring·vue·毕业设计·mybatis·课程设计
地平线开发者9 小时前
profiler debug 工具用法与高一致性策略
算法·自动驾驶
卷毛的技术笔记9 小时前
告别硬编码!Spring AI Alibaba 实现 AI Agent 智能工具调用(Tool Calling)
java·人工智能·后端·python·spring·ai编程
编程大师哥9 小时前
匿名函数 lambda + 高阶函数
java·python·算法
isyangli_blog9 小时前
OpenDayLight (Carbon 版本) 启动与组件安装
开发语言·php
vb2008119 小时前
FastAPI APIRouter
开发语言·python