【数据结构】栈和队列完全解析

文章目录

  • 一、什么是栈
  • 二、栈的实现
    • 1. 实现方式
    • 2. 接口介绍
    • 3. 接口实现
    • 4. 完整源码
      • stack.h
      • stack.c
  • 三、什么是队列
  • 四、队列的实现
    • 1. 实现方式
    • 2. 接口介绍
    • 3. 接口实现
    • 4. 完整源码
      • queue.h
      • queue.c

一、什么是栈

栈:
一种特殊的线性表,只允许在一端进行插入和删除
进行插入和删除的一端称为栈顶,另一端称为栈底
栈中的数据元素遵循后进先出的原则。
【数据结构】栈和队列完全解析_第1张图片

二、栈的实现

1. 实现方式

栈可以用数组或链表实现,相对而言用数组更好,因为数组尾删尾插更方便。

2. 接口介绍

//顺序结构实现栈

typedef int STDataType;

typedef struct Stack
{
	STDataType* a;
	int top;//top初始为0表示栈顶下一个,初始为-1表示栈顶
	int capacity;//容量
}ST;

//初始化栈
void STInit(ST* ps);
//销毁栈
void STDestroy(ST* ps);
//入栈
void STPush(ST* ps, STDataType x);
//出栈
void STPop(ST* ps);
//获取栈的数据个数
int STSize(ST* ps);
//栈的判空
bool STEmpty(ST* ps);
//获取栈顶元素
STDataType STTop(ST* ps);

3. 接口实现

//初始化栈
void STInit(ST* ps)
{
	assert(ps);//断言,保证传入指针不为空,方便后面解引用
	ps->a = (STDataType*)malloc(sizeof(STDataType) * 4);//开辟初始空间
	if (ps->a == NULL)//判断是否开辟成功
	{
		perror("malloc");//如果失败,显示报错信息
		return;
	}
	ps->capacity = 4;//初始化容量
	ps->top = 0;//初始化top,top表示栈顶下一个
}
//销毁栈
void STDestroy(ST* ps)
{
	assert(ps);//断言,保证传入指针不为空,方便后面解引用
	
	free(ps->a);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}
//入栈
void STPush(ST* ps, STDataType x)
{
	assert(ps);//断言,保证传入指针不为空,方便后面解引用
	if (ps->top == ps->capacity)//判断是否需要扩容
	{
		STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * ps->capacity * 2);//如果需要,扩容两倍
		if (tmp == NULL)//判断是否扩容成功
		{
			perror("realloc");//如果失败,显示报错信息
			return;
		}
		ps->a = tmp;//扩容成功,把tmp赋给a
		ps->capacity *= 2;//更新容量
	}
	ps->a[ps->top] = x;//尾插
	ps->top++;//top指向栈顶下一个
}
//出栈
void STPop(ST* ps)
{
	assert(ps);//断言,保证传入指针不为空,方便后面解引用
	assert(!STEmpty(ps));//保证栈不为空,才能删除

	ps->top--;//更新top
}
//获取栈的数据个数
int STSize(ST* ps)
{
	assert(ps);//断言,保证传入指针不为空,方便后面解引用

	return ps->top;//top就是栈的数据个数
}
//栈的判空
bool STEmpty(ST* ps)
{
	assert(ps);//断言,保证传入指针不为空,方便后面解引用

	return ps->top == 0;//如果top为0则返回true,否则返回false
}
//获取栈顶元素
STDataType STTop(ST* ps)
{
	assert(ps);//如果size为0则返回true,否则返回false
	assert(!STEmpty(ps));//保证栈不为空,才有栈顶元素

	return ps->a[ps->top - 1];//返回栈顶元素
}

4. 完整源码

stack.h

#pragma once
#include
#include
#include
#include

//顺序结构实现栈

typedef int STDataType;

typedef struct Stack
{
	STDataType* a;
	int top;//top初始为0表示栈顶下一个,初始为-1表示栈顶
	int capacity;//容量
}ST;

//初始化栈
void STInit(ST* ps);
//销毁栈
void STDestroy(ST* ps);
//入栈
void STPush(ST* ps, STDataType x);
//出栈
void STPop(ST* ps);
//获取栈的数据个数
int STSize(ST* ps);
//栈的判空
bool STEmpty(ST* ps);
//获取栈顶元素
STDataType STTop(ST* ps);

stack.c

#include"stack.h"

//初始化栈
void STInit(ST* ps)
{
	assert(ps);//断言,保证传入指针不为空,方便后面解引用
	ps->a = (STDataType*)malloc(sizeof(STDataType) * 4);//开辟初始空间
	if (ps->a == NULL)//判断是否开辟成功
	{
		perror("malloc");//如果失败,显示报错信息
		return;
	}
	ps->capacity = 4;//初始化容量
	ps->top = 0;//初始化top,top表示栈顶下一个
}

