C和C++实现stack的对比

news2024/9/20 14:47:25

本篇文章,我们将对比C语言和C++实现栈的不同来体会C++的魅力!

1.栈的介绍

栈(Stack)是一种常见的数据结构,它是一种特殊的线性表,只允许在一端进行数据的插入和删除操作。这一端通常被称为栈顶(Top),而另一端则被称为栈底(Bottom)。栈的操作遵循后进先出(Last In First Out,简称LIFO)的原则,即最后进入栈的元素将会最先被移除。 

1.1基本特征

  • 后进先出:最后插入的元素最先被删除。
  • 单端操作:所有的插入和删除操作都在栈顶进行。
  • 动态大小:栈的大小可以根据需要动态调整,但在某些实现中,栈的大小可能是固定的。
     

1.2基本操作

  • 初始化(Initialize):创建一个空的栈。
  • 压栈(Push):在栈顶插入一个新的元素。
  • 出栈(Pop):从栈顶删除一个元素,并返回该元素。
  • 获取栈顶元素(Peek/Top):返回栈顶元素的值,但不删除该元素。
  • 判断栈是否为空(IsEmpty):检查栈是否为空。
  • 获取栈的大小(Size):返回栈中元素的数量。
  • 清空栈(Clear):移除栈中的所有元素。
  • 销毁栈(Destroy):释放栈所占用的内存资源

1.3实现方式

  • 数组实现:使用数组来存储栈中的元素,栈的大小在创建时确定,可能存在上溢问题。
  • 链表实现:使用链表来存储栈中的元素,链栈没有固定的大小限制,可以动态扩展。  

1.4应用场景

  • 函数调用:在程序中,函数调用的顺序通常使用栈来管理。
  • 表达式求值:在计算表达式时,使用栈来存储操作数和运算符。
  • 括号匹配:检查括号是否成对出现,常用于编译器的语法分析。
  • 逆波兰表达式转换:将中缀表达式转换为后缀表达式(逆波兰表达式)。 

栈是一种非常高效的数据结构,因为它只允许在一端进行操作,这使得插入和删除操作的时间复杂度都是O(1)。在许多编程语言中,栈已经作为内置的数据类型被实现,如C++中的stack,Java中的Stack类等。 

2.C语言实现栈

stack.c

#include<stdio.h>
#include<assert.h>
typedef int DataType;
typedef struct Stack
{
	DataType* array;
	int capacity;
	int size;
}Stack;

void StackInit(Stack* ps)
{
	assert(ps);
	ps->array = (DataType*)malloc(sizeof(DataType) * 3);
	if (NULL == ps->array)
	{
		assert(0);
		return;
	}
	ps->capacity = 3;
	ps->size = 0;
}

void StackDestroy(Stack* ps)
{
	assert(ps);
	if (ps->array)
	{
		free(ps->array);
		ps->array = NULL;
		ps->capacity = 0;
		ps->size = 0;
	}
}

void CheckCapacity(Stack* ps)
{
	if (ps->size == ps->capacity)
	{
		int newcapacity = ps->capacity * 2;
		DataType* temp = (DataType*)realloc(ps->array, newcapacity * sizeof(DataType));
		if (temp == NULL)
		{
			perror("realloc申请空间失败!!");
			return;
		}
		ps->array = temp;
		ps->capacity = newcapacity;
	}
}
void StackPush(Stack* ps, DataType data)
{
	assert(ps);
	CheckCapacity(ps);
	ps->array[ps->size] = data;
	ps->size++;
}

int StackEmpty(Stack* ps)
{
	assert(ps);
	return 0 == ps->size;
}

void StackPop(Stack* ps)
{
	if (StackEmpty(ps))
		return;
	ps->size--;
}

DataType StackTop(Stack* ps)
{
	assert(!StackEmpty(ps));
	return ps->array[ps->size - 1];
}

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

test.c

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

	StackPush(&s, 1);
	StackPush(&s, 2);
	StackPush(&s, 3);
	StackPush(&s, 4);
	printf("%d\n", StackTop(&s));
	printf("%d\n", StackSize(&s));

	StackPop(&s);
	StackPop(&s);
	printf("%d\n", StackTop(&s));
	printf("%d\n", StackSize(&s));

	StackDestroy(&s);
	return 0;
}

 从以上代码,我们可以看到,用C语言实现栈时,Stack相关操作函数有以下共性

  • 每个函数的第一个参数都是Stack*
  • 函数中必须要对第一个参数检测,因为该参数可能是NULL
  • 函数中都是通过Stack*参数来操作栈的
  • 调用时必须传递Stack结构体变量的地址

 结构体中只能定义存放数据的结构,操作数据的方法不能放在结构体里,即数据和操作数据的方式是分离开的。

3.C++实现栈(手搓版ovo) 

stack.cpp

