IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【数据结构】栈与队列 -> 正文阅读

[数据结构与算法]【数据结构】栈与队列

概念及结构

一种特殊的线性表,只能在固定的一端进行插入和删除操作,进行插入和删除的一端称为栈顶,另一端称为栈底。
数据元素遵循:后进先出,LIFO(Last in first out);
压栈(入栈):插入数据的过程
出栈:删除栈顶元素的过程。
在这里插入图片描述

栈的实现

结构的选择

栈可以使用顺序表或者链表来实现,考虑到栈的操作来说,顺序表的结构实现更优一些。因为在数组末尾插入数据代价较小。
因此:选用顺序表来实现栈这一数据结构

分类

静态栈结构

实际上这种结构并不实用,所以不推荐使用。

typedef int STDataType;
#define N 10
typedef struct Stack
{
 STDataType a[N];//数组大小提前给定了
 int top; // 栈顶
}Stack;

动态的栈结构

动态增长的栈,相对比较实用,用户可以根据情况确定使用栈的空间大小。

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

动态增长的栈相关操作实现

1.栈的基本结构定义

#define DEFAULT 3
// 支持动态增长的栈
typedef int STDataType;

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

2.初始化栈

对于栈的初始化,我们只需要为其开辟空间(使用malloc从堆上申请),然后将栈顶top置为0,也就是处于数组的第一个空间位置处。

void StackInit(Stack* ps)
{
	ps->arr = (STDataType*)malloc(sizeof(STDataType)* DEFAULT);
	if (NULL == ps->arr)
	{
		assert(0);
		return;
	}
	ps->capacity = DEFAULT;
	ps->top = 0;
}

3.栈的销毁

由于初始化时数组的空间是从堆上开辟的,所以在使用完毕之后需要释放申请的内存空间,否则会发生内存泄漏。

// 销毁栈 
void StackDestroy(Stack* ps)
{
	assert(ps);
	if (ps->arr)
	{
		free(ps->arr);
		ps->arr = NULL;
		ps->capacity = 0;
		ps->top = 0;
	}
}

判断栈是否为空

只需要判断top的值是否为0,若为0,则栈空,否则不空~

// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
int StackEmpty(Stack* ps)
{
	assert(ps);
	return 0 == ps->top;
}

入栈操作

数据入栈,只需要将数据插入到top所在的位置,然后将top加1。

但是:会不会出现无法插入的情况???
会的,如果栈空间满了,就无法开辟进行入栈操作

怎么办??当然是扩容之后再入栈了~~

如何扩容呢?
有以下几步构成:
1、重新开辟空间
2、将旧空间的元素copy到新空间
3、释放旧空间
4、使用新空间
具体操作见代码
扩容

static void CheckCapicity(Stack* ps)
{
	if (ps->top == ps->capacity)
	{
		//1.申请新空间
		int newCapicity = ps->capacity * 2;
		STDataType* newArr = (STDataType*)malloc(sizeof(STDataType)*newCapicity);
		if (NULL == newArr)
		{
			assert(0);
			return;
		}
		//2.拷贝元素
		memcpy(newArr, ps->arr, sizeof(STDataType)*ps->top);
		//3.释放旧空间
		free(ps->arr);

		//4.使用新空间
		ps->arr = newArr;
		ps->capacity = newCapicity;
	}
}

入栈

// 入栈 
void StackPush(Stack* ps, STDataType data)
{
	assert(ps);
	CheckCapicity(ps);

	ps->arr[ps->top] = data;
	ps->top++;
}

出栈

出栈就不需要考虑那么多了,只需要判断一下栈是否为空,若不空,让top–就可以实现出栈操作。(top–后尽管要出栈元素依然存在,但是已经无法访问到)

// 出栈 
void StackPop(Stack* ps)
{
	assert(ps);

	if (!StackEmpty(ps))
	{
		ps->top--;
	}
}

获取栈顶元素

1、判断栈是否为空
2、若不空,去array[top-1]处的元素即为栈顶元素
注意:取栈顶元素与出栈不同,不需要改变top自身的值

