数据结构之栈的实现

!!‧✧̣̥̇‧✦‧✧̣̥̇‧✦ ‧✧̣̥̇:  Solitary-walk

      ⸝⋆   ━━━┓
     - 个性标签 - :来于“云”的“羽球人”。 Talk is cheap. Show me the code
┗━━━━━━━  ➴ ⷯ

本人座右铭 :   欲达高峰,必忍其痛;欲戴王冠,必承其重。

 


     希望在看完我的此篇博客后可以对你有帮助哟

   此外,希望各位大佬们在看完后,可以互赞互关一下,看到必回
  

 今日本up主将为大家share 一下如何实现栈的基本操作

一·栈的初始化


二·栈的销毁


三·进栈


四·判断栈空


五·取栈顶元素


六·出栈


数据结构之栈的实现_第1张图片

 这里姑且就以顺序栈为例

1.栈的特征就是先进后出

2.栈的构成:数据域,栈顶指针,栈的空间容量

3.注意栈顶指针只是用来指示位置的,并非真正的指针

1.初始化

因为我们采用的是顺序栈,所以这里就涉及到是用动态还是静态的数组

暂时选择动态的数组

初始状态栈空间容量是0

有个问题大家思考一下初始态我的top是为0还是为-1???,以及对应状态下所表示的逻辑意义

数据结构之栈的实现_第2张图片 

 其实对top 的初始值并没有强制性的规定只要是明白自己所写的top 的逻辑意义即可

这里就暂时以top = 0,来测试,一定要明白这一点,否则在自己进行敲代码的时候就会晕

 top = 0,表示当前top位置的下一个位置即为栈顶元素 的位置

 

void STInit(ST* pst)//栈的初始化
{
	assert(pst);//判断所传的结构体的指针是否为空
	pst->a = NULL;
	pst->capacity = pst->top = 0;// 注意这里top = 0,表示当前top位置的下一个位置即为栈顶元素 的位置
	//注意,以下所有接口函数都是基于top = 0 来执行的
}
2.销毁

 对于栈的销毁我们只需把数组所指向的 那一块空间进行free即可

free(pst->a);

void STDestroy(ST* pst)
{
	assert(pst);
	free(pst->a);//直接把这块空间free就行
	pst->a = NULL;
}
3进栈

草图如下:

数据结构之栈的实现_第3张图片

1. 注意:因为top =  0,表示 当前top位置的下一个位置即为栈顶元素 的位置,此时元素的个数为0,如第一个图

在进栈的时候到底是先移top这个指针还是插入我的数据,注意此时top = 0哟

因为我是把数据放在top所对应的位置,所以就是先插入数据后移动top

若是先移动top指针后进行插入数据那所对应的topd 初始值就不是0了,而是我的top = -1

2.在插入数据的时候我们需要先判断是否为空

3.因为初始化之后我的数组空间为0,这里就需要进行开辟空间

 数据结构之栈的实现_第4张图片

  

void STPush(ST* pst,STDataType x)//进栈
{
	assert(pst);
	//先判断栈是否为空
	//	STDataType tmp = (STDataType)realloc(pst->a, sizeof(newcapacity));//注意这样是错误的
	int newcapacity ;
	if (pst->top == pst->capacity)
	{
	    newcapacity = pst->capacity == 0 ? 4 : 2 * (pst->capacity);
	//	STDataType tmp = (STDataType)realloc(pst->a, sizeof(newcapacity));//注意这样是错误的
		STDataType* tmp= (STDataType*)realloc(pst->a, newcapacity*sizeof(pst->capacity));//sizeof()求大小的时候是以字节为单位进行的
		if (tmp == NULL)
	{
		perror("realloc faail\n");//为什么不用malloc 

		return;
	}
	//来到这,扩容成功,对我的空间以及空间容量进行更新
	pst->a = tmp;
	pst->capacity = newcapacity;

	}
	//进栈操作
	pst->a[pst->top] = x;
	pst->top++;//永远指向栈顶元素下一个位置
}

 这里面有许多小点,稍不注意就会跳进坑,比如空间的开辟

还有就是栈容量初始是0,我们需要定义一个新的newcapacity来反映此时栈的容量,否则在后面空间开辟的时候就会有问题

大家可能就会写成下面的代码,这是错误滴

 

STDataType* tmp= (STDataType*)realloc(pst->a, capacity*sizeof(pst->capacity));//sizeof()求大小的时候是以字节为单位进行的

 

4.判空

 对于判空操作,我们这里只需看top == 0即可

 

bool STEmpty(ST* pst)
{
	assert(pst);
	return pst->top == 0;//没必要用if else,直接一步到位
}
5.出栈

