数据结构 -- #栈和队列的定义和基本实现

发布于:2024-12-18 ⋅ 阅读:(138) ⋅ 点赞:(0)

若没有相关知识基础,可以先看看下面文章哦🤗👇
线性表


栈和队列的基本概念

栈(stack)是只允许在一端进行插入和删除操作的线性表
其最大的特性就是LIFO(last in first out) 后进先出

栈的顺序存储实现
#include<iostream>

using namespace std;

#define maxSize 10//栈的最大容量

typedef struct {
	int a[maxSize];
	int top;
}sqStack;
//初始化
void initStack(sqStack& s) {
	s.top = -1;//栈顶指针的初始化有多种,每种都要注意其栈满的条件
}
//判空
bool empty(sqStack& s) {
	if (s.top == -1)return true;
}
//入栈
bool push(sqStack& s, int x) {
	//如果maxSize为10,我们的有效存储下标为0~9
	if (s.top == maxSize - 1)return false;
	
	s.a[++s.top] = x;//栈顶指针先移动,然后元素入栈
	
	return true;
}
//出栈
bool pop(sqStack& s, int& x) {
	if (s.top == -1)return false;//栈空

	x = s.a[s.top--];//先出栈,指针再移动

	return true;
}
//得到栈顶元素
bool getTop(sqStack s, int& x) {
	if (s.top == -1)return false;
	
	x = s.a[s.top];

	return true;
}

int main() {

	return 0;
}
栈的链式存储实现(不带头结点)

由于栈是特殊的线性表,
我们可以采用头插法建立单链表的形式实现链栈
以下是不带头结点的链栈基本操作,在不带头结点的链栈中,
首结点相当于栈顶

#include<iostream>
using namespace std;

typedef struct linkStack {
	int num;
	struct linkStack* next;
}stackNode,*linkStack;

void initStack(linkStack& s) {
	s = NULL;
}
//判断是否为空
bool isEmpty(linkStack s) {
	return s == NULL;
}
//计算栈的长度
int getLen(linkStack s) {
	int length = 0;
	stackNode* temp = s;
	
	while (temp != NULL) {
		length++;
		temp = temp->next;
	}

	return length;
}
//利用单链表的头插法进行链栈的入栈操作
bool push(linkStack& s, int x) {
	stackNode* p =(stackNode*)malloc(sizeof(stackNode));
	//如果当前栈中没有结点,那么当前节点为首结点
	if (isEmpty(s)) {
		p = s;
		return true;
	}
	
	p->num = x;
	p->next = s;
	s = p;
    return true;
}

bool pop(linkStack& s, int& x) {
	if (isEmpty(s))return false;

	stackNode* p = (stackNode*)malloc(sizeof(stackNode));
	x = s->num;//返回弹出的元素
	p = s;
	s = s->next;
	free(p);//删除之前的首结点

	return true;
}

int getTop(linkStack s) {
	if (isEmpty)return -999;//代表不存在
	return s->num;
}

队列

只允许在一端插入,在另一端删除的线性表

其最大特性为先进先出(First in first out)

队列的顺序存储实现

#include <iostream>

using namespace std;

#define maxSize 10

typedef struct {
	int num[maxSize];
	int front, rear;
}sqQueue;
//初始化队列,规定头指针front==尾指针rear的时候
//为队空状态
void initQueue(sqQueue& q) {
	q.rear = q.front = 0;
}
//判断队列是否为空
bool queueEmpty(sqQueue q) {
	if (q.rear == q.front)return true;

	return false;
}
//入队
bool enQueue(sqQueue& q, int x) {
    //判断队列是否存满
	if ((q.rear + 1) % maxSize == q.front)return false;
	//在尾部插入
	q.num[q.rear] = x;
    //尾指针自增
	q.rear = (q.rear + 1) % maxSize;
	return true;
}
//出队
bool deQueue(sqQueue& q, int& x) {
    //队列如果为空则无法出队返回false
	if (queueEmpty(q))return false;
	//将出队的元素带回
	x = q.num[q.front];
    //对头指针自增
	q.front = (q.front + 1) % maxSize;
	return true;
}
//读取队头
bool getHead(sqQueue q, int& x) {
    //队列为空则返回false
	if (queueEmpty(q))return false;
	//读取队头元素
	x = q.num[q.front];
	return true;
}

if ((q.rear + 1) % maxSize == q.front)return false;

  • 如何判断队满?
    借助于模运算的性质,我们将存储数据的下标映射到0~maxSize-1这样的范围,形成一个环状结构(循环队列)
    由于队头指针==队尾指针已经被定义成为判断队列是否为空的条件,所以要换一种形式来定义队列是否已满。
  • 这里我们通过牺牲一个存储单元的形式来判断是否存满
    在这里插入图片描述

队列的链式存储实现(带头结点)

链式队列的特性就类似于在单链表的表头进行删除,表尾进行插入的操作

//链队每个结点的类型
typedef struct linkNode {
	int data;
	struct linkNode* next;
}linkNode;
//链队的头尾指针
//头指针相当于队头,尾指针相当于队尾
typedef struct {
	linkNode* front;
	linkNode* rear;
}linkQueue;
//初始化链队
void initQueue(linkQueue& q) {
    //初始化头尾指针
	q.front = q.rear = (linkNode*)malloc(sizeof(linkNode));
    q.front->next = NULL;
}
//判断是否为空
bool isEmpty(linkQueue q) {
	if (q.front == q.rear)return true;
	else return false;
}
//入队
void enQueue(linkQueue& q, int x) {
    //定义新结点
	linkNode* s = (linkNode*)malloc(sizeof(linkNode));
    s->data = x;
    //由于入队操作是在队尾,且当前元素入队之后一定是最后一个元素
    //所以其指向为NULL
	s->next = NULL;
    //之前的队尾指向新的队尾
	q.rear->next = s;
    //之前的队尾指针变为新的队尾
	q.rear = s;
}
//出队
bool deQueue(linkQueue& q, int& x) {
    //队空则出队失败
	if (isEmpty(q))return false;
	//让p指向出队结点,即头指针的next
	linkNode* p = q.front->next;
    //将元素记录
	x = p->data;
    //删除
	q.front->next = p->next;
    //如果被删除的元素是队列中最后一个元素
    //那么需要修改队尾指针指向
	if (q.rear == p)q.rear = q.front;
    //释放节点
	free(p);
	return true;
}
//获取队头
int getTop(linkQueue q){
	if (isEmpty(q))return -9999;//代表不存在

    return q.front->data;
}
入队图解

在这里插入图片描述
在这里插入图片描述

出队图解

在这里插入图片描述
在这里插入图片描述

总结

栈和队列都是一种操作受限的线性表,
栈只能在栈顶插入,删除。
其特点就是先进后出,类似于压子弹入匣的过程

而队列只能在队头删除,队尾删除。
其特点是先进先出。


🌻编写本篇文章目的是笔者想以输出的形式进行学习,顺便记录学习点滴🌻

🌹 如果本篇文章对你有帮助的话那就点个赞吧👍🌹

😇 本篇文章存在多处不足,如有修改意见,可以私信或者评论哦,还望海涵 😇

本篇文章部分内容来自于 王道-数据结构



网站公告

今日签到

点亮在社区的每一天
去签到