//销毁栈
void STDestroy(ST* ps)
{
	assert(ps);//断言,保证传入指针不为空,方便后面解引用
	
	free(ps->a);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}

//入栈
void STPush(ST* ps, STDataType x)
{
	assert(ps);//断言,保证传入指针不为空,方便后面解引用
	if (ps->top == ps->capacity)//判断是否需要扩容
	{
		STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * ps->capacity * 2);//如果需要,扩容两倍
		if (tmp == NULL)//判断是否扩容成功
		{
			perror("realloc");//如果失败,显示报错信息
			return;
		}
		ps->a = tmp;//扩容成功,把tmp赋给a
		ps->capacity *= 2;//更新容量
	}
	ps->a[ps->top] = x;//尾插
	ps->top++;//top指向栈顶下一个
}

//出栈
void STPop(ST* ps)
{
	assert(ps);//断言,保证传入指针不为空,方便后面解引用
	assert(!STEmpty(ps));//保证栈不为空,才能删除

	ps->top--;//更新top
}

//获取栈的数据个数
int STSize(ST* ps)
{
	assert(ps);//断言,保证传入指针不为空,方便后面解引用

	return ps->top;//top就是栈的数据个数
}

//栈的判空
bool STEmpty(ST* ps)
{
	assert(ps);//断言,保证传入指针不为空,方便后面解引用

	return ps->top == 0;//如果top为0则返回true,否则返回false
}

//获取栈顶元素
STDataType STTop(ST* ps)
{
	assert(ps);//如果size为0则返回true,否则返回false
	assert(!STEmpty(ps));//保证栈不为空,才有栈顶元素

	return ps->a[ps->top - 1];//返回栈顶元素
}

三、什么是队列

队列:
一种特殊的线性表,只允许在一端插入数据,另一端删除数据,尾插头删

【数据结构】栈和队列完全解析_第2张图片

四、队列的实现

1. 实现方式

队列可以用数组或链表实现,相对而言用链表更好,因为数组的头删要挪动数据,效率较低。

2. 接口介绍

//链式结构实现队列

typedef int QDataType;

//节点声明
typedef struct QueueNode//结构体类型声明,并没有创建结构体变量
{
	QDataType data;
	struct QueueNode* next;//单链表实现
}QNode;

//封装指针和size,方便传参,直接传一个结构体指针,不用传多个参数
typedef struct Queue
{
	QNode* head;//头指针,指向节点
	QNode* tail;   //尾指针,指向节点
	int size;           //数据个数
}Queue;

//初始化队列
void QueueInit(Queue* q);
//销毁队列
void QueueDestroy(Queue* q);
//入队列
void QueuePush(Queue* q, QDataType x);
//出队列
void QueuePop(Queue* q);
//获取头部元素
QDataType QueueFront(Queue* q);
//获取队尾元素
QDataType QueueBack(Queue* q);
//队列数据个数
int QueueSize(Queue* q);
//队列判空
bool QueueEmpty(Queue* q);

3. 接口实现