出栈我们这里永远都是从栈顶的这个位置进行出栈,切忌,不要让我的top指针进行移动啊(也就是说,不要改变我top的值

重要的事情说三遍:永远都是从栈顶的这个位置进行出栈,永远都是从栈顶的这个位置进行出栈永远都是从栈顶的这个位置进行出栈

STDataType STTop(ST* pst)//取栈顶元素
{
	assert(pst);
	/*assert(STEmpty(pst));*/// 断言是否为空,这样写是错的
	assert(!STEmpty(pst));//正常逻辑,STEmpty(pst)应该是不为空,STEmpty(pst)这个函数返回0,!STEmpty(pst)取反操作就是1
	return  pst->a[pst->top-1];//因为top = 0,所以在用的时候先减1,指向当前栈顶元素
	//return  pst->a[pst->top--];注意这样写是错误的
}

 

return  pst->a[pst->top--];注意这样写是错误的

对于我们这些刚刚开始学习栈的小伙伴们来说,可能就会这样写,比如说,我就是之一

如果我们这里写成top--的话就会改变我们top  的值,也就是说top的位置就会变

对于我的top-1并不会改变我的top的一个值,即不会改变top的位置


Stack.c完整代码如下:

 

#define _CRT_SECURE_NO_WARNINGS 1
#include"Stack.h"
void STInit(ST* pst)//栈的初始化
{
	assert(pst);//判断所传的结构体的指针是否为空
	pst->a = NULL;
	pst->capacity = pst->top = 0;// 注意这里top = 0,表示当前top位置的下一个位置即为栈顶元素 的位置
	//注意,以下所有接口函数都是基于top = 0 来执行的
}
void STDestroy(ST* pst)
{
	assert(pst);
	free(pst->a);//直接把这块空间free就行
	pst->a = NULL;
}
void STPop(ST* pst)//出栈
{
	assert(pst);
	//assert(pst->top != 0);//为空就不能删除,也可以换种写法
	assert(!STEmpty(pst));//正常逻辑,STEmpty(pst)应该是不为空,STEmpty(pst)这个函数返回0,!STEmpty(pst)取反操作就是1
	//top 永远指向栈顶元素的下一个位置
	pst->top--;//直接top-- 就行,没有必要free

}
void STPush(ST* pst,STDataType x)//进栈
{
	assert(pst);
	//先判断栈是否为空
	//	STDataType tmp = (STDataType)realloc(pst->a, sizeof(newcapacity));//注意这样是错误的
	int newcapacity ;
	if (pst->top == pst->capacity)
	{
	    newcapacity = pst->capacity == 0 ? 4 : 2 * (pst->capacity);
	//	STDataType tmp = (STDataType)realloc(pst->a, sizeof(newcapacity));//注意这样是错误的
		STDataType* tmp= (STDataType*)realloc(pst->a, newcapacity*sizeof(pst->capacity));//sizeof()求大小的时候是以字节为单位进行的
		if (tmp == NULL)
	{
		perror("realloc faail\n");//为什么不用malloc 

		return;
	}
	//来到这,扩容成功,对我的空间以及空间容量进行更新
	pst->a = tmp;
	pst->capacity = newcapacity;

	}
	//进栈操作
	pst->a[pst->top] = x;
	pst->top++;//永远指向栈顶元素下一个位置
}
bool STEmpty(ST* pst)
{
	assert(pst);
	return pst->top == 0;//没必要用if else,直接一步到位
}
STDataType STTop(ST* pst)//取栈顶元素
{
	assert(pst);
	/*assert(STEmpty(pst));*/// 断言是否为空,这样写是错的
	assert(!STEmpty(pst));//正常逻辑,STEmpty(pst)应该是不为空,STEmpty(pst)这个函数返回0,!STEmpty(pst)取反操作就是1
	return  pst->a[pst->top-1];//因为top = 0,所以在用的时候先减1,指向当前栈顶元素
	//return  pst->a[pst->top--];注意这样写是错误的
}

Stack.h完整代码如下:

#include
#include
//对顺序栈而言,有三部分,数据域,栈顶指针,栈的空间容量
typedef int STDataType;//类型重命名
typedef struct STStack
{
	STDataType* a;//数据域
	int top; // 栈顶指针
	int capacity;//栈的空间容量
}ST;

void STInit(ST* pst);//栈的初始化
void STDestroy(ST* pst);//销毁
void STPush(ST* pst,STDataType x);//进栈
bool STEmpty(ST* pst);//判断栈是否为空
STDataType STTop(ST* pst);//取栈顶元素
void STPop(ST* pst);//出栈
//void STPrint(ST* pst);// 打印栈中元素,一般不这样写,不符合实际应用场景,都是一边访问一边打印,多用循环

ok以上就是我要 为大家share的一些基本操作,要是觉得还不错的话,烦劳各位大佬点个赞,互关一下呗,以便彼此留个联系方式,哈哈哈。

你可能感兴趣的:(javascript,开发语言,ecmascript)