栈和队列介绍及全部源码

11 篇文章 0 订阅
文章详细介绍了栈和队列这两种数据结构的定义、特点以及C语言的代码实现。栈是限定性线性表,遵循后进先出的原则,用动态数组实现;队列则允许在一端插入,在另一端删除,用链表实现。文章提供了完整的栈和队列的初始化、插入、删除等操作的C代码示例。
摘要由CSDN通过智能技术生成

栈的定义

栈是一种限定性线性表,是将线性表的插入和删除限制在只能在一端操作,我们通俗的叫为栈顶(Top),通常只允许在栈顶进行插入、删除。
表的另一端我们通俗的较为栈底(Bottom),一般栈底不做任何操作。
栈的插入操作我们一般形象的称为入栈和进栈,删除操作形象的叫为出栈和退栈。
栈的操作顺序为先进后出,后进先出,一般采用数组来存储栈是较为方便的。
在这里插入图片描述

1 所在的位置为栈底,5 所在的位置为栈顶,入栈顺序为 1、2、3、4、5;由于栈顶只允许插入和删除,所以 出栈顺序为 5、4、3、2、1。

在这里插入图片描述
当先让1、2入栈,在把栈出空,然后再让3、4、5入栈,然后再出空,则最后出栈的先后顺序为 2、1、5、4、3。

代码实现栈
1、实现一个动态数组

用数组实现一个栈,也叫顺序栈,也就是在内存中申请一块连续的空间,依次存放自栈底到栈顶的数据元素,栈底也就是数组为0的位置,栈顶就是数组大小减1的位置。

typedef int STDataType;
typedef struct Stack
{
	STDataType* a;//用于动态申请空间
	int top;//用于记录栈里的元素个数,也就是数组的下标
	int capacity;//记录数组允许的最大空间
}ST;
2、初始化栈
//初始化
void STInit(ST* ps)
{
	assert(ps);//如果这里没有按照形参的要求传参会直接报错结束
	ps->a = (STDataType*)malloc(sizeof(STDataType) * 4);//动态申请4个STDataType大小的空间
	if (ps->a == NULL)
	{
		perror("malloc err");
		return;//如果申请空间失败会直接结束程序,并且报错
	}

	ps->capacity = 4;//代码执行到这里说明空间申请成功,并且设置数组最大的空间为4
	ps->top = 0;//初始化数组下标为0
}
3、销毁动态栈
//栈销毁
void STDestroy(ST* ps)
{
	assert(ps);//如果这里没有按照形参的要求传参会直接报错结束
	free(ps->a);//因为数组a申请的是动态的,所以使用完后需要进行内存释放,否则会发生内存泄漏,后果比较严重
	ps->a = NULL;//释放空间后对a进行置空,防止野指针
	ps->top = 0;//数组下标和数组允许的最大空间都设置为0
	ps->capacity = 0;
}
4、栈的插入
//栈插入
void STPush(ST* ps, STDataType x)
{
	assert(ps);//如果这里没有按照形参的要求传参会直接报错结束
	if (ps->capacity == ps->top)
	{//插入之前先判断一个数组存储空间是否到达了极限,如果空间马上不足就是用realloc进行原地或异地扩容
		STDataType* new = (STDataType*)realloc(ps->a, sizeof(STDataType) * ps->capacity * 2);
		if (new == NULL)
		{
			perror("realloc err");
			return;//如果申请失败就结束程序,并输出我们的perror的错误语
		}
		ps->a = new;//进行地址赋值
		ps->capacity = ps->capacity * 2;//因为我们扩容了二倍,所以capacity最大允许存放的数据元素空间也得扩容二倍
	}
	ps->a[ps->top] = x;//插入元素数据
	ps->top++;//小标往后加一位
}
5、判断栈是否为空
//判断栈区是否为空
bool STEmpty(ST* ps)
{
	assert(ps);//如果这里没有按照形参的要求传参会直接报错结束
	return ps->top;//当栈区为空时,top为0,0为假,非0为真
}
6、栈的删除(从尾部删除)
//栈的删除
void STPop(ST* ps)
{
	assert(ps);//如果这里没有按照形参的要求传参会直接报错结束
	assert(STEmpty(ps));//如果栈为空就不会操作下面的程序

	ps->top--;//元素下标减一,实现删除
}
7、返回栈内现有多少元素
//栈里有多少元素
int STSize(ST* ps)
{
	assert(ps);//如果这里没有按照形参的要求传参会直接报错结束
	return ps->top;//返回元素下标也就是现有的数据元素个数
}
8、返回栈顶元素
//访问栈顶的元素
STDataType STTop(ST* ps)
{
	assert(ps);//如果这里没有按照形参的要求传参会直接报错结束
	assert(STEmpty(ps));//如果栈为空就不会操作下面的程序

	return ps->a[ps->top - 1];//因为每次插入数据后top都往后加了一位,所以在返回栈顶元素的时候需要减一
}

