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

 更新时间:2021年11月03日 10:29:06   作者:MAX在码字  
栈和队列,严格意义上来说,也属于线性表,因为它们也都用于存储逻辑关系为 "一对一" 的数据,但由于它们比较特殊,因此将其单独作为一章,做重点讲解

栈的实现:

一、栈的概念和性质

栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在固定的一端进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶

在这里插入图片描述

二、栈的实现思路

栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小这里我们用顺序表结构来实现栈。
顺序表可以把使用的空间写成固定值,也可以构建动态开辟内存;但是如果写成固定的数组形式当存的数据满了就不能再使用了,所以下面我们实现的是动态开辟内存的形式。

所以我们先创建一个顺序表结构体类型,结构体类型中有指针,下标,容量。
指针: 用来维护在堆上连续的一段空间,
下标:表示数据存放到哪一个位置了,因为数据只能一个接着一个地存放,要有个下标来记录我数据放到哪一个位置了。
容量:与下标相比较,当下标与容量相等就表示空间存储满了,要进行扩容处理。
创建类型如下:

typedef int STDataType; //对int类型重新起个名字叫DataType

//创建一个栈结构体类型
struct Stack   
{
	STDataType* a; //数据的指针
	int top;    //栈顶
	int capacity; //记录开辟空间的最大下标处
};

//对顺序表类型struct Stack类型重新起个名字叫SL
typedef struct Stack ST;  

//当size 和 capacity相等时要进行扩容处理

三、栈的相关变量内存布局图

在这里插入图片描述

四、栈的初始化和销毁

//初始化变量st
void StackInit(ST* ps)
{
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}

//栈的销毁
void StackDestroy(ST* ps)
{
	free(ps->a);
	ps->a = NULL;
	ps->top = 0;
	ps->capacity = 0;
}

五、栈的接口实现:

1.入栈

//入栈
void StackPush(ST* ps, STDataType x)
{
	assert(ps);
	//内存满了要扩容
	if (ps->capacity == ps->top)
	{
		ps->capacity = ps->capacity > 0 ? ps->capacity * 2 : 2;
		STDataType* tmp = 
		(STDataType*)realloc(ps->a,sizeof(STDataType) * ps->capacity);
		if (tmp == NULL)
		{
			perror("erron ");
			exit(-1);
		}
		ps->a = tmp;
	}
	//没有满就直接在后面入栈
	ps->a[ps->top] = x;
	ps->top++;

}

2.出栈

//出栈,要注意栈不能为空
void StackPop(ST* ps)
{
	assert(ps);
	//栈为空就不能再出栈了
	assert(ps->top >= 1);

	ps->top--;
}

3.获取栈顶的数据

//返回栈顶的元素
STDataType StackTop(ST* ps)
{
	assert(ps);
	//栈不能为空
	assert(ps->top >= 1);
	return ps->a[ps->top - 1];

}

4.获取栈的元素个数

//获取栈的元素个数
int StackSize(ST* ps)
{
	assert(ps);
	assert(ps->top >= 1);
	return ps->top - 1;
}

5.判断栈是否为空

//判断栈是否为空
bool StackEmpty(ST* ps)
{
	return ps->top == 0;
}

队列的实现:

一、队列的概念和性质

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

在这里插入图片描述

二、队列的实现思路

队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。
而链表我们采用双向链接结构,一个指针来维护头节点,一个指针维护尾部节点

在这里插入图片描述

定义的结构体类型如下:

typedef int QDataType;

//创建一个结点型结构体
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QueueNode;

//创建一个队列
typedef struct Queue
{
	QueueNode* head;
	QueueNode* tail;
}Queue;

三、队列相关变量的内存布局图

在这里插入图片描述

四、队列的初始化和销毁

//初始化队列
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = NULL;
	pq->tail = NULL;
}

