数据结构:栈的实现

news2024/11/25 20:47:56

1. 栈(Stack)

1.1 栈的概念

  • 栈(Stack)是只允许在一端进行插入或删除操作的线性表.首先栈是一种线性表,但限定这种线性表只能在某一端进行插入和删除操作.
  • 进行数据插入和删除操作的一端栈顶,另一端称为栈底.
  • 栈中的元素遵循后进先出LIFO(Last In First Out)的原则

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

1.2 栈的结构

在这里插入图片描述

栈的元素,遵循后进先出原则


栈采用什么逻辑结构呢?
通常栈可以用链表和数组实现.
当然我们调用的时候不需要知道,使用的是什么方法实现.

链表栈

通过在表前端插入来实现 push ,通过删除表前端元素实现 pop.
可以使用之前实现的单链表来实现栈,单链表实现详见.只用注意,栈只有插入删除操作,需要头删和头插.

虽然操作都是花费常数时间,但是对mallocfree的调用是十分昂贵的.

数组栈

更为流行的是使用数组来实现栈.虽然数组的大小需要提前说明或者临时开辟,但是,在典型的应用程序中,栈元素的实际个数一般不会太大,使用数组是更加高效的方法.


总结:

  • 推荐使用数组结构实现栈
  • 若使用链表实现栈
    用尾做栈顶,尾删尾插,要设计成双向链表
    用头做栈顶,头删头插,要设计成单链表

2. 栈的定义

一般来说,使用动态栈而非静态栈,需要扩容的时候,可以进行适当扩容,增加了程序的适用性.

动态栈实现的数据结构

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
int StackEmpty(Stack* ps);
// 销毁栈
void StackDestroy(Stack* ps);

3. 栈的实现

3.1 初始化栈 (StackInit)

// 初始化栈
void StackInit(Stack* ps)
{
  assert(ps);
  
  ps->a = NULL;     
  ps->top = 0;
  ps->capacity = 0;
}
  1. 和创建顺序表的操作是一致的,通过结构体指针ps修改主函数中的结构体的成员变量,将ps指向的数组指针指向NULL,同时将容量capacity和栈顶元素top置为 0.
  1. 注意,在这里,top所指向的是栈顶元素后一个空间,此时没有元素,自然就指向了数组的第一个空间

3.2 入栈 (StackPush)

//入栈
void StackPush(Stack* ps, STDataType data)
{
  assert(ps);       //确保ps合法

  //如果容量不够则扩容
  if (ps->capacity == ps->top)
  {
    int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;   //定义新的容量
    STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newCapacity);  //开辟新的空间
    if (tmp == NULL)
    {
      perror("malloc error");
      exit(-1);
    }
    else 
    {
      ps->a = tmp;
      ps->capacity = newCapacity;
    }
  }

  //将数据入栈
  ps->a[ps->top] = data;
  ps->top++;
}
  1. 首先确保ps合法
  2. 因为是动态栈,会出现空间不够的情况,在入栈之前首先确保容量充足,如果容量不够,则进行扩容
  3. 将数据入栈,同时top++

3.3 出栈 (StackPop)

// 出栈
void StackPop(Stack* ps)
{
  assert(ps); //确保ps合法

  assert(!StackEmpty(ps));  //确保栈不为空
  ps->top--;

}
  1. 确保 ps 合法
  2. 确保栈不为空
  3. 直接将top--即可

3.4 检测栈是否为空 (StackEmpty)

// 检测栈是否为空, 如果为空返回非零结果, 如果不为空返回 0
int StackEmpty(Stack* ps)
{
  assert(ps); //确保ps合法
  
  if (ps->top > 0)
  {
    return 0;
  }
  else 
  {
    return 1;
  }
}
  1. 确保ps合法
  2. 如果top大于0,说明栈不为空,反之则为空

3.5 获取栈顶元素 (StackTop)

