【数据结构与算法】栈(Stack)之 浅谈数组和链表实现栈各自的优缺点

文章目录

  • 1.栈介绍
  • 2. 哪种结构实现栈会更优?
  • 3.栈代码实现(C语言)

往期相关文章:

  1. 线性表之顺序表
  2. 线性表之链表

1.栈介绍

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

  1. 栈的插入操作(Push):称为压栈 或 入栈 或 进栈。
  2. 栈的删除操作(Pop):也叫出栈 或 弹栈。

在这里插入图片描述
  栈顶(top)也可以是最后一次进栈的数据位置,比如上图中,栈顶可以分别是100、200、300的位置,这取决于栈顶初始化成 0 还是 -1。如果栈顶最开始初始化为0,则栈顶是如上图所演示的位置,因为是先Push,然后再栈底top++;如果栈顶初始化为-1,则栈顶是最后一次进栈的数据下标位置,因为是先top++,然后再Push。

2. 哪种结构实现栈会更优?

  栈的实现一般可以使用数组或链表实现。对栈而言数组的结构实现更优一些,因为数组在尾上插入和删除数据的代价很小,时间复杂度均为O(1),且没有其它额外开销。下面具体分析两种结构实现栈的优缺点。

对于链表实现栈,问题很多。一是链表有八种,二是每种链表实现起来都存在缺点。下面简单分析下链表实现栈的问题:

  1. 先说单向链表实现栈,即便是多维护一个尾指针,对于栈的删除操作还是需要遍历,因为需要找到尾节点的上一个节点。

  2. 而对于双向链表,为了解决单向链表实现栈的删除操作问题,唯一可行的只有双向循环链表,不仅轻松地找到尾结点,同时还能找到上一个节点,确实能解决上面谈到的问题。不过这又有其它问题了,每个节点相比于单向链表都多维护了一个指针变量,有一定内存开销。

所以说实现栈的最优结构,还得是数组,且数组自身的特性也产生了几个优点。数组的存储是连续的,正是因为这个原因:

  1. 数组的寄存器命中率比链表高
  2. 寄存器命中后,不会产生寄存器空间污染

数组实现栈的话就没有任何缺点吗?答案是有的,前面也说过,栈是一种特殊的线性表。

  1. 空间给大了或每次扩容扩大了,然后又不使用,那空间就浪费了;4
  2. 空间给小了或者每次扩容扩小了,那插入数据时容量不够经常需要扩容(realloc),扩容本身也有一些消耗
  3. 最不能接受的是,如果后面的内存不足以扩容设定的大小,realloc扩容可能会异地扩容,内存碎片增多,异地扩容意思是跳过这段大小不够的内存空间,到另一片内存区域扩容,这也会导致跳过的那一段内存变成内存碎片,如果一直没有程序去使用,空间也浪费掉了!关于realloc扩容,可以看看我的这篇文章 指针与动态内存 2.3realloc部分。

不过上述数组的缺点,也是能控制的。比如数组初始化大小根据需求给一个折中,扩容方案也折中,比如按自身1.5倍扩,这样能控制扩容的频率不至于太频繁,异地扩容的几率也小一些!优点相比于缺点,利大于弊!最重要的是,比起链表的优缺点,也要好上许多!

3.栈代码实现(C语言)

stack.h

#pragma once

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

typedef int valuetype;

typedef struct {
	valuetype* arr;
	int top;
	int capacity;
} Stack;

void Init(Stack* stack);

void Push(Stack* stack, valuetype value);
void Pop(Stack* stack);

valuetype Top(Stack* stack);
int Size(Stack* stack);
bool Empty(Stack* stack);

void Destroy(Stack* stack);

stack.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "Stack.h"

void Init(Stack* stack) {
	assert(stack);
	stack->arr = NULL;
	stack->capacity = stack->top = 0;
}

void Push(Stack* stack, valuetype value) {
	assert(stack);
	if (stack->top == stack->capacity) {
		stack->capacity = stack->capacity == 0 ? 10 : (int)(stack->capacity * 1.5);
		stack->arr = (valuetype*)realloc(stack->arr, sizeof(valuetype) * stack->capacity);
		if (stack->arr == NULL) {
			perror("realloc failed in the function Push(Stack*, valuetype).");
			return;
		}
	}
	stack->arr[stack->top++] = value;
}

