【数据结构】栈和队列

目录

1.栈

栈的概念模型:

先进后出规律模型:  ​编辑

栈的应用: 

栈的实现 

栈创建分析: 

 我们需要实现的功能接口如下:

 栈的初始化

栈的入栈 

栈的出栈 

 查看栈顶元素

 计算栈的元素个数

 判空

 栈的销毁

 栈整个代码实现和测试文件:

 Stack.h

Stack.c 

Text.c 

 2.队列

 队列的概念模型:

​编辑 先进先出的规律:

 栈的应用:

队列的实现 

队列创建分析: 

数组实现:

链表实现: 

 我们需要实现的功能接口如下:

 队列的初始化

 队列的插入

 队列的删除

 获取队列头部元素

 获取队列队尾元素

 获取队列中有效元素个数

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

 销毁队列

 队列整个代码实现和测试文件:

Queue.h 

Queue.c 

Text.c 


1.栈

栈是数据结构中的一种线性结构,栈的出入数据只能从一端进行,所以栈的出入规律是先进后出(FILO, First In Last Out )。

栈的概念模型:

先进后出规律模型:  

栈的应用: 

  •  算法上的递归应用
  •  游戏上的多开界面,比如打开背包之后,又可以打开装备属性的界面,但是这时候背包界面   却没有关闭。

栈的实现 

栈创建分析: 

栈是一种只有一端出口,并且先进后出的数据结构,实现方面我们可以通过数组或者链表进行实现,他们两种实现各有优劣,小编这边使用的是数组实现,当然为了更加动态的表示栈,我们这边使用动态数组实现。

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>

// 类型声明
typedef int STDataType;


typedef struct Stack
{
	STDataType* a;	// 动态数组
	int top;		// 栈顶
	int capacity;	// 表示空间容量
}ST;

 我们需要实现的功能接口如下:

// 栈的初始化
void StackInit(ST* pst);

// 入栈
void StackPush(ST* pst, STDataType x);

// 出栈
void StackPop(ST* pst);

// 查看栈顶元素
STDataType StackTop(ST* pst);

// 计算栈的元素个数
int StackSize(ST* pst);

// 判空
bool StackEmpty(ST* pst);

// 栈的销毁
void StackDestory(ST* pst);

 栈的初始化

 我们这边实现栈的初始化有一个分歧,就是我们的top初始化什么?如果初始化为0,那么top代表的就是栈的元素个数,初始化为-1,那么top代表的就是动态数组的下标。

我这边为了方便后续判断栈的满我的top就初始化为0。 

代码实现: 

// 栈的初始化
void StackInit(ST* pst)
{
	// 判空
	assert(pst);

	// 初始化
	pst->a = NULL;
	pst->top = 0;
	pst->capacity = 0;
}

栈的入栈 

 栈为空时我们入栈的概念图,但是我们需要判断栈是否为满,如果满了就重新分配空间,没满就直接插入。

 代码实现: 

// 入栈
void StackPush(ST* pst, STDataType x)
{
	// 判空
	assert(pst);

	// 判栈的满
	// 我这边定义的top为0,所以代表的是数据的个数,当个数和容量相等时为满
	if (pst->top == pst->capacity)
	{
		// 三目操作符
		// 判断原空间是否为0,为0则先分配4个空间,不为0则开辟两倍空间。
		int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;

		// 动态分配空间
		STDataType* tmp = (STDataType*)malloc(newcapacity * sizeof(STDataType));
		// 判断是否申请成功
		if (NULL == tmp)
		{
			perror("StackPush()::malloc fail");
			return 1;
		}
			pst->a = tmp;
			pst->capacity = newcapacity;
	}

	// 入栈
	pst->a[pst->top] = x;
	pst->top++;
}

栈的出栈 

 栈的出栈实现很简单,我们只需要将top--就行了,这样动态输入就访问不到原栈顶元素了,但是我们还是需要注意如果栈内的元素为0,我们是不可以执行出栈操作的。

 代码实现: 