typedef int DataType;
class Stack
{
public:
	void Init()
	{
		_array = (DataType*)malloc(sizeof(DataType*) * 3);
		if (NULL == _array)
		{
			perror("malloc申请空间失败");
			return;
		}
		_capacity = 3;
		_size = 0;
	}

	void Push(DataType data)
	{
		CheckCapacity();
		_array[_size] = data;
		_size++;
	}

	void Pop()
	{
		if (Empty())
			return;
		_size--;
	}

	DataType Top() { return _array[_size - 1]; }
	int Empty() { return 0 == _size; }
	int Size() { return _size; }

	void Destroy()
	{
		if (_array)
		{
			free(_array);
			_array = NULL;
			_capacity = 0;
			_size = 0;
		}
	}
private:
	void CheckCapacity()
	{
		if (_size == _capacity)
		{
			int newcapacity = _capacity * 2;
			DataType* temp = (DataType&)realloc(_array, newcapacity * sizeof(DataType));
			if (temp == NULL)
			{
				perror("realloc申请空间失败");
				return;
			}
			_array = temp;
			_capacity = newcapacity;
		}
	}
private:
	DataType* _array;
	int _capacity;
	int _size;
};

test.cpp

int main()
{
	Stack s;
	s.Init();
	s.Push(1);
	s.Push(2);
	s.Push(3);
	s.Push(4);

	printf("%d\n", s.Top());
	printf("%d\n", s.Size());

	s.Destroy();
	return 0;
}

 C++通过类可以将数据以及操作数据的方法进行完美结合,通过访问权限可以控制那些方法在类外被调用,即封装,在使用时就像使用自己的成员一样,更符合人类对一件事情的认知。

而且每个方法不需要传递Stack*的参数了,编译器编译之后该参数会自动还原。即C++中Stack*参数是编译器维护的,C语言需要自己维护。

总之,从C语言到C++实现Stack类的转变,可以明显体会到C++在面向对象编程、封装、代码复用、异常处理等方面的优势。这些特性使得C++更适合于开发大型、复杂的应用程序 。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1858438.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

移位操作符

目录 移位 >> --- 右移操作符 右移操作符代码的使用 代码验证 算术右移和逻辑右移 验证Visual Studio使用的是算术右移还是逻辑右移 逻辑右移 or 算术右移的代码验证 右移操作符对正整数有除2的效果&#xff08;除2是整数除法的除2&#xff09; 验证 << -…

Day3:203 移除链表元素 707设计链表 206反转链表

题目&#xff1a;206. 反转链表 - 力扣&#xff08;LeetCode&#xff09; /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* …

[数据集][目标检测]棉花检测数据集VOC+YOLO格式389张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;389 标注数量(xml文件个数)&#xff1a;389 标注数量(txt文件个数)&#xff1a;389 标注类别…

Excel如果将一个表格拆分为多个表格,文末另赠彩蛋!

前期分享如何用数据透视表将一个表格拆分成多个工作薄Excel一个表格拆分多个表格&#xff0c;你学会了吗&#xff1f; 今天刘小生分享另外一种&#xff0c;如果拆分成多个工作表格文件&#xff01; 如何将一个表格根据部门进行拆分成多个表格&#xff0c;再点对点发送给各部门…

浅析Vite本地构建原理

前言 随着Vue3的逐渐普及以及Vite的逐渐成熟&#xff0c;我们有必要来了解一下关于vite的本地构建原理。 对于webpack打包的核心流程是通过分析JS文件中引用关系&#xff0c;通过递归得到整个项目的依赖关系&#xff0c;并且对于非JS类型的资源&#xff0c;通过调用对应的loade…

宝宝早教电子图书 酷得电子方案

宝宝早教发声书是一种专为婴幼儿设计的图书&#xff0c;旨在通过有趣的图画和声音来吸引宝宝的注意力&#xff0c;帮助他们学习语言、认知和发展各种技能。这类书籍通常包括以下特点&#xff1a; 鲜艳的图画&#xff1a;发声书通常配有色彩鲜艳、形象生动的图画&#xff0c;以…

什么美业系统好用?美业门店收银系统源码分享、小程序展示

专业美业系统与普通系统相比&#xff0c;更加贴合美业门店的经营需求&#xff0c;提供了更全面、便捷、高效的管理功能&#xff0c;有助于提升门店的服务质量和经营效益。 博弈美业系统包括PC、iPad、手机、小程序四大端口&#xff0c;满足不同人群的各种需求。客户可从小程序…

使用Leaflet和瓦片地图实现离线地图的技术指南

引言 在现代的Web应用中&#xff0c;地图服务扮演着越来越重要的角色。然而&#xff0c;在一些特殊环境下&#xff0c;如偏远地区或网络环境不稳定的情况下&#xff0c;依赖在线地图服务可能会受到限制。因此&#xff0c;实现离线地图功能成为了一个重要的需求。本文将介绍如何…

