当前位置: 首页 > article >正文

带你深入理解“栈”(c语言 c++和stl Stack三个版本的模拟实现)

目录

一.栈的概念及结构

二.栈的实现(c语言版)

2.1静态增长的栈

2.2动态增长的栈

2.3动态栈的模拟实现

   1.栈的初始化

  2.入栈

 3.出栈

4.获取栈顶元素

5.获取栈中有效数据个数

6.检查栈是否为空

7.栈的销毁

三.C++ 版本模拟实现栈

 1.C++版本的源代码

四.c语言版本的源代码

  4.1  头文件.h源码

  4.2 功能实现的.c文件

4.3测试代码test.c文件


一.栈的概念及结构

栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则

压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶

二.栈的实现(c语言版)

栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小

2.1静态增长的栈

下面是定长的静态栈的结构,栈的内存空间是固定的,当我们栈中的数据很少时,可能会浪费空间,而数据量很大的时候,栈有可能占不下大量的数据,所以,在实际中一般不实用。

typedef int STDataType;
#define N 10
typedef struct Stack
{
STDataType _a[N];
int _top; // 栈顶
}Stack;

2.2动态增长的栈

下面是动态增长的栈,初始化的时候可以先给_a一个固定的小值,如何根据用户输入的数据自我进行扩容

typedef int STDataType;

typedef struct Stack
{
STDataType* _a;
int _top; // 栈顶
int _capacity; // 容量
}Stack;

2.3动态栈的模拟实现

   1.栈的初始化

  在这里我对“栈”的容量给予5,然后用malloc去堆上创建5个int字节大小的空间付给我们的数组,因为malloc有可能申请失败,所以我们用if去进行判断。

  top栈顶初始化为0,代表没有数据。

void StackInit(Stack* ps)
{
    ps->capacity = 5;
    ps->a = (Stack*)malloc(ps->capacity * sizeof(STDataType));
    if (ps->a == NULL)
    {
        perror("malloc");
        exit(-1);
    }
    ps->top = 0;
}

  2.入栈

入栈,栈里面插入数据,相当于数组进行尾插

首先,进行判断,top栈顶等于capacity容量的时候,代表我们栈里的内存满了,这里我们需要扩容,用realloc对数组进行扩容,现在我进行的二倍扩容

判断完成后 进行插入数据,在数组栈顶插入传入的数据 data