栈完整代码

头文件 Stack.h

#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>
typedef int STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;
	int capacity;
}ST;

//初始化
void STInit(ST* ps);

//栈销毁
void STDestroy(ST* ps);

//栈插入
void STPush(ST* ps, STDataType x);

//判断栈区是否为空
bool STEmpty(ST* ps);

//栈的删除
void STPop(ST* ps);

//栈里有多少元素
int STSize(ST* ps);

//访问栈顶的元素
STDataType STTop(ST* ps);

源文件 Stack.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "Stack.h"

//初始化
void STInit(ST* ps)
{
	assert(ps);
	ps->a = (STDataType*)malloc(sizeof(STDataType) * 4);
	if (ps->a == NULL)
	{
		perror("malloc err");
		return;
	}

	ps->capacity = 4;
	ps->top = 0;
}

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

//栈插入
void STPush(ST* ps, STDataType x)
{
	assert(ps);
	if (ps->capacity == ps->top)
	{
		STDataType* new = (STDataType*)realloc(ps->a, sizeof(STDataType) * ps->capacity * 2);
		if (new == NULL)
		{
			perror("realloc err");
			return;
		}
		ps->a = new;
		ps->capacity = ps->capacity * 2;
	}
	ps->a[ps->top] = x;
	ps->top++;
}

//判断栈区是否为空
bool STEmpty(ST* ps)
{
	assert(ps);
	return ps->top;
}

//栈的删除
void STPop(ST* ps)
{
	assert(ps);
	assert(STEmpty(ps));

	ps->top--;

}

//栈里有多少元素
int STSize(ST* ps)
{
	assert(ps);

	return ps->top;
}

//访问栈顶的元素
STDataType STTop(ST* ps)
{
	assert(ps);
	assert(STEmpty(ps));

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

源文件(用于测试的文件) test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "Stack.h"

void test()
{
	ST st;
	STInit(&st);
	STPush(&st,1);
	STPush(&st, 2);
	printf("%d ", STTop(&st));
	STPop(&st);
	STPush(&st, 3);
	STPush(&st, 4);
	printf("%d ", STTop(&st));
	STPop(&st);
	STPush(&st, 5);

	while (STEmpty(&st))
	{
		printf("%d ", STTop(&st));
		STPop(&st);
	}
	STDestroy(&st);
}

int main()
{
	test();
	return 0;
}

队列

队列的定义

队列是只允许在一端进行插入操作,而在另一端进行删除输出操作的线性表。只允许插入的一端叫做队尾,只允许删除输出的一端叫做队头。

在这里插入图片描述
队的特点是先进先出,而栈是先进后出
由于队是先进先出,队头和队尾都会有操作,所以用数组来实现队列是不合实际的,我们在这里使用链表来完成,一个记录队头,一个记录队尾

代码实现栈
1、定义一个单链表和能记录队头和队尾的结构体
typedef int QDatatype;
typedef struct QueueNode
{
	struct QueueNode* next;
	QDatatype data;
}QNode;
typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;
}Queue;

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