// 获取栈顶元素
STDataType StackTop(Stack* ps)
{
  assert(ps);   //确保ps合法
  assert(!StackEmpty(ps));  //确保栈不为空

  return ps->a[ps->top - 1];
}
  1. 确保ps合法
  2. 确保栈不为空
  3. 直接返回top - 1位置的元素

3.6 获取栈中有效元素个数 (StackSize)

// 获取栈中有效元素个数
int StackSize(Stack* ps)
{
  assert(ps);   //确保ps合法
  return ps->top;
}
  1. 确保ps合法
  2. 直接将top返回即可

3.7 销毁栈 (StackDestroy)

// 销毁栈
void StackDestroy(Stack* ps)
{
  assert(ps); //确保ps合法

  free(ps->a);
  ps->a = NULL;
  ps->capacity = 0;
  ps->top = 0;
}
  1. 确保ps合法
  2. 将ps指向的数组空间归还给操作系统,同时将topcapacity置为0

3.8 完整代码

  • Stack.h
#pragma once 

#include <stdio.h>
#include <assert.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
int StackEmpty(Stack* ps);
// 销毁栈
void StackDestroy(Stack* ps);


  • Stack.c
#include "Stack.h"

// 初始化栈
void StackInit(Stack* ps)
{
  assert(ps);
  
  ps->a = NULL;     
  ps->top = 0;
  ps->capacity = 0;
}

//入栈
void StackPush(Stack* ps, STDataType data)
{
  assert(ps);       //确保ps合法

  //如果容量不够则扩容
  if (ps->capacity == ps->top)
  {
    int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;   //定义新的容量
    STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newCapacity);  //开辟新的空间
    if (tmp == NULL)
    {
      perror("malloc error");
      exit(-1);
    }
    else 
    {
      ps->a = tmp;
      ps->capacity = newCapacity;
    }
  }

  //将数据入栈
  ps->a[ps->top] = data;
  ps->top++;
}

// 出栈
void StackPop(Stack* ps)
{
  assert(ps); //确保ps合法

  assert(!StackEmpty(ps));  //确保栈不为空
  ps->top--;

}

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