void StackPush(Stack* ps, STDataType data)
{
	//扩容
	if (ps->top == ps->capacity)
	{
		Stack * da = (Stack*)realloc(  ps->a  ,ps->capacity * 2 * sizeof(STDataType));
		if (da == NULL)
		{
			perror("realloc");
			exit(-1);
		}
		else
		{
			ps->a = da;
		}
		ps->capacity *= 2;
	}

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

 3.出栈

出栈,直接栈顶元素减一就好了,以后插入的数据会直接替换原先的数据,而top--后自己也访问不到top以后的数据

void StackPop(Stack* ps)
{
	ps->top--;
}

4.获取栈顶元素

获取栈顶元素,因为数组下标是从0开始的,所以返回的是栈顶元素-1;

STDataType StackTop(Stack* ps)
{
	return ps->a[ps->top-1];
}

5.获取栈中有效数据个数

有效的数据个数就是 栈顶,直接返回栈顶就好了

int StackSize(Stack* ps)
{
	return ps->top;
}

6.检查栈是否为空

c语言并不支持bool,需要我们引用头文件#include<stdbool.h>

判断栈顶是否为0,来判断栈里是否有数据

有返回true

无返回false

bool StackEmpty(Stack* ps)
{
	if (ps->top == 0)
		return true;
	else
		return false;
}

7.栈的销毁

栈的销毁,对容量和栈顶进行请0,然后用free函数释放我们使用malloc/realloc在堆上开辟的空间

void StackDestroy(Stack* ps)
{
	ps->capacity = 0;
	ps->top = 0;
	free(ps->a);
	ps->a = NULL;	
}

以上就是c语言版本的栈的模拟实现

三.C++ 版本模拟实现栈

考虑到学校有好多老师上课,虽然说得是用c语言实现,却用cpp进行操作,现在给大家更新cpp版本的栈的模拟实现,cpp版本的扩容使用的new,函数参数使用的&,可能有同学对指针使用不太熟悉,所以我们同意用&(引用)来实现,方便大家的理解,就不再详细的进行说明了,思路跟c语言实现的一样,只是c和cpp的语言差距有所不同。

 1.C++版本的源代码

#include<iostream>
using namespace std;

// 支持动态增长的栈
typedef int STDataType;
typedef struct Stack1
{
	STDataType* a;
	int top;		// 栈顶
	int capacity;  // 容量 
}Stack;

// 初始化栈 
void StackInit(Stack& ps)
{
	ps.capacity = 5;
	ps.a = new STDataType[ps.capacity * sizeof(STDataType)];
	ps.top = 0;
}
// 入栈 
void StackPush(Stack& ps, STDataType data)
{
	//扩容
	if (ps.top == ps.capacity)
	{
		STDataType* da = new STDataType[ps.capacity * 2 * sizeof(STDataType)];
		ps.a = da;
		ps.capacity *= 2;
	}
	ps.a[ps.top] = data;
	ps.top++;
}
// 出栈 
void StackPop(Stack& ps)
{
	ps.top--;
}
// 获取栈顶元素 
STDataType StackTop(const Stack& ps)
{
	return ps.a[ps.top - 1];
}
// 获取栈中有效元素个数 
int StackSize(const Stack& ps)
{
	return ps.top;
}
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
bool StackEmpty( const Stack& ps)
{
	if (ps.top == 0)
		return true;
	else
		return false;
}
// 销毁栈 
void StackDestroy(Stack& ps)
{
	ps.capacity = 0;
	ps.top = 0;
	delete ps.a;
	ps.a = NULL;
}


int main()
{
	Stack s;
	StackInit(s);

	StackPush(s, 1);
	StackPush(s, 2);
	StackPush(s, 3);
	StackPush(s, 4);

	for (int i = 0;i < 4;i++)
	{
		cout << StackTop(s) << endl;
		StackPop(s);
	}

	printf("栈中有效元素个数为 %d \n", StackSize(s));
	if (StackEmpty(s))
	{
		printf("为空\n");
	}
	else
	{
		printf("不为空\n");
	}

	StackDestroy(s);
}

四.c语言版本的源代码

  4.1  头文件.h源码

	#include<stdio.h>
	#include<stdlib.h>
	#include<stdbool.h>

	// 支持动态增长的栈
	typedef int STDataType;
	typedef struct Stack
	{
		STDataType* a;
		int top;		// 栈顶
		int capacity;  // 容量 
	}Stack;

	// 初始化栈 
	void StackInit(Stack* ps);
	// 入栈 
	void StackPush(Stack* ps, STDataType data);
	// 出栈 
	void StackPop(Stack* ps);
	// 获取栈顶元素 
	STDataType StackTop(Stack* ps);
	// 获取栈中有效元素个数 
	int StackSize(Stack* ps);
	// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
	bool StackEmpty(Stack* ps);
	// 销毁栈 
	void StackDestroy(Stack* ps);

  4.2 功能实现的.c文件

#include"Stack.h"

// 初始化栈 
void StackInit(Stack* ps)
{
	assert(ps);
	ps->capacity = 5;
	ps->a = (Stack*)malloc(ps->capacity * sizeof(STDataType));
	if (ps->a == NULL)
	{
		perror("malloc");
		exit(-1);
	}
	ps->top = 0;
}
// 入栈 
void StackPush(Stack* ps, STDataType data)
{
	assert(ps);
	//扩容
	if (ps->top == ps->capacity)
	{
		Stack * da = (Stack*)realloc(  ps->a  ,ps->capacity * 2 * sizeof(STDataType));
		if (da == NULL)
		{
			perror("realloc");
			exit(-1);
		}
		else
		{
			ps->a = da;
		}
		ps->capacity *= 2;
	}

	ps->a[ps->top] = data;
	ps->top++;
}
// 出栈 
void StackPop(Stack* ps)
{
	assert(ps);
	assert(ps->top > 0);
	ps->top--;
}
// 获取栈顶元素 
STDataType StackTop(Stack* ps)
{
	assert(ps);
	return ps->a[ps->top-1];
}
// 获取栈中有效元素个数 
int StackSize(Stack* ps)
{
	return ps->top;
}
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
bool StackEmpty(Stack* ps)
{
	if (ps->top == 0)
		return true;
	else
		return false;
}
// 销毁栈 
void StackDestroy(Stack* ps)
{
	assert(ps);

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

4.3测试代码test.c文件

#include"Stack.h"

int main()
{
	Stack s;
	StackInit(&s);

	StackPush(&s, 1);
	StackPush(&s, 2);
	StackPush(&s, 3);
	StackPush(&s, 4);

	StackPop(&s);

	printf("栈顶元素为%d \n", StackTop(&s));
	printf("栈中有效元素个数为 %d \n", StackSize(&s));

	if (StackEmpty(&s))
	{
		printf("为空\n");
	}
	else
	{
		printf("不为空\n");
	}

	StackDestroy(&s);


}


http://www.kler.cn/a/105888.html

相关文章:

  • 【C/C++】Lambda 用法
  • 【时间之外】IT人求职和创业应知【37】-AIGC私有化
  • 七、箭头函数及简写、arguments、剩余参数、展开运算符、解构数组与对象、数组常见方法(forEach、map、join、reduce)
  • 【原创】如何备份和还原Ubuntu系统,非常详细!!
  • PlantUML——时序图
  • PHP代码审计 --MVC模型开发框架rce示例
  • 如何选择适合的美颜SDK?
  • ES 数据迁移最佳实践
  • hello react
  • 再获Gartner认可!持安科技获评ZTNA领域代表供应商
  • Instagram引流技巧:如何充分利用社交媒体来增加独立站流量
  • 【Overload游戏引擎细节分析】PBR材质Shader
  • 部署应用链太费心?Tanssi 教你轻松开发部署
  • 解锁高效检索技能:掌握MySQL索引数据结构的精髓
  • 阿里巴巴:海量请求下的接口并发,都有哪些方案?
  • 重复控制器的性能优化
  • [每周一更]-(第69期):特殊及面试的GIT问题解析
  • 华为云双十一服务器数据中心带宽全动态BGP和静态BGP区别
  • 港联证券:2万元股票一进一出手续费?
  • Uniapp 跳转回上一页面并刷新页面数据
  • jdbc技术实现插入数据,更新和删除操作,查询操作
  • 【计算机视觉】MoCo v3 讲解
  • 基于Java的宠物商店管理系统设计与实现(源码+lw+部署文档+讲解等)
  • 全国客运飞机场数据,2023年的,有shp和xlsx格式
  • jvm摘要
  • php实战案例记录(25)intval函数的用法