void Pop(Stack* stack) {
	assert(stack && stack->top > 0);
	stack->top--;
}

valuetype Top(Stack* stack) {
	assert(stack && stack->top > 0);
	return stack->arr[stack->top - 1];
}

int Size(Stack* stack) {
	assert(stack);
	return stack->top;
}

bool Empty(Stack* stack) {
	assert(stack);
	return stack->top == 0;
}

void Destroy(Stack* stack) {
	assert(stack);
	free(stack->arr);
	stack->arr = NULL;
	stack->capacity = stack->top = 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【项目日记(四)】第一层: 线程缓存的具体实现

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:项目日记-高并发内存池⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你做项目   &#x1f51d;&#x1f51d; 开发环境: Visual Studio 2022 项目日…

Unity中URP下获取每一个额外灯数据

文章目录 前言一、我们先来看一下 SimpleLit 中的调用二、获取额外灯索引1、非移动平台2、非GLES平台3、大多数平台 三、获取额外灯数据 前言 在上一篇文章中&#xff0c;我们知道了URP下是怎么获取额外灯数量的。 Unity中URP下获取额外灯数量 在这篇文章中&#xff0c;我们…

场内基金出货是什么意思?出货和洗盘有什么区别?

场内基金出货是股市中常见的一种操作策略&#xff0c;指股市中的投资大户或者机构大量或者批次买入某只股票&#xff0c;并散发利好该股票的消息&#xff0c;导致该股票在短时间内股价升高&#xff0c;从而吸引投资散户购买该股票。等到股价上升到一定的阶段时&#xff0c;庄家…

nextjs中beforePopState使用

在某些情况下&#xff0c;希望监听popstate并在路由器对其进行操作之前执行某些操作。可以使用beforePopState。 在Next.js中&#xff0c;beforePopState是一个可选的生命周期函数&#xff0c;用于在浏览器的历史记录发生更改之前执行一些操作。具体来说&#xff0c;beforePopS…

两千字讲明白java中instanceof关键字的使用!

写在开头 在过往的内容中&#xff0c;我们讲了不少的Java关键字&#xff0c;比如final、static、this、super等等&#xff0c;Java中的关键字非常之多&#xff0c;下图是整理的关键字集合 而我们今天要学习的就是其中的instanceof关键字&#xff01; instanceof的定义 instanc…

k8s安全机制

安全机制&#xff1a;k8s的安全机制&#xff0c;分布式集群管理工具&#xff0c;就是容器编排。 安全机制的核心&#xff1a;API SERVER作为整个集群内部通信的中介&#xff0c;也是外控控制的入口。所有的安全机制都是围绕api server来进行设计&#xff1a; 请求api资源&#…

数据结构·单链表

不可否认的是&#xff0c;前几节我们讲解的顺序表存在一下几点问题&#xff1a; 1. 中间、头部的插入和删除&#xff0c;需要移动一整串数据&#xff0c;时间复杂度O(N) 2. 增容需要申请新空间&#xff0c;拷贝数据&#xff0c;释放旧空间。会有不小的消耗 3. 增容一般是2倍的增…

MySQL安装及可视化工具SQLyog下载

编程如画&#xff0c;我是panda&#xff01; 最近学习Web开发的时候要用到数据库&#xff0c;一开始下载的ZIP版本的&#xff0c;还得修改配置文件&#xff0c;挺麻烦的&#xff0c;后来发现可以直接使用msi版的安装包疯狂next&#xff0c;所以就出一期教程。 前言 MySQL 是一…

链表--104. 二叉树的最大深度/medium 理解度A

104. 二叉树的最大深度 1、题目2、题目分析3、复杂度最优解代码示例4、适用场景 1、题目 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,n…

22款奔驰GLS450升级香氛负离子车载香薰功能

奔驰原厂香氛系统激活原车自带系统&#xff0c;将香气加藏储物盒中&#xff0c;通过系统调节与出风口相结合&#xff0c;再将香味传达至整个车厢&#xff0c;达到净化车厢空气的效果&#xff0c;让整个车厢更加绿色健康&#xff0c;清新淡雅。星骏汇小许Xjh15863 产品功能&…

Vue3+Vite使用Puppeteer进行SEO优化(SSR+Meta)

1. 背景 【笑小枫】https://www.xiaoxiaofeng.com上线啦 资源持续整合中&#xff0c;程序员必备网站&#xff0c;快点前往围观吧~ 我的个人博客【笑小枫】又一次版本大升级&#xff0c;虽然知道没有多少访问量&#xff0c;但我还是整天没事瞎折腾。因为一些功能在Halo上不太好实…

MES管理系统计划排产有哪些重要作用

在当今制造业中&#xff0c;MES管理系统解决方案已经成为提高生产效率、优化资源利用以及提升企业整体运营水平的关键工具。尤其是在生产计划排产这一核心环节&#xff0c;MES管理系统发挥着无可替代的作用。通过精准的计划和调度&#xff0c;MES管理系统帮助企业实现生产过程的…

SAP EXCEL上传如何实现指定读取某一个sheet页(ALSM_EXCEL_TO_INTERNAL_TABLE)

如何读取指定的EXCEL sheet 页签&#xff0c;比如要读取下图中第二个输出sheet页签 具体实现方法如下&#xff1a; 拷贝标准的函数ALSM_EXCEL_TO_INTERNAL_TABLE封装成一个自定义函数ZCALSM_EXCEL_TO_INTERNAL_TABLE 在自定义函数导入参数页签新增一个参数SHEET_NAME 在源代码…

【word密码】Word 文档设置了只读为什么还能编辑?

有些朋友可能会遇到这种疑问&#xff0c;为什么我的Word文档设置了只读模式&#xff0c;还是可以编辑的&#xff0c;这是什么原因呢&#xff1f; 其实是因为大部分的只读模式&#xff0c;设置完成之后都是可以编辑的&#xff0c;但是当我们进行保存的时候就会发现&#xff0c;…

【边缘计算】TA的基本概念,以及TA的挑战和机遇

大家好&#xff0c;我是全栈小5&#xff0c;欢迎阅读文章&#xff01; 此篇是【话题达人】序列文章&#xff0c;这一次的话题是《边缘计算的挑战和机遇》 文章将以博主的角度进行讲述&#xff0c;理解和水平有限&#xff0c;不足之处&#xff0c;望指正。 目录 背景基本概念挑战…

软件游戏提示msvcp140.dll丢失的解决方法,全面分析msvcp140.dll文件

msvcp140.dll是Microsoft Visual C 2015 Redistributable的一部分&#xff0c;它包含了许多用于运行程序的函数和类库。当这个文件丢失或损坏时&#xff0c;依赖于该组件的应用程序可能无法正常启动&#xff0c;系统会弹出错误提示&#xff0c;告知用户找不到msvcp140.dll文件。…

【Linux】糟糕,是心动的感觉——与Linux的初次相遇

初识Linux 导言一、计算机的发展1.1 历史背景1.2 计算机的发明 二、操作系统2.1 什么是操作系统&#xff1f;2.2 操作系统的诞生2.3 操作系统的发展2.3.1 批处理系统的发展2.3.2 分时系统2.3.3 实时系统2.3.4 通用操作系统 2.4 UNIX操作系统2.4.1 UNIX的诞生2.4.2 UNIX的发展 2…

ESXI 本地和虚拟机之间可以自由复制和粘贴

文章目录 ESXI 本地和虚拟机之间可以自由复制和粘贴 ESXI 本地和虚拟机之间可以自由复制和粘贴 web访问esxi&#xff0c;然后&#xff1a; 1、右击新建的虚拟机&#xff0c;确保是在关机状态下&#xff0c;点击编辑设置 2. 找到 虚拟机选项→高级→常规→配置参数 3、点击添加…

Scrapy爬虫在新闻数据提取中的应用

Scrapy是一个强大的爬虫框架&#xff0c;广泛用于从网站上提取结构化数据。下面这段代码是Scrapy爬虫的一个例子&#xff0c;用于从新闻网站上提取和分组新闻数据。 使用场景 在新闻分析和内容聚合的场景中&#xff0c;收集和组织新闻数据是常见需求。例如&#xff0c;如果我…

❤css实用

❤ css实用 渐变色边框&#xff08;Gradient borders方法的汇总 5种-代码可直接下载&#xff09; 资源链接 https://download.csdn.net/download/weixin_43615570/88779950?spm1001.2014.3001.5503 给 border 设置渐变色是很常见的效果&#xff0c;实现这个效果有很多思路 1…