Jenkins定时构建自动化(四):Python 的 argparse 模块

目录 一、主要功能和用途 二、核心类和方法 三、总结 四、argparse模块示例 Jenkins定时构建自动化(一)&#xff1a;Jenkins下载安装配置-CSDN博客 Jenkins定时构建自动化(二)&#xff1a;Jenkins的定时构建-CSDN博客 Jenkins定时构建自动化(三)&#xff1a;手动定时构建…

【服务器08】之【游戏框架】之【加载主角】

首先简单了解一下帧率 FixedUpdate( ) > Update( ) > LateUpdate( ) 首先FixedUpdate的设置值 默认一秒运行50次 虽然默认是0.02秒&#xff0c;但FiexedUpdate并不是真的0.02秒调用一次&#xff0c;因为在脚本的生命周期内&#xff0c;FixedUpdate有一个小循环&…

嵌入式开发板屏幕显示汉字

一、实验目的 1&#xff0e;编写能够在嵌入式开发板LCD上显示汉字的程序&#xff1b; 2&#xff0e;在Ubuntu系统中编译上述程序生成可执行文件&#xff1b; 3&#xff0e;到开发板中验证。 二、实验步骤 1. Ubuntu系统上编写验证程序 Ubuntu系统上编写的验证程序如下&…

【亲测好用】神级PSAI插件大揭秘:三款创成式修图神器,让你解放双手

PsBeta被停用后&#xff0c;小编一直想找到能够平替PsBeta创成式填充功能的插件。 功夫不负有心&#xff0c;终于被我找到啦&#xff0c;现在就给大家揭秘这三款宝藏修图神器&#xff0c;希望能够帮到大家。 1.插件名称&#xff1a;Starai 无需科学上网&#xff0c;还自带提示…

文库小程序搭建部署:实现资源共享正向反馈

文档库相信大家应该不陌生&#xff0c;日常我们的工作模板、会议模板、求职时的简历模板、教育界的教学模板等来源方式都出自于文档库&#xff0c;随着互联网的发展和工作需求&#xff0c;文档模板开启了新型的知识变现新途径&#xff0c;通过文库小程序&#xff0c;我们不仅能…

RS-485和RS-422通信的3.3V低功耗收发器MAX3483

描述 多数公司的MAX3483速率为&#xff1a;250kbps&#xff1b; Analog Devices公司的MAX3483速率为10Mbps。 国产MAX3485外观和丝印 该MAX3483ESA为15kV ESD保护、3.3V、低功耗收发器&#xff0c;用于RS-485和RS-422通信。 每个设备包含一个驱动器和一个接收器。 该MAX3483E…

0624_ARM1

思维导图&#xff1a;

10分钟安装好torch的GPU版本(Windows)

pytorch-gpu 1. 确定cuda版本2. 确定Python版本3 开始下载-cu118-cp383.1 下载cuda3.2 下载torchvision 4.下载好了5.开始安装6. 开始验证 1. 确定cuda版本 nvcc -V 版本为11.8 , 一会下载的版本为cu118 2. 确定Python版本 确定python版本为为3.8&#xff0c;一会下载为cp38 3 …

Web自动化介绍以及8种元素定位方式

自动化理论 回归测试&#xff1a; 在进行软件升级、修改或修复bug后&#xff0c;对系统进行回归测试&#xff0c;以确保修改过的部分没有引入新的问题或破坏其他功能。回归测试通常是自动化执行的&#xff0c;并且可以通过比较测试前后的结果来确定系统的稳定性。 压力测试&am…

Android Studio 编译无错误 运行无结果一例

好长时间没写Android 代码了&#xff0c;基本规则也忘了。终于在编译成功了&#xff0c;然而运行毫无结果&#xff0c;debug跟踪断点也没有触发。屏幕赫然写着&#xff0c;execute successfully! 。 进行了各种检查&#xff0c;毫无进展。最后&#xff0c;试着重启一下AS&#…

APP启动流程

文章目录 主要构成详细启动流程参考链接 主要构成 App的启动流程主要涉及几个关键步骤和组件的交互&#xff0c;包括Launcher进程、ActivityManagerService&#xff08;AMS&#xff09;、Zygote进程、以及App进程本身。以下是详细的启动流程&#xff1a; 用户操作&#xff1a;…

【代码随想录】【算法训练营】【第49天】 [300]最长递增子序列 [674]最长连续递增序列 [718]最长重复子数组

前言 思路及算法思维&#xff0c;指路 代码随想录。 题目来自 LeetCode。 day 49&#xff0c;周二&#xff0c;坚持不了一点~ 题目详情 [300] 最长递增子序列 题目描述 300 最长递增子序列 解题思路 前提&#xff1a; 思路&#xff1a; 重点&#xff1a; 代码实现 C…