C语言分别实现栈和队列详解流程

目录
  • 什么是栈
  • 栈的结构图示
  • 栈的实现
    • 创建栈的结构体
    • 初始化栈
    • 入栈
    • 出栈
    • 获取栈顶元素
    • 获取栈中有效元素个数
    • 检测栈是否为空
    • 栈的销毁
  • 什么是队列?
  • 队列的实现
    • 创建队列结构体
    • 初始化队列
    • 队尾入队列
    • 队头出队列
    • 获取队列头部元素
    • 获取队列尾部元素
    • 获取队列中元素个数
    • 检测队列是否为空
    • 销毁队列

什么是栈

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

压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。

出栈:栈的删除操作叫做出栈。出数据也在栈顶。

栈的结构图示

栈的实现

栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。

创建栈的结构体

我们用栈来存储数据,首先需要实现一个动态增长的栈。所以我们先创建一个栈的结构体。

typedef int STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;       //栈顶
	int capacity;  //容量
}Stack;

初始化栈

初始化栈的方式有很多种,我们可以根据不同的需求来选择。这里写一种常规的。

void StackInit(Stack* ps)
{
	assert(ps);//检测传过来的ps是否为空
	ps->a = NULL;//把a标识的这块空间先置为空
	ps->top = ps->capacity = 0;
}

入栈

一开始top为0标识栈顶的位置,所以我们要先将数据放入栈顶,在让top向后走一位。

void StackPush(Stack* ps, STDataType x)
{
	assert(ps);//检测ps是否为空

	//如果空间满了,我们需要扩容
	if (ps->capacity == ps->top)//判断空间是否满了的条件
	{
		int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;//指定新空间的大小
		ps->a = (STDataType*)realloc(ps->a, newCapacity*sizeof(STDataType));//进行扩容
		if (ps->a == NULL)//扩容失败
		{
			printf("realloc fail\n");
			exit(-1);//终止程序
		}
		ps->capacity = newCapacity;//让其标识新的空间的大小
	}
	ps->a[ps->top] = x;//将数据放入栈
	ps->top++;//top向后走一步
}

出栈

void StackPop(Stack* ps)
{
	assert(ps);
	if (ps->top > 0)//避免栈里面数据已经删除完了,top依旧向下减为负数
	{
		--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.

bool StackEmpty(Stack* ps)
{
	assert(ps);
	return ps->top == 0;//如果条件成立就返回真,否则就为假(不为空)
}

栈的销毁

void StackDestroy(Stack* ps)
{
	assert(ps);
	free(ps->a);//释放开辟的这一块空间
	ps->a = NULL;
	ps->top = ps->capacity = 0;
}

什么是队列?

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为对头。

队列的实现

队列也可以用数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。

创建队列结构体

我们使用链表来实现队列,我们需要创建一个存储队列信息的结构体。

typedef int QDataType;
//链式结构:表示队列
typedef struct QueueNode
{
	QDataType data;           //存储数据
	struct QueueNode* next;   //指针域
}QNode;
//队列的结构
typedef struct Queue
{
	QNode* head;//标识队头的位置
	QNode* tail;//标识队尾的位置
}Queue;

初始化队列

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = pq->tail = NULL;//将两个指针置为空
}

队尾入队列

让一个数据进入队列,我们只需要用链表结构来实现队列,在队尾进行尾插数据就可以了。

如果队列为空,需要单独处理一下。

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));//申请一个新的结点
	assert(newnode);//检测结点是否申请成功
	newnode->data = x;//
	newnode->next = NULL;
	if (pq->tail == NULL)//如果队列为空的情况
	{
		assert(pq->head==NULL);
		pq->tail = pq->head = newnode;
	}
	else//队列不为空的情况
	{
		pq->tail->next = newnode;//尾插一个新结点
		pq->tail = newnode;//更新尾的位置
	}
}

队头出队列

当队列为空,没有存储数据时,我们就不能够出数据。如果队列中只有一个结点,那么我们需要对其单独处理,否则就会出现错误。

void QueuePop(Queue* pq)
{
	assert(pq);
	assert(pq->head && pq->tail);//保证队列中有数据在往下走
	if (pq->head->next == NULL)//如果队列里面只有一个数据的情况
	{
		free(pq->head);//释放队头数据
		pq->head = pq->tail = NULL;//将队列的头指针和尾指针均置为空
	}
	else
	{
		QNode* next = pq->head->next;//让next指向队头结点的下一个结点
		free(pq->head);//释放队头结点
		pq->head = next;//让head指向next结点
	}
}