//队列销毁
void QueueDestroy(Queue* pq)
{
	assert(pq);
	QueueNode* cur = pq->head;
	while (cur != NULL)
	{
		QueueNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = NULL;
	pq->tail = NULL;
}

五、队列的接口实现:

1. 入数据

//入数据有两种情况
void QueuePush(Queue* pq,QDataType x)
{
	assert(pq);
	QueueNode* newNode = (QueueNode*)malloc(sizeof(QueueNode));
	if (newNode == NULL)
	{
		perror("erron ");
		exit(-1);
	}
	newNode->next = NULL;
	newNode->data = x;
	//1.入队列时队列为空状态
	if (pq->head == NULL)
	{
		pq->head = newNode;
		pq->tail = newNode;
	}
	//2.入队列,队列不为空,直接在尾指针后面链接即可
	else
	{
		pq->tail->next = newNode;
		pq->tail = newNode;
	}
}

2.出数据

//出数据,类似链表的头删
void QueuePop(Queue* pq)
{
	assert(pq);
	//要保证队列不能为空
	assert(pq->head != NULL);
	QueueNode* next = pq->head->next;
	free(pq->head);
	pq->head = next;

	//防止野指针出现,当队列为空时要把tail指针置为空
	if (pq->head == NULL)
	{
		pq->tail = NULL;
	}
}

3.取队头数据

//取队头数据
QDataType QueueFront(Queue* pq)
{
	assert(pq);
	//检验队列不能为空
	assert(pq->head != NULL);
	return pq->head->data;
}

4.取队尾数据

//取队尾数据
QDataType QueueBack(Queue* pq)
{
	assert(pq);
	//同样要检验队列不能为空
	assert(pq->head != NULL);
	return pq->tail->data;
}

5.获取队列元素个数

//获取队列元素个数
int QueueSize(Queue* pq)
{
	assert(pq);
	int count = 0;
	QueueNode* cur = pq->head;
	while (cur != NULL)
	{
		count++;
		cur = cur->next;
	}
	return count;
}

6.判断队列是否为空

//判断队列是否为空
bool QueueEmpty(Queue* pq)
{
	return pq->head == NULL;
}

总结

以上就是栈和队列的实现内容了,其中前面我只有把源文件Stack.c 和Queue.c拆开来分析了。如果想要栈和队列的全部内容,阔以移步到gitee上获取
【栈的源码链接,点击即可】
【队列的源码链接,点击即可】

到此这篇关于C语言数据结构进阶之栈和队列的实现的文章就介绍到这了,更多相关C语言 数据结构 内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C语言实现三子棋游戏的示例代码

    C语言实现三子棋游戏的示例代码

    今天我们将会用C语言实现三子棋。所谓三子棋,就是三行三列的棋盘,玩家可以和电脑下棋,率先连成三个的获胜。话不多说,我们开始吧
    2022-10-10
  • 详解C语言实现猜数字游戏

    详解C语言实现猜数字游戏

    这篇文章主要为大家介绍了C语言实现猜数字游戏,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助<BR>
    2022-01-01
  • QT实现定时关闭消息提示框

    QT实现定时关闭消息提示框

    这篇文章主要介绍了软件利用Qt简单实现消息提示框可定时自动关闭,文中的示例代码讲解详细,对我们;了解QT有一定的帮助,感兴趣的可以学习一下
    2022-01-01
  • C语言实现简易的扫雷小游戏

    C语言实现简易的扫雷小游戏

    这篇文章主要为大家详细介绍了C语言实现简易的扫雷小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-05-05
  • C语言实现学生信息管理系统(多文件)

    C语言实现学生信息管理系统(多文件)

    这篇文章主要为大家详细介绍了C语言实现学生信息管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-12-12
  • C++中的vector中erase用法实例代码

    C++中的vector中erase用法实例代码

    在vector数组中我们删除数组经常用的就是erase方法,但是earse的用法一不注意就会出错,今天我就遇到了,所以在这里总结一下,避免大家用错,对vector中erase用法感兴趣的朋友跟随小编一起看看吧
    2022-11-11
  • C语言字符串原地压缩实现方法

    C语言字符串原地压缩实现方法

    这篇文章主要介绍了C语言字符串原地压缩实现方法,包含了字符串的遍历与转换等操作,是很实用的操作技巧,需要的朋友可以参考下
    2014-09-09
  • C++ 智能指针深入解析

    C++ 智能指针深入解析

    以下是对C++中智能指针的使用进行了详细的分析介绍,需要的朋友可以参考下
    2013-07-07
  • C语言示例讲解结构体的声明与初始化方法

    C语言示例讲解结构体的声明与初始化方法

    结构体是一些值的集合,这些值称为成员变量,结构体的每个成员可以是不同类型的变量。本文将通过示例为大家详细讲讲C语言中结构体的使用,需要的可以参考一下
    2022-07-07
  • C/C++读写JSON数据的详细过程记录

    C/C++读写JSON数据的详细过程记录

    JSON文件无论是在web开发、客户端开发、服务端等开发中都是应用比较广泛的的第一种轻量级数据交换格式,非常方便阅读和编写,下面这篇文章主要给大家介绍了关于C/C++读写JSON数据的详细过程,需要的朋友可以参考下
    2023-04-04

最新评论