// 出栈
void StackPop(ST* pst)
{
	// 判空
	assert(pst);
	// 栈内数据不可以为0
	assert(pst->top > 0);

	// 出栈
	pst->top--;
}

 查看栈顶元素

每次查看栈顶元素需要我们访问最上层数据,在每次访问后需要记录下来返回,过程中top代表的是数据个数,返回下标需要减1。

 代码实现:

// 查看栈顶元素
STDataType StackTop(ST* pst)
{
	// 判空
	assert(pst);
	// 栈内数据不可以为0
	assert(pst->top > 0);

	return pst->a[pst->top - 1];
}

 计算栈的元素个数

由于我们前边的top定义是0,top代表的是栈内数据的个数,我们直接返回top即可。 

 代码实现:

// 计算栈的元素个数
int StackSize(ST* pst)
{
	// 判空
	assert(pst);

	return pst->top;
}

 判空

判空也很简单我们只需要验证top是否为0即可。 

  代码实现:

// 判空
bool StackEmpty(ST* pst)
{
	// 判空
	assert(pst);

	return pst->top == 0;
}

 栈的销毁

由于我们的栈内数据是由动态内存申请的,所以我们最后需要释放动态内存在堆区申请的空间,防止空间泄露。 

// 栈的销毁
void StackDestory(ST* pst)
{
	// 判空
	assert(pst);

	free(pst->a);
	pst->a = NULL;
	pst->capacity = pst->top = 0;
}

 栈整个代码实现和测试文件:

 Stack.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>

// 类型声明
typedef int STDataType;


typedef struct Stack
{
	STDataType* a;	// 动态数组
	int top;		// 栈顶
	int capacity;	// 表示空间容量
}ST;

// 栈的初始化
void StackInit(ST* pst);

// 栈的销毁
void StackDestory(ST* pst);

// 入栈
void StackPush(ST* pst, STDataType x);

// 出栈
void StackPop(ST* pst);

// 查看栈顶元素
STDataType StackTop(ST* pst);

// 计算栈的元素个数
int StackSize(ST* pst);

// 判空
bool StackEmpty(ST* pst);

Stack.c 

#include "Stack.h"

// 栈的初始化
void StackInit(ST* pst)
{
	// 判空
	assert(pst);

	// 初始化
	pst->a = NULL;
	pst->top = 0;
	pst->capacity = 0;
}

// 入栈
void StackPush(ST* pst, STDataType x)
{
	// 判空
	assert(pst);

	// 判栈的满
	// 我这边定义的top为0,所以代表的是数据的个数,当个数和容量相等时为满
	if (pst->top == pst->capacity)
	{
		// 三目操作符
		// 判断原空间是否为0,为0则先分配4个空间,不为0则开辟两倍空间。
		int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;

		// 动态分配空间
		STDataType* tmp = (STDataType*)malloc(newcapacity * sizeof(STDataType));
		// 判断是否申请成功
		if (NULL == tmp)
		{
			perror("StackPush()::malloc fail");
			return 1;
		}
			pst->a = tmp;
			pst->capacity = newcapacity;
	}

	// 入栈
	pst->a[pst->top] = x;
	pst->top++;
}

// 出栈
void StackPop(ST* pst)
{
	// 判空
	assert(pst);
	// 栈内数据不可以为0
	assert(pst->top > 0);

	// 出栈
	pst->top--;
}

// 查看栈顶元素
STDataType StackTop(ST* pst)
{
	// 判空
	assert(pst);
	// 栈内数据不可以为0
	assert(pst->top > 0);

	return pst->a[pst->top - 1];
}

// 计算栈的元素个数
int StackSize(ST* pst)
{
	// 判空
	assert(pst);

	return pst->top;
}

// 判空
bool StackEmpty(ST* pst)
{
	// 判空
	assert(pst);

	return pst->top == 0;
}

// 栈的销毁
void StackDestory(ST* pst)
{
	// 判空
	assert(pst);

	free(pst->a);
	pst->a = NULL;
	pst->capacity = pst->top = 0;
}

Text.c 

#include "Stack.h"

