数据结构 —— 栈 与 队列

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;*/
}
相关推荐
IT学长编程7 分钟前
计算机毕业设计 玩具租赁系统的设计与实现 Java实战项目 附源码+文档+视频讲解
java·spring boot·毕业设计·课程设计·毕业论文·计算机毕业设计选题·玩具租赁系统
莹雨潇潇9 分钟前
Docker 快速入门(Ubuntu版)
java·前端·docker·容器
杨哥带你写代码28 分钟前
足球青训俱乐部管理:Spring Boot技术驱动
java·spring boot·后端
小字节,大梦想29 分钟前
【C++】二叉搜索树
数据结构·c++
XKSYA(小巢校长)1 小时前
NatGo我的世界联机篇
开发语言·php
Cons.W1 小时前
Codeforces Round 975 (Div. 1) C. Tree Pruning
c语言·开发语言·剪枝
我是哈哈hh1 小时前
专题十_穷举vs暴搜vs深搜vs回溯vs剪枝_二叉树的深度优先搜索_算法专题详细总结
服务器·数据结构·c++·算法·机器学习·深度优先·剪枝
憧憬成为原神糕手1 小时前
c++_ 多态
开发语言·c++
VBA63371 小时前
VBA信息获取与处理第三个专题第三节:工作薄在空闲后自动关闭
开发语言
郭二哈1 小时前
C++——模板进阶、继承
java·服务器·c++