获取队列头部元素

检测队列是否为空,如果不为空则直接返回队列头指针指向的元素。

QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->head);//检测队列是否为空
	return pq->head->data;//返回队列头部元素
}

获取队列尾部元素

检测队列是否为空,如果不为空则直接返回队列尾指针指向的元素。

//获取队列队尾元素
QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->tail);//检测队列是否为空
	return pq->tail->data;//返回队列尾部元素
}

获取队列中元素个数

可以对队列进行遍历,统计元素个数,如果队列比较长那么这个方法效率就比较低。如果想要效率比较高,那么我们可以在定义队列结构体的时候加上一个size变量,每往队列里面入一个数据就统计一下,那么我们需要队列中元素个数的时候就可以直接返回。

int QueueSize(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->head;//让cur指向队头的元素
	size_t size = 0;//定义一个无符号的size变量用来计数
	while (cur)//cur不为空则进入循环继续执行
	{
		size++;//size=size+1
		cur = cur->next;//继续向后遍历
	}
	return size;//返回有效元素个数
}

检测队列是否为空

检测队列是否为空,如果为空返回非零结果,如果非空返回0

bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return (pq->head == NULL) && (pq->tail == NULL);
}

销毁队列

在使用完队列之后,我们应该对其进行销毁,防止造成内存泄漏。

void QueueDestroy(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	while (cur)
	{
		QNode* next = cur->next;//定义一个next指向cur的下一个结点
		free(cur);//释放cur
		cur = next;
	}
	pq->head = pq->tail = NULL;//将头尾指针均置为空
}