int main()
{
	ST s1;

	// 栈的初始化
	StackInit(&s1);

	// 入栈
	StackPush(&s1, 1);
	StackPush(&s1, 2);
	StackPush(&s1, 3);
	StackPush(&s1, 4);

	// 出栈
	/*printf("%d ", StackTop(&s1));
	StackPop(&s1);
	printf("%d ", StackTop(&s1));
	StackPop(&s1);
	printf("%d ", StackTop(&s1));
	StackPop(&s1);
	printf("%d ", StackTop(&s1));*/
	// 报错
	/*StackPop(&s1);
	printf("%d ", StackTop(&s1));*/

	// 如果栈的元素不为0,则打印,然后删除
	/*while (!StackEmpty(&s1))
	{
		printf("%d ", StackTop(&s1));
		StackPop(&s1);
	}*/

	// 计算栈的元素个数
	int ret = StackSize(&s1);
	printf("栈的数据个数为:%d", ret);

	// 栈的销毁
	StackDestory(&s1);

	return 0;
}

 2.队列

 队列是数据结构中的一种线性结构,队列的出入数据只能从队尾进行,出数据只能从队首进行,所以队列的出入规律是先进先出(FIFO, First In First Out )。

 队列的概念模型:

 先进先出的规律:

队列的数据是由一端对尾进入,队首出去,所以是先进先出的规律。 

 栈的应用:

  • 我们平时点奶茶时会在小程序上获得一个排序号,这就是通过队列实现的。
  • 为了保证公平性的抽号机器 

队列的实现 

队列创建分析: 

同栈一样,队列也属于线性的数据结构,实现队列我们也可以通过数组或者链表来实现。 

数组实现:

找首位数据很容易,但是入队列和出队列都要对整体的数据进行挪动太过于麻烦。

链表实现: 

入队列和出队列十分方便,但是每次都需要找队尾,我们可以提前定义队尾指针解决这个问题。 

综上我决定使用链表实现队列。 

 队列节点:

 

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>

// 类型声明
typedef int QDataType;

// 每个队列数据的节点创建
typedef struct QueueNode
{
	QDataType data;		// 存放数据
	struct QueueNode* next; // 指向下一个节点的指针
}QueueNode;

为了方便使用头尾指针我们创建一个存放头尾指针的结构体,同时也具有避免传二级指针的担忧,然后再定义一个size用于记录数据的个数。

// 存放头尾指针的结构体
typedef struct Queue
{
	QueueNode* head;
	QueueNode* tail;
    int size;
}Queue;

 我们需要实现的功能接口如下:

// 队列的初始化
void QueueInit(Queue* pq);

// 队列的插入
void QueuePush(Queue* pq, QDataType x);

// 队列的删除
void QueuePop(Queue* pq);

// 获取队列头部元素
QDataType QueueFront(Queue* pq);

// 获取队列队尾元素
QDataType QueueBack(Queue* pq);

// 获取队列中有效元素个数
int QueueSize(Queue* pq);

// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
bool QueueEmpty(Queue* pq);

// 销毁队列
void QueueDestroy(Queue* pq);

 队列的初始化

 头尾指针指向NULL,将size定义为。

代码实现: 

// 队列的初始化
void QueueInit(Queue* pq)
{
	// 判空
	assert(pq);

	pq->head = pq->tail = NULL;
	pq->size = 0;
}

 队列的插入

 代码实现:

// 队列的插入
void QueuePush(Queue* pq, QDataType x)
{
	// 判空
	assert(pq);

	// 插入
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	if (NULL == newnode)
	{
		perror("QueuePush()::malloc fail");
		return 1;
	}

	newnode->next = NULL;
	newnode->data = x;

	// head为空
	if (pq->head == NULL)
	{
		pq->head = pq->tail = newnode;
	}
	else {
		pq->tail->next = newnode;
		pq->tail = newnode;
	}

	pq->size++;
}

 队列的删除

  代码实现:

void QueuePop(Queue* pq)
{
	// 判空
	assert(pq);
	assert(pq->head != NULL);

	// 删除
	// 只有一个节点
	if (pq->head->next == NULL)
	{
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
	else {
		Queue* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}

	pq->size--;
}

 获取队列头部元素

 代码实现:

QDataType QueueFront(Queue* pq)
{
	// 判空
	assert(pq);
	assert(pq->head != NULL);

	return pq->head->data;
}

 获取队列队尾元素

 代码实现:

QDataType QueueBack(Queue* pq)
{
	// 判空
	assert(pq);
	assert(pq->head != NULL);

	return pq->tail->data;
}

 获取队列中有效元素个数

 代码实现:

int QueueSize(Queue* pq)
{
	// 判空
	assert(pq);

	return pq->size;
}

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

  代码实现:

bool QueueEmpty(Queue* pq)
{
	// 判空
	assert(pq);

	return pq->size == 0;
}

 销毁队列

 代码实现:

void QueueDestroy(Queue* pq)
{
	QueueNode* cur = pq->head;
	while (cur)
	{
		QueueNode* next = cur->next;
		free(cur);
		cur = next;
	}

	pq->head = pq->tail = NULL;
	pq->size = 0;
}

 队列整个代码实现和测试文件:

Queue.h 

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>

// 类型声明
typedef int QDataType;

// 每个队列数据的节点创建
typedef struct QueueNode
{
	QDataType data;		// 存放数据
	struct QueueNode* next; // 指向下一个节点的指针
}QueueNode;

// 存放头尾指针的结构体
typedef struct Queue
{
	QueueNode* head;
	QueueNode* tail;
	int size;
}Queue;

// 队列的初始化
void QueueInit(Queue* pq);

// 队列的插入
void QueuePush(Queue* pq, QDataType x);

// 队列的删除
void QueuePop(Queue* pq);

// 获取队列头部元素
QDataType QueueFront(Queue* pq);

// 获取队列队尾元素
QDataType QueueBack(Queue* pq);

// 获取队列中有效元素个数
int QueueSize(Queue* pq);

// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
bool QueueEmpty(Queue* pq);

// 销毁队列
void QueueDestroy(Queue* pq);

Queue.c 

#include "Queue.h"

// 队列的初始化
void QueueInit(Queue* pq)
{
	// 判空
	assert(pq);

	pq->head = pq->tail = NULL;
	pq->size = 0;
}

// 队列的插入
void QueuePush(Queue* pq, QDataType x)
{
	// 判空
	assert(pq);

	// 插入
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	if (NULL == newnode)
	{
		perror("QueuePush()::malloc fail");
		return 1;
	}

	newnode->next = NULL;
	newnode->data = x;

	// head为空
	if (pq->head == NULL)
	{
		pq->head = pq->tail = newnode;
	}
	else {
		pq->tail->next = newnode;
		pq->tail = newnode;
	}

	pq->size++;
}

// 队列的删除
void QueuePop(Queue* pq)
{
	// 判空
	assert(pq);
	assert(pq->head != NULL);

	// 删除
	// 只有一个节点
	if (pq->head->next == NULL)
	{
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
	else {
		Queue* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}

	pq->size--;
}

// 获取队列头部元素
QDataType QueueFront(Queue* pq)
{
	// 判空
	assert(pq);
	assert(pq->head != NULL);

	return pq->head->data;
}

// 获取队列队尾元素
QDataType QueueBack(Queue* pq)
{
	// 判空
	assert(pq);
	assert(pq->head != NULL);

	return pq->tail->data;
}

// 获取队列中有效元素个数
int QueueSize(Queue* pq)
{
	// 判空
	assert(pq);

	return pq->size;
}

// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
bool QueueEmpty(Queue* pq)
{
	// 判空
	assert(pq);

	return pq->size == 0;
}

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

	pq->head = pq->tail = NULL;
	pq->size = 0;
}

Text.c 

#include "Queue.h"


int main()
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, 1);
	QueuePush(&q, 2);

	printf("%d ", QueueFront(&q));
	QueuePop(&q);

	QueuePush(&q, 3);
	QueuePush(&q, 4);

	while (!QueueEmpty(&q))
	{
		printf("%d ", QueueFront(&q));
		QueuePop(&q);
	}

	QueueDestroy(&q);


	return 0;
}

 

  • 25
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值