//初始化队列
void QueueInit(Queue* q)
{
	assert(q);//断言,防止传入指针为空,方便后面解引用
	q->head = q->tail = NULL;//初始化头指针和尾指针
	q->size = 0;//初始化数据个数
}
//销毁队列
void QueueDestroy(Queue* q)
{
	assert(q);//断言,防止传入指针为空,方便后面解引用
	QNode* cur = q->head;
	//遍历队列
	while (cur)
	{
		//逐个销毁
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	q->head = q->tail = NULL;//头尾指针置空
	q->size = 0;//数据个数清零
}
//入队列
void QueuePush(Queue* q, QDataType x)
{
	assert(q);//断言,防止传入指针为空,方便后面解引用

	QNode* newnode = (QNode*)malloc(sizeof(QNode));//动态申请新结点
	if (newnode == NULL)//判断是否申请成功
	{
		perror("malloc");//如果失败,显示报错信息
		return;
	}
	newnode->data = x;//初始化新结点数据
	newnode->next = NULL;//初始化新结点指针

	if (q->tail == NULL)//如果是空队列的情况
	{
		assert(q->head == NULL);//此时头尾指针必然都为空,否则出错
		q->head = q->tail = newnode;//头尾指针都指向新结点
	}
	else//不是空队列
	{
		q->tail->next = newnode;//尾插
		q->tail = newnode;//更新尾指针
	}
	q->size++;//更新数据个数
}
//出队列
void QueuePop(Queue* q)
{
	assert(q && q->head);
	//断言,防止传入指针为空,方便后面解引用;
	//保证队列不为空,才能删除

	//头删
	QNode* first = q->head;
	q->head = first->next;
	free(first);
	q->size--;//更新数据个数

	if (q->head == NULL)//如果头删后队列为空
	{
		q->tail = NULL;//应该更新尾指针,防止野指针的情况
	}
}
//获取头部元素
QDataType QueueFront(Queue* q)
{
	assert(q);//断言,防止传入指针为空,方便后面解引用
	assert(!QueueEmpty(q));//保证队列不为空,才有头部元素

	return q->head->data;
}
//获取队尾元素
QDataType QueueBack(Queue* q)
{
	assert(q);//断言,防止传入指针为空,方便后面解引用
	assert(!QueueEmpty(q));//保证队列不为空,才有尾部元素

	return q->tail->data;
}
//队列数据个数
int QueueSize(Queue* q)
{
	assert(q);//断言,防止传入指针为空,方便后面解引用

	return q->size;
}
//队列判空
bool QueueEmpty(Queue* q)
{
	assert(q);//断言,防止传入指针为空,方便后面解引用

	return q->size == 0;//如果size为0则返回true,否则返回false
}

4. 完整源码

queue.h

#pragma once
#include
#include
#include
#include

//链式结构实现队列

typedef int QDataType;

//节点声明
typedef struct QueueNode//结构体类型声明,并没有创建结构体变量
{
	QDataType data;
	struct QueueNode* next;//单链表实现
}QNode;

//封装指针和size,方便传参,直接传一个结构体指针,不用传多个参数
typedef struct Queue
{
	QNode* head;//头指针,指向节点
	QNode* tail;   //尾指针,指向节点
	int size;           //数据个数
}Queue;

//初始化队列
void QueueInit(Queue* q);
//销毁队列
void QueueDestroy(Queue* q);
//入队列
void QueuePush(Queue* q, QDataType x);
//出队列
void QueuePop(Queue* q);
//获取头部元素
QDataType QueueFront(Queue* q);
//获取队尾元素
QDataType QueueBack(Queue* q);
//队列数据个数
int QueueSize(Queue* q);
//队列判空
bool QueueEmpty(Queue* q);

queue.c

#include"queue.h"

//初始化队列
void QueueInit(Queue* q)
{
	assert(q);//断言,防止传入指针为空,方便后面解引用
	q->head = q->tail = NULL;//初始化头指针和尾指针
	q->size = 0;//初始化数据个数
}

//销毁队列
void QueueDestroy(Queue* q)
{
	assert(q);//断言,防止传入指针为空,方便后面解引用
	QNode* cur = q->head;
	//遍历队列
	while (cur)
	{
		//逐个销毁
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	q->head = q->tail = NULL;//头尾指针置空
	q->size = 0;//数据个数清零
}

//入队列
void QueuePush(Queue* q, QDataType x)
{
	assert(q);//断言,防止传入指针为空,方便后面解引用

	QNode* newnode = (QNode*)malloc(sizeof(QNode));//动态申请新结点
	if (newnode == NULL)//判断是否申请成功
	{
		perror("malloc");//如果失败,显示报错信息
		return;
	}
	newnode->data = x;//初始化新结点数据
	newnode->next = NULL;//初始化新结点指针

	if (q->tail == NULL)//如果是空队列的情况
	{
		assert(q->head == NULL);//此时头尾指针必然都为空,否则出错
		q->head = q->tail = newnode;//头尾指针都指向新结点
	}
	else//不是空队列
	{
		q->tail->next = newnode;//尾插
		q->tail = newnode;//更新尾指针
	}
	q->size++;//更新数据个数
}

//出队列
void QueuePop(Queue* q)
{
	assert(q && q->head);
	//断言,防止传入指针为空,方便后面解引用;
	//保证队列不为空,才能删除

	//头删
	QNode* first = q->head;
	q->head = first->next;
	free(first);
	q->size--;//更新数据个数

	if (q->head == NULL)//如果头删后队列为空
	{
		q->tail = NULL;//应该更新尾指针,防止野指针的情况
	}
}

//获取头部元素
QDataType QueueFront(Queue* q)
{
	assert(q);//断言,防止传入指针为空,方便后面解引用
	assert(!QueueEmpty(q));//保证队列不为空,才有头部元素

	return q->head->data;
}

//获取队尾元素
QDataType QueueBack(Queue* q)
{
	assert(q);//断言,防止传入指针为空,方便后面解引用
	assert(!QueueEmpty(q));//保证队列不为空,才有尾部元素

	return q->tail->data;
}

//队列数据个数
int QueueSize(Queue* q)
{
	assert(q);//断言,防止传入指针为空,方便后面解引用

	return q->size;
}

//队列判空
bool QueueEmpty(Queue* q)
{
	assert(q);//断言,防止传入指针为空,方便后面解引用

	return q->size == 0;//如果size为0则返回true,否则返回false
}

你可能感兴趣的:(数据结构简明教程(C语言实现),数据结构,c语言)