到此这篇关于C语言分别实现栈和队列详解流程的文章就介绍到这了,更多相关C语言栈和队列内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C语言循环队列与用队列实现栈问题解析

    目录 “莫听穿林打叶声,何妨吟啸且徐行” 这里是目录 循环队列题目描述题目链接思路分析代码实现 用队列实现栈题目描述题目链接思路分析代码实现 循环队列 循环队列: 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环循环队列的好处:可以重新利用队列的空间.我们可以利用这个队列之前用过的空间.在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间.但是使用循环队列,我们能使用这些空间去存储新的值. 题目描述 设计你

  • C语言超详细讲解栈与队列实现实例

    目录 1.思考-1 2.栈基本操作的实现 2.1 初始化栈 2.2 入栈 2.3 出栈 2.4 获取栈顶数据 2.5 获取栈中有效元素个数 2.6 判断栈是否为空 2.7 销毁栈 3.测试 3.1测试 3.2测试结果 4.思考-2 5.队列的基本操作实现 5.1 初始化队列 5.2 队尾入队列 5.3 队头出队列 5.4 队列中有效元素的个数 5.5 判断队列是否为空 5.6 获取队头数据 5.7 获取队尾的数据 5.8 销毁队列 6.测试 6.1测试 6.2 测试结果 1.思考-1 为什么栈用

  • C语言栈与队列面试题详解

    目录 1.括号匹配问题 2.用队列实现栈 3.用栈实现队列 4.设计循环队列 1.括号匹配问题 链接直达: 有效的括号 题目: 思路: 做题前,得先明确解题方案是啥,此题用栈的思想去解决是较为方便的,栈明确指出后进先出.我们可以这样设定: 遇到左括号“ ( ”.“ [ ”.“ { ”,入栈. 遇到右括号“ ) ”.“ ] ”.“ } ”,出栈,跟左括号进行匹配,不匹配就报错. 上两句话的意思就是说我去遍历字符串,如果遇到左括号,就入栈:遇到右括号,就出栈顶元素,并判断这个右括号是否与栈顶括号相匹

  • C语言中用栈+队列实现队列中的元素逆置

    下面举例代码: 提到的Q是一个队列,S是一个空栈,实现将队列中的元素逆置的算法 #include<stdio.h> #define MaxSize 10 typedef int ElemType; typedef struct{     ElemType data[MaxSize];     int front,rear; }Queue; typedef struct{     ElemType data[MaxSize];     int top; }SqStack;   void Init

  • C语言编程数据结构栈与队列的全面讲解示例教程

    目录 一.栈的表示和实现 1栈的概念和结构 2栈的初始化 3压栈(栈顶插入一个数据) 4出栈(栈顶删除一个数据) 5取栈顶元素 6取栈顶元素 7判断栈是否为空 二.队列的表示和实现 1队列的概念及结构 2队列的实现 3队列初始化 4入队(队尾插入一个数据) 5出队(队头删除一个数据) 6取队头数据 7取队尾数据 8计算队列中数据个数 9判断队列是否为空 10销毁队列 总结 一.栈的表示和实现 1栈的概念和结构 栈:一种特殊的线性表(逻辑上数据是连着放的),其只允许在固定的一端进行插入和删除操作.

  • C语言 浅谈栈与队列的定义与操作

    目录 栈的定义 栈的实现 前置 初始化栈 栈的销毁 栈的插入 出栈的操作 取栈顶元素 栈的大小 队列的定义 队列的基本操作 队列的初始化 队列的销毁 队列的插入 队列的删除 队列的判空 取出队头元素 取出队尾元素 队列的大小 栈的定义 栈同样是一种线性表,它的特性是插入元素必须从后面插入,删除元素也是从后面删除,进行数据删除和插入的一端称为栈顶,另一端是栈底. 压栈-就是插入元素 出栈-就是删除元素 它可以用数组实现也可以用链表实现 但是用数组实现更好,因为链表的插入和删除要进行遍历,而数组可以

  • C语言用栈模拟实现队列问题详解

    目录 题目描述 题目链接 思路分析 代码实现 题目描述 请你仅使用两个栈实现先入先出队列.队列应当支持一般队列支持的所有操作(push.pop.peek.empty). 你只能使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的. 题目链接 用栈实现队列 思路分析 题目的意思是要用两个栈来模拟实现一个队列.仅可以用栈的基本功能实现队列的基本功能.所以需要创建两个栈.所以这两个栈st1,st2可用一个结构

  • C语言数据结构进阶之栈和队列的实现

    目录 栈的实现: 一.栈的概念和性质 二.栈的实现思路 三.栈的相关变量内存布局图 四.栈的初始化和销毁 五.栈的接口实现: 1.入栈 2.出栈 3.获取栈顶的数据 4.获取栈的元素个数 5.判断栈是否为空 队列的实现: 一.队列的概念和性质 二.队列的实现思路 三.队列相关变量的内存布局图 四.队列的初始化和销毁 五.队列的接口实现: 1. 入数据 2.出数据 3.取队头数据 4.取队尾数据 5.获取队列元素个数 6.判断队列是否为空 总结 栈的实现: 一.栈的概念和性质 栈(stack)又名

  • C语言栈与队列相互实现详解

    目录 一.本章重点 二.队列实现栈 三.栈实现队列 四.解题思路总结 一.本章重点 用两个队列实现栈 用两个栈实现队列 解题思路总结 二.队列实现栈 我们有两个队列: 入栈数据1. 2. 3 可以将数据入队列至队列一或者队列二. 如何出栈? 但出栈要先出1,怎么办? 第一步: 将队列一出队n-1个至队列二. 第二步: pop队列一的最后一个元素. 接下来怎么入栈呢? 将元素入队至不为空的队列. 怎么判断栈空? 队列一和队列二都为空的情况下,栈就是空的. 如何取栈顶元素? 取不为空的队列尾部元素.

  • C语言分别实现栈和队列详解流程

    目录 什么是栈 栈的结构图示 栈的实现 创建栈的结构体 初始化栈 入栈 出栈 获取栈顶元素 获取栈中有效元素个数 检测栈是否为空 栈的销毁 什么是队列? 队列的实现 创建队列结构体 初始化队列 队尾入队列 队头出队列 获取队列头部元素 获取队列尾部元素 获取队列中元素个数 检测队列是否为空 销毁队列 什么是栈 栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素的操作.进行数据插入和删除的一端称为栈顶,另一端称为栈底.栈中的数据元素遵守先进后出LIFO(Last In First Out

  • C语言 表、栈和队列详解及实例代码

    C语言 表.栈和队列详解 表ADT 形如A1,A2,A3-An的表,这个表的大小为n,而大小为0的表称为空表,非空表中,Ai+1后继Ai,Ai-1前驱Ai,表ADT的相关操有PrintList打印表中的元素:CreateEmpty创建一个空表:Find返回关键字首次出现的位置:Insert和Delete从表的某个位置插入和删除某个关键字. 对表的所有操作都可以通过使用数组来实现,但在这里使用链表的方式来实现.链表(linked list)由一系列不必在内存中相连的结构组成,每个结构均含有元素和指

  • c语言数据结构之栈和队列详解(Stack&Queue)

    目录 简介 栈 一.栈的基本概念 1.栈的定义 2.栈的常见基本操作 二.栈的顺序存储结构 1.栈的顺序存储 2.顺序栈的基本算法 3.共享栈(两栈共享空间) 三.栈的链式存储结构 1.链栈 2.链栈的基本算法 3.性能分析 四.栈的应用——递归 1.递归的定义 2.斐波那契数列 五.栈的应用——四则运算表达式求值 1.后缀表达式计算结果 2.中缀表达式转后缀表达式 队列 一.队列的基本概念 1.队列的定义 2.队列的常见基本操作 二.队列的顺序存储结构 1.顺序队列 2.循环队列 3.循环队列

  • Javascript数据结构之栈和队列详解

    目录 前言 栈(stack) 栈实现 解决实际问题 栈的另外应用 简单队列(Queue) 队列实现 队列应用 - 树的广度优先搜索(breadth-first search,BFS) 优先队列 优先队列实现 线性数据结构实现优先队列 Heap(堆)数据结构实现优先队列 代码实现一个二叉堆 小顶堆在 React Scheduler 事务调度的包应用 最后 前言 我们实际开发中,比较熟悉的数据结构是数组.一般情况下够用了.但如果遇到复杂的问题,数组就捉襟见肘了.在解决一个复杂的实际问题的时候,选择一

  • Python全栈之队列详解

    目录 1. lock互斥锁 2. 事件_红绿灯效果 2.1 信号量_semaphore 2.2 事件_红绿灯效果 3. queue进程队列 4. 生产者消费者模型 5. joinablequeue队列使用 6. 总结 1. lock互斥锁 知识点: lock.acquire()# 上锁 lock.release()# 解锁 #同一时间允许一个进程上一把锁 就是Lock 加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,即串行的修改,没错,速度是慢了,但牺牲速度却保证了数据

  • C语言进阶栈帧示例详解教程

    目录 正片开始 栈有什么用? 寄存器 main函数创建 局部变量创建 函数部分 形参与实参 正片开始 今天来讲讲我对栈帧创建与销毁的拙见.理解什么是栈帧首先知道什么是栈: 在数据结构中, 栈是限定仅在表尾进行插入或删除操作的线性表.栈是一种数据结构,它按照后进先出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据. 栈有什么用? 在计算机系统中,栈也可以称之为栈内存是一个具有动态内存区域,存储函数内部(包括main函数)的局部变量和方法调用和函数参数值,

  • C语言实现栈的示例详解

    目录 前言 一. 什么是栈 二. 使用什么来实现栈 三. 栈的实现 3.1 头文件 3.2 函数实现 3.3 完整代码 四. 栈的用处 前言 前一段时间,我们试着用C语言实现了数据结构中的顺序表,单链表,双向循环链表.今天我们再用C语言来实现另一种特殊的线性结构:栈 一. 什么是栈 栈(stack)又名堆栈,它是一种运算受限的线性表.限定仅在表尾进行插入和删除操作的线性表.这一端被称为栈顶,相对地,把另一端称为栈底.向一个栈插入新元素又称作进栈.入栈或压栈,它是把新元素放到栈顶元素的上面,使之成

  • C语言数据结构之栈与队列的相互实现

    目录 一.用对列实现栈 代码实现 二.用栈实现队列 代码实现 一.用对列实现栈 题干要求: 细节分析:队列是先进先出: 要实现的栈是先进后出. 解题思路:假设:先用一个队列储存数据 N 个,然后将前 N-1 个数据导入到另一个队列, 此时,原始队列中仅剩一个,是最后剩的数据,便可将其导出,这便是一次后进先出. 细节点:每次导出数据时,都需要一个队列向另一个队列传入数据,因此输入队列和输出队列                    需要轮换,要对其进行判定. 具体过程gif动态图如下: 代码实现

  • C语言数据结构之栈和队列的实现及应用

    目录 一.栈的概念 二.Stack.h 三.Stack.c 1.栈的初始化和销毁 2.栈的进栈.出栈 3.栈的判空.访问栈顶元素.栈内元素个数 四.队列的概念 五.Queue.h 六.Queue.c 1.队列的初始化和销毁 2.队列的入队.出队 3.队列的判空 4.访问队头.队尾数据.统计队列长度 七.力扣中栈和队列OJ题 1.有效的括号 2.用队列实现栈 3.用栈实现队列 4.设计循环队列 栈和队列是一种数据结构,只规定了性质,并没有规定实现方式. 本文以顺序结构实现栈,链表方式实现队列. 一

随机推荐