// 获取栈顶元素
STDataType StackTop(Stack* ps)
{
  assert(ps);   //确保ps合法
  assert(!StackEmpty(ps));  //确保栈不为空

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

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

// 销毁栈
void StackDestroy(Stack* ps)
{
  assert(ps); //确保ps合法

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

  • Test.c
#include "Stack.h"

void StackTest1()
{
  Stack st;

  StackInit(&st);
  StackPush(&st, 1);
  printf("%d\n", StackSize(&st));
  printf("%d\n", StackTop(&st));

  StackPush(&st, 2);
  printf("%d\n", StackSize(&st));
  printf("%d\n", StackTop(&st));
 
  StackPush(&st, 3);
  printf("%d\n", StackSize(&st));
  printf("%d\n", StackTop(&st));
  
  StackPush(&st, 4);
  printf("%d\n", StackSize(&st));
  printf("%d\n", StackTop(&st));
  
  StackPush(&st, 5);
  printf("%d\n", StackSize(&st));
  printf("%d\n", StackTop(&st));
  
  StackPop(&st);
  printf("%d\n", StackSize(&st));
  printf("%d\n", StackTop(&st));
  
  StackPop(&st);
  printf("%d\n", StackSize(&st));
  printf("%d\n", StackTop(&st));
  
  StackPop(&st);
  printf("%d\n", StackSize(&st));
  printf("%d\n", StackTop(&st));
  
  StackPop(&st);
  printf("%d\n", StackSize(&st));
  printf("%d\n", StackTop(&st));
  
  StackPop(&st);
  printf("%d\n", StackSize(&st));
  printf("%d\n", StackTop(&st));
  
  StackPop(&st);
}

int main(void)
{
  StackTest1();

  return 0;
}

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

int main(void)
{
  StackTest1();

  return 0;
}

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

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

相关文章

【论文投稿】图形学论文投稿去向

如果您想投稿关于网格几何处理的论文&#xff0c;以下是一些知名的学术会议和期刊&#xff0c;您可以考虑将您的研究成果提交到这些地方&#xff1a; 学术会议&#xff1a; SIGGRAPH&#xff1a;SIGGRAPH会议是计算机图形学领域最重要的会议之一&#xff0c;接收与图形学和交互…

力扣:86. 分隔链表(Python3)

题目&#xff1a; 给你一个链表的头节点 head 和一个特定值 x &#xff0c;请你对链表进行分隔&#xff0c;使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。 你应当 保留 两个分区中每个节点的初始相对位置。 来源&#xff1a;力扣&#xff08;LeetCode&#xff09;…

2023-9-4 快速幂

题目链接&#xff1a;快速幂 #include <iostream> #include <algorithm>using namespace std;typedef long long LL;LL qmi(int a, int k, int p) {LL res 1;while(k){if(k & 1) res (LL) res * a % p;k >> 1;a (LL) a * a % p;}return res; }int mai…

羊城杯2023 部分wp

目录 D0nt pl4y g4m3!!!(php7.4.21源码泄露&pop链构造) Serpent(pickle反序列化&python提权) ArkNights(环境变量泄露) Ez_misc(win10sinpping_tools恢复) D0nt pl4y g4m3!!!(php7.4.21源码泄露&pop链构造) 访问/p0p.php 跳转到了游戏界面 应该是存在302跳转…

如何高效的解析Json?

Json介绍 Json是一种数据格式&#xff0c;广泛应用在需要数据交互的场景Json由键值对组成每一个键值对的key是字符串类型每一个键值对的value是值类型(boo1值数字值字符串值)Array类型object类型Json灵活性他可以不断嵌套&#xff0c;数组的每个元素还可以是数组或者键值对键值…

Kubernetes v1.25.0集群搭建实战案例(新版本含Docker容器运行时)

k8s 1.24之后弃用了docker容器运行时&#xff0c;安装方式上有所不同&#xff0c;网上找到的大多数都是1.24之前的版本。所以把自己搭建的完整过程记录下来供大家参考。 一、前言 k8s的部署方式有多种kubeadm、kind、minikube、Kubespray、kops等本文介绍官方推荐的kubeadm的…

Python入门学习12

一、Python包 什么是Python包 从物理上看&#xff0c;包就是一个文件夹&#xff0c;在该文件夹下包含了一个 __init__.py 文件&#xff0c;该文件夹可用于包含多个模块文件。从逻辑上看&#xff0c;包的本质依然是模块 包的作用: 当我们的模块文件越来越多时,包可以帮助我们管…

arco-design-vue的tree组件实现右击事件

arco-design-vue的tree组件实现右击事件 业务中需要使用到tree组件&#xff0c;并且还要对tree实现自定义鼠标右击事件。在arco-design-vue的文档中&#xff0c;可以明确的看到&#xff0c;tree组件并没有右击事件的相关回调&#xff0c;那要如何实现呢&#xff1f;&#xff1f…

10 和为K的子数组

和为K的子数组 题解1 前缀和&#xff08;哈希表&#xff09;题解2 暴力枚举(没过) 给你一个整数数组 nums 和一个整数 k &#xff0c;请你统计并返回 该数组中和为 k 的 连续子数组的个数 。 示例 1&#xff1a; 输入&#xff1a;nums [1,1,1], k 2 输出&#xff1a;2示例…

字节二面:如果高性能渲染十万条数据?

前言 最近博主在字节面试中遇到这样一个面试题&#xff0c;这个问题也是前端面试的高频问题&#xff0c;作为一名前端开发工程师&#xff0c;我们虽然可能很少会遇到后端返回十万条数据的情况&#xff0c;但是了解掌握如何处理这种情况&#xff0c;能让你对前端性能优化有更深的…

【力扣每日一题】2023.9.4 序列化和反序列化二叉搜索树

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 题目给我们一棵搜索二叉树&#xff0c;要我们将这棵二叉树转变为字符串&#xff0c;同时我们需要根据字符串再变回二叉树&#xff0c;具体…

外贸开发信这么写,效果更好

很多小伙伴说好像现在无论是精准的发送开发信还是群发邮件&#xff0c;似乎效果都没有以往那么好&#xff0c; 虽然现在的开信已经从简单的纯文字书写改到了图文并茂&#xff0c;也从只介绍自己公司的产品实力晋升到对目标客户的分析探寻&#xff0c; 虽然找到了很多对口的邮…

智慧农旅数字农旅

智慧农旅|数字农旅|智慧文旅|智慧农旅平台|数字农旅平台|产业大脑|农业产业大脑|智慧农业|农业可视化|高标准农田|高标准产业园|数字农业大脑|大棚可视化|大棚物联管控|大棚数字孪生管控|大田物联管控|数字农业|数字乡村|数字乡村可视化|数字农业研学|数字大棚|智慧大棚|农业数…

RHCA之路---EX280(6)

RHCA之路—EX280(6) 1. 题目 Create an application greeter in the project samples which uses the Docker image registry.lab.example.com/openshift/hello-openshift so that it is reachable at the following address only: https://greeter.apps.lab.example.com (Not…

QTday1基础

作业 一、做个QT页面 #include "hqyj.h"HQYJ::HQYJ(QWidget *parent)//构造函数定义: QWidget(parent)//显性调用父类的有参构造 {//主界面设置this->resize(540,410);//设置大小this->setFixedSize(540,410);//设置固定大小this->setWindowIcon(QIcon(&q…

算法 数据结构 双向环形链表 手撸环形链表 环形链表实现容器 环形链表添加修改删除获取大小 环形链表实现自定义容器 手撸容器 双向环形哨兵链表 数据结构(六)

1. 环形链表&#xff1a; 2. 建议先不要看我写得自己先实现下&#xff0c;只将Node内部类复制自己命名得容器内&#xff0c; 实现方法&#xff1a; a. add方法&#xff08;添加到头部&#xff0c;尾部添加&#xff0c;指定位置添加&#xff09; b. get方法&#xff08;获取首部…

中小型ISR无人机海战场的运用与关键技术分析

源自&#xff1a;航空兵器 作者&#xff1a;温亮, 孙晓路, 卫国华, 吕建平, 王波 摘 要 关键词 无人机, 情报侦察监视, 海战场, 发射与回收, 自主控制, 任务载荷 引 言 1 国内外海上中小型无人机发展现状 表1 各国的部分中小型无人机 2 中小型ISR无人机在海战场的运用 2…

ModaHub魔搭社区专访百度智能云李莅:做 AI native 的向量数据库有哪些技术难点?

ModaHub魔搭社区&#xff1a;那这种传统的数据库加向量插件的方式和 AI native 的向量数据库两者之间的区别是什么&#xff1f;做 AI native 的向量数据库有哪些技术难点&#xff1f; 李莅&#xff1a;向量检索算法是向量领域最核心的技术挑战。目前&#xff0c;主流的算法是基…

无涯教程-JavaScript - DAY函数

描述 DAY函数返回日期的日期,由序列号表示。日期以1到31之间的整数形式给出。 语法 DAY (serial number)争论 Argument描述Required/Optionalserial number 您要查找的日期。 应该使用DATE函数或其他公式或函数的输出输入日期。 如,在2008年5月的第23天使用DATE(2008,5,23)…

计算准确率sklearn.accuracy_score

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 计算准确率 sklearn.accuracy_score [太阳]选择题 请问关于以下代码最后输出结果的是&#xff1f; from sklearn.metrics import accuracy_score yp [1, 0, 1, 1] y [1, 0, 0, 1] print(&qu…