2、队列初始化
//初始化队列
void QueueInit(Queue* pq)
{
	assert(pq);//如果这里没有按照形参的要求传参会直接报错结束
	pq->head = pq->tail = NULL;//将head和tail的初始指认状态都设置为空
	pq->size = 0;//size代表目前的数据元素个数,
}
3、队列销毁
//销毁队列
void QueueDestroy(Queue* pq)
{
	assert(pq);//如果这里没有按照形参的要求传参会直接报错结束
	QNode* cur = pq->head;//用于记录头的位置
	while (cur)
	{
		QNode* next = cur->next;//保存头的下一个位置
		free(cur);//因为刚开始就把head的位置给了cur,所以这里只free   cur就好了
		cur = next;//对cur重新赋值
	}
	pq->head = pq->tail = NULL;//设置为空,防止野指针
	pq->size = 0;//数据个数设置为空
}
4、队列插入数据
//队列插入数据
void QueuePush(Queue* pq,QDatatype x)
{
	QNode* newnode = (QNode*)malloc(sizeof(QNode));//malloc一个结点,用于链接队尾
	if (newnode == NULL)
	{
		perror("Push malloc err");//如果申请失败,打印perror提示
	}
	else
	{
		newnode->data = x;//申请空间成功,将数据赋值进去
		newnode->next = NULL;//这里必须要把next设置为空
	}
	if (pq->head == NULL && pq->tail == NULL)
	{
		//如果头和尾都指向空,说明现在的队列还是空的,所以直接赋值给头和尾就行
		pq->head = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;//程序走到这里说明队列不为空,再队尾插入数据就行
		pq->tail = pq->tail->next;//更新队尾的指向
	}
	pq->size++;//每插入一个数据就让数据的元素个数加一个
}
5、出队操作
//队列删除
void QueuePop(Queue* pq)
{
	assert(pq);//如果这里没有按照形参的要求传参会直接报错结束
	assert(pq->head!=NULL);//如果head为空说明数据元素为0,不可以再删除,所以这里直接断言结束程序
	/*if (pq->head->next == NULL)
	{
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
	else
	{
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}*/

	QNode* next = pq->head->next;//记录队头的下一个位置
	free(pq->head);//释放删除队头
	pq->head = next;//队头重新赋值

	if (pq->head == NULL)//如果head为空证明队列已经出空,并把tail也设置为空
		pq->tail = NULL;
	pq->size--;//出一个数据,数据元素个数减一个
}
6、返回目前队列的大小
//返回队列现在的大小
int QueueSize(Queue* pq)
{
	assert(pq);//如果这里没有按照形参的要求传参会直接报错结束
	//这里不需要判断队列是否为空,因为当队列为空时元素个数尾0
	return pq->size;//返回队列数据元素个数
}
7、返回队列是否为空(空位假)
//队列是否为空
bool QueueEmpty(Queue* pq)
{
	assert(pq);//如果这里没有按照形参的要求传参会直接报错结束

	return pq->size;//0为假,非0为真
}
8、返回队列的队头元素
//返回队列的第一个元素
QDatatype QueueFront(Queue* pq)
{
	assert(pq);//如果这里没有按照形参的要求传参会直接报错结束
	assert(QueueEmpty(pq));//如果队列为空就不会操作下面的程序

	return pq->head->data;//返回队头指向的数据元素
}

9、返回队尾元素
//返回队列的最后一个元素
QDatatype QueueBack(Queue* pq)
{
	assert(pq);//如果这里没有按照形参的要求传参会直接报错结束
	assert(QueueEmpty(pq));//如果队列为空就不会操作下面的程序

	return pq->tail->data;//返回队尾指向的数据元素
}

队列完整代码

头文件 Queue.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int QDatatype;
typedef struct QueueNode
{
	struct QueueNode* next;
	QDatatype data;
}QNode;
typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;
}Queue;

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

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

//队列输入数据
void QueuePush(Queue* pq,QDatatype x);

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

//返回队列现在的大小
int QueueSize(Queue* pq);

//队列是否为空
bool QueueEmpty(Queue* pq);

//返回队列的第一个元素
QDatatype QueueFront(Queue* pq);

//返回队列的最后一个元素
QDatatype QueueBack(Queue* pq);

源文件 Queue.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "Queue.h"

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

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

//队列插入数据
void QueuePush(Queue* pq,QDatatype x)
{
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("Push malloc err");
	}
	else
	{
		newnode->data = x;
		newnode->next = NULL;
	}
	if (pq->head == NULL && pq->tail == NULL)
	{
		pq->head = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = pq->tail->next;
	}
	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
	{
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}*/

	QNode* next = pq->head->next;
	free(pq->head);
	pq->head = next;

	if (pq->head == NULL)
		pq->tail = NULL;
	pq->size--;
}

//返回队列现在的大小
int QueueSize(Queue* pq)
{
	assert(pq);

	return pq->size;
}

//队列是否为空
bool QueueEmpty(Queue* pq)
{
	assert(pq);

	return pq->size;
}

//返回队列的第一个元素
QDatatype QueueFront(Queue* pq)
{
	assert(pq);
	assert(QueueEmpty(pq));

	return pq->head->data;
}

//返回队列的最后一个元素
QDatatype QueueBack(Queue* pq)
{
	assert(pq);
	assert(QueueEmpty(pq));

	return pq->tail->data;
}

源文件(用于测试) text.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "Queue.h"

void test1()
{
	Queue pq;
	//修改结构体只需要传结构体的地址
	QueueInit(&pq);
	QueuePush(&pq, 1);
	QueuePush(&pq, 2);
	QueuePush(&pq, 3);
	QueuePush(&pq, 4);
	QueuePush(&pq, 5);
	while (QueueEmpty(&pq))
	{
		printf("%d ", QueueFront(&pq));
		QueuePop(&pq);
	}
	//printf("\n%d", QueueSize(&pq));
}

int main()
{
	test1();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值