// 获取栈顶元素 
STDataType StackTop(Stack* ps)
{

	assert(!StackEmpty(ps));

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

获取栈中元素个数

top:既表示栈顶,也表示有效元素的个数

// 获取栈中有效元素个数 
int StackSize(Stack* ps)
{
	assert(ps);
	return ps->top;
}

测试代码

void testStack()
{
	Stack s;
	StackInit(&s);

	StackPush(&s, 1);
	StackPush(&s, 2);
	StackPush(&s, 3);
	StackPush(&s, 4);
	StackPush(&s, 5);
	int num = StackTop(&s);
	int size = StackSize(&s);
	printf("%d %d\n",num,size);

	StackPop(&s);
	StackPop(&s);
	StackPop(&s);
	int num1 = StackTop(&s);
	int size1 = StackSize(&s);
	printf("%d %d\n", num1, size1);

	StackDestroy(&s);
}

输出结果:
在这里插入图片描述

队列

概念及结构

只允许在一端进行数据插入操作,另一端进行数据删除操作的线性结构。
队头:进行数据删除的一端
队尾:进行数据插入的一端
队列特点:先进先出在这里插入图片描述

队列的实现

结构的选择

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

因此,选用链表来实现队列

相关操作的实现

数据结构的定义

typedef int QDataType;

// 链式结构:表示队列 
typedef struct QListNode
{
	struct QListNode* next;
	QDataType data;
}QNode;

// 队列的结构 
typedef struct Queue
{
	QNode* front;
	QNode* rear;
	int size;//队列里有效元素个数
}Queue;

队列的初始化

刚开始,队列没有元素,只需要申请一个空队列,即front和rear都置为NULL,size置为0

//申请一个节点
QNode* buyQNode(QDataType data)
{
	QNode* Node = (QNode*)malloc(sizeof(QNode));
	if (NULL == Node)
	{
		assert(0);
		return NULL;
	}
	Node->data = data;
	Node->next = NULL;
	return Node;
}
// 初始化队列 
void QueueInit(Queue* q)
{
	assert(q);
	q->front = q->rear = NULL;
	q->size = 0;
}

销毁队列

对于队列的销毁,我们只需要循环遍历整个队列,采用“单链表头删”的方式进行释放,直到将整个队列全部释放。

// 销毁队列 
void QueueDestroy(Queue* q)
{
	assert(q);
	QNode* delNode = q->front;
	while (q->front)
	{
		q->front = delNode->next;
		free(delNode);
		delNode = q->front;
	}
	q->rear = NULL;
	q->size = 0;
}

判断队列是否为空

// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q)
{
	assert(q);
	return NULL == q->front;
}

入队操作

1.队列为空
在这里插入图片描述
2.队列不空
在这里插入图片描述

// 队尾入队列 
void QueuePush(Queue* q, QDataType data)
{
	assert(q);
	QNode* newNode = buyQNode(data);
	//1.队列为空
	if (NULL ==	q->front)
	{
		q->front = newNode;
	}
	//2.队列不空
	else
	{
		q->rear->next = newNode;
	}
	q->rear = newNode;
	q->size++;
}

出队操作

如果队列不空,就可以执行出队列操作,否则直接返回
1.队列有多个结点
在这里插入图片描述
2.队列只有1个元素
在这里插入图片描述

// 队头出队列 
void QueuePop(Queue* q)
{
	if (QueueEmpty(q))
	{
		return;
	}
	else
	{
		QNode* delNode = q->front;
		q->front = delNode->next;
		free(delNode);
		if (q->front == NULL)
		{
			q->rear = NULL;
		}
		q->size--;
	}
}

获取队头元素

// 获取队列头部元素 
QDataType QueueFront(Queue* q)
{
	assert(!QueueEmpty(q));

	return q->front->data;
}

获取队尾元素

// 获取队列队尾元素 
QDataType QueueBack(Queue* q)
{
	assert(!QueueEmpty(q));

	return q->rear->data;
}

获取有效元素个数

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

	return q->size;
}

测试代码

void testQueue()
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, 1);
	QueuePush(&q, 2);
	QueuePush(&q, 3);
	QueuePush(&q, 4);
	QueuePush(&q, 5);
	printf("队头:%d 队尾:%d 有效元素个数:%d \n", QueueFront(&q), QueueBack(&q), QueueSize(&q));

	QueuePop(&q);
	QueuePop(&q);
	QueuePop(&q);
	QueuePop(&q);
	printf("队头:%d 队尾:%d 有效元素个数:%d \n", QueueFront(&q), QueueBack(&q), QueueSize(&q));
	QueueDestroy(&q);
}

在这里插入图片描述

以上就是对栈和队列基础操作的分享,各位看官们请留下你们的足迹~~

获取原码:

栈-我的Git
队列-我的Git

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-12-02 17:01:12  更:2021-12-02 17:01:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 14:35:20-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码