数据结构 之 栈【图文详解】

2023-11-10

在这里插入图片描述

栈是一种操作受限的线性表只允许从一端插入和删除数据。栈有两种存储方式,即线性存储和链接存储(链表)。栈的一个最重要的特征就是栈的插入和删除只能在栈顶进行,所以每次删除的元素都是最后进栈的元素,故栈也被称为后进先出(LIFO)表。每个栈都有一个栈顶指针,它初始值为-1,且总是指向最后一个入栈的元素,栈有两种处理方式,即进栈(push)和出栈(pop),因为在进栈只需要移动一个变量存储空间,所以它的时间复杂度为O(1),但是对于出栈分两种情况,栈未满时,时间复杂度也为O(1),但是当栈满时,需要重新分配内存,并移动栈内所有数据,所以此时的时间复杂度为O(n)。以下举例栈结构的两种实现方式,线性存储和链接存储。
这里写图片描述

1、线性存储
线性存储的方式和线性表基本一致,只不过多了后进先出的限制而已,它是静态分配的,即使用前,它的内存就已经以数组的形式分配好了,所以在初始化时,需要指明栈的节点最大个数。

#include "stdafx.h"
#include <iostream>  
#include <new>  
   
//定义  
template<class T>  
class LineStack  
{  
public :  
    LineStack(int MaxListSize=10);  //构造函数
    ~LineStack()                             //析构函数 
    {
        delete[] elements;
    }  
  
    bool IsEmpty() const             //判断是否为空
    {
        return top==-1;
    }  

    bool IsFull() const               //判断是否满
    {
        return top==MaxSize-1;
    }  

    T pop(); //出栈 

    int push(const T& data);  //进栈

    T getPop();  //获取栈顶元素值

    void clear();  //清空栈

    void print() ;  
  
private:  
    int top;  //栈顶指针
    int MaxSize;  //数组最大长度
    T *elements;//一维动态数组  
  
};  

//实现...  
template<class T>  
LineStack<T>::LineStack(int MaxListSize)  
{   
    //基于公式的线性表的构造函数  
    MaxSize = MaxListSize;  
    elements = new T[MaxSize];  
    top = -1;  
}  
  
template<class T>  
T LineStack<T>::pop()  
{  
    if(IsEmpty()) 
    {
        return NULL;  
    }

    return elements[top--];  
}  
  
template<class T>  
int LineStack<T>::push(const T& data)  
{  
    if(IsFull())
    {
        return -1;
    }
    else
    {
        elements[++top] = data;
    }

    return 0;  
}  
  
  
template<class T>  
T LineStack<T>::getPop()  
{  
    if(IsEmpty()) 
    {
        return NULL;  
    }

    return elements[top]; 
}  
  
template<class T>  
void LineStack<T>::clear()  
{  
    top = -1;
    return true;  
}  
  
template<class T>  
void LineStack<T>::print()  
{  
    for(int i=0;i<=top;i++)
    {
        std:: cout<<elements[i]<<"   ";  
    }
}  
 
void LineStackSample()  
{  
    int j;
    int a = 10,b = 20,c = 30,d = 40;

    LineStack<int> S(10);  
    std::cout<<"IsFull  = "<<S.IsFull()<<std::endl;  
    std::cout<<"IsEmpty = "<<S.IsEmpty()<<std::endl;  
  
    S.push(a);
    S.push(b);
    S.push(c);
    S.push(d);

    j = S.pop();
    std::cout<<j<<std::endl;
    j = S.pop();
    std::cout<<j<<std::endl;
    j = S.pop();
    std::cout<<j<<std::endl;
    j = S.pop();
    std::cout<<j<<std::endl;

    return;
}  

int main(int argc, _TCHAR* argv[])  
{  
    LineStackSample();  
  
    //暂停操作  
    char str;  
    std::cin>>str;  
    //程序结束  
    return 0;  
}  

运行结果如下:
这里写图片描述

2、链接存储
实际上只要对单链表类做适当的修改,限制其插入、删除、修改和访问结点的行为,使其符合栈先进后出的规则即可,另外需要单独提供栈访问的接口函数,例如进栈、出栈、获取栈大小等,链表知识可以参考https://blog.csdn.net/Chiang2018/article/details/82730174。

// 栈动态.cpp : 定义控制台应用程序的入口点。
//

// 单链表.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <stdlib.h>
#include <iostream>

template <class T>
class Node
{
public:
    T data;
    Node(T& item);
    Node<T>* next;
};

template<class T>
class LinkList
{
public:
    LinkList();
    ~LinkList();
    int getSize(void);
    bool IsEmpty(void);
    int gotoNext(void);
    int getPostion(void);
    int InsertNode(T& data);
    int DeleteNode(void);
    void getCurrNodeData(T& data);
    void setCurrNodeData(T& data);
    void clear();
    void print();

private:
    Node<T>* head;
    Node<T>* currNode;
    int size;
    int position;
    void freeNode(Node<T>* p);
};

/* 链表节点构造函数 */
template <class T>
Node<T>::Node(T& item)
{
    data = item;
    next = NULL;
}

/* 链表构造函数 */
template <class T>
LinkList<T>::LinkList()
{
    head = NULL;
    currNode = NULL;
    size = 0;
    position = -1;
}

/* 链表析构函数 */
template <class T>
LinkList<T>::~LinkList()
{
    clear();
}

/* 获取链表长度 */
template <class T>
int LinkList<T>::getSize(void)
{
    return size;
}

/* 判断链表是否为空 */
template <class T>
bool LinkList<T>::IsEmpty(void)
{
    return size==0?true:false;
}

/* 移动到下个节点,返回下个节点的位置值 */
template <class T>
int LinkList<T>::gotoNext(void)
{
    if(NULL == head)
    {
        return -1;
    }

    if(NULL == currNode)
    {
        return -1;
    }
    else
    {
        currNode = currNode->next;
        position++
    }

    return position;
}

/* 获取当前节点的位置 */
template <class T>
int LinkList<T>::getPostion(void)
{
    return position;
}

/* 在当前节点前插入新节点 */
template <class T>
int LinkList<T>::InsertNode(T& data)
{
    Node<T>* p = new Node<T>(data);

    if(0 == size)
    {
        head = p;
        head->next = NULL;
        currNode = p;
    }
    else
    {
        p->next = currNode->next;
        currNode->next = p;
        currNode = p;
    }

    size++;
    position++;
    return size;
}


/* 删除当前节点 */
template <class T>
int LinkList<T>::DeleteNode(void)
{
    if(0 == size)
    {
        return -1;
    }
    
    Node<T>* p = head;
    Node<T>* tmp;
    for(int i = 0;i < size;i++)
    {
        if(NULL == p)
        {
            return -1;
        }

        if(p->next == currNode)
        {
            p->next = currNode->next;
            break;
        }

        p = p->next;
    }

    tmp = currNode;

    if(currNode == head)
    {
        head = currNode->next;
    }

    if(NULL == currNode->next)
    {
        position--;
        currNode = p;
    }
    else
    {
        currNode = currNode->next;
    }
    

    freeNode(p);
    size--;
    if(0 == size)
    {
       position = -1;
    }

    return 0;
}

/* 释放指定节点的内存 */
template <class T>
void LinkList<T>::freeNode(Node<T>* p)
{
    if(!p)
    {
        delete p;
    }

    return;
}

/* 获取当前节点的数据 */
template <class T>
void LinkList<T>::getCurrNodeData(T& data)
{
    if(currNode)
    {
        data = currNode->data;
    }

    return ;
}

/* 修改当前节点的数据 */
template <class T>
void LinkList<T>::setCurrNodeData(T& data)
{
    if(currNode)
    {
        currNode->data = data;
    }

    return ;
}

/* 清空链表 */
template <class T>
void LinkList<T>::clear()
{
    if(0 == size)
    {
        return;
    }

    Node<T>* p = head;
    Node<T>* tmp = head->next;
    while(p)
    {
        freeNode(p);
        p = tmp;
        if(tmp)
        {
            tmp = tmp->next;
        }
    }

    head = NULL;
    currNode = NULL;
    size = 0;
    position = -1;

    return;
}

template <class T>
void LinkList<T>::print()
{
    if(0 == size)
    {
        return;
    }

    Node<T>* p = head;
    Node<T>* tmp = head->next;
    while(p)
    {
        std::cout<<p->data<<std::endl;
        p = tmp;
        if(tmp)
        {
            tmp = tmp->next;
        }
    }

    return;
}
template <class T>
class LinkedStack
{
private:
    LinkList<T>* link;
public:
    LinkedStack();
    void push(T& data);
    T pop();
    void ClearStack();
    int getSize();
    bool isEmpty();
};
template <class T>
LinkedStack<T>::LinkedStack()
{
    link = new LinkList<T>;
}
template <class T>
bool LinkedStack<T>::isEmpty()
{
    return link->IsEmpty();
}
template <class T>
int LinkedStack<T>::getSize()
{
    return link->size;
}

template <class T>
void LinkedStack<T>::ClearStack()
{
    link->clear();
}
template <class T>
void LinkedStack<T>::push(T& data)
{
    link->InsertNode(data);
}

template <class T>
T LinkedStack<T>::pop()
{
    T tmp;
    if(isEmpty())
    {
        return NULL;
    }
    
    link->getCurrNodeData(tmp);

    link->DeleteNode();

    return tmp; 
}

int main(int argc, _TCHAR* argv[])
{
    int j = 0;
    int a = 10,b=20,c=30,d=40,e=50;
    LinkedStack<int> list;

    list.push(a);
   
    list.push(b);
    list.push(c);
    list.push(d);
    list.push(e);

    j = list.pop();
    std::cout<<j<<std::endl;

    j = list.pop();
    std::cout<<j<<std::endl;

    j = list.pop();
    std::cout<<j<<std::endl;

    j = list.pop();
    std::cout<<j<<std::endl;

    j = list.pop();
    std::cout<<j<<std::endl;

    std::cin.get();
	return 0;
}

运行结果是:
这里写图片描述
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

数据结构 之 栈【图文详解】 的相关文章

  • 设计一个也可以在 O(1) 摊余时间内出队的堆栈?

    我有一个抽象数据类型 可以将其视为从左到右存储的列表 具有以下可能的操作 推送 将新项目添加到列表的左端 Pop 删除列表左端的项目 Pull 删除列表右端的项目 使用三个堆栈和恒定的附加内存来实现此目的 以便任何推入 弹出或拉出操作的摊销
  • 206.翻转链表

    翻转链表 力扣 LeetCode 官网 全球极客挚爱的技术成长平台 备战技术面试 力扣提供海量技术面试资源 帮助你高效提升编程技能 轻松拿下世界 IT 名企 Dream Offer https leetcode cn problems re
  • 顺序表和链表基础

    定义动态的顺序表 typedef int SLDataType typedef struct Seqlist SLDataType array size t size size t capacity Seqlist 在顺序表中插入数据 bo
  • 「优选算法刷题」:移动零

    嗨 这个假期罗根开始接触了算法 在为今年的蓝桥杯做准备 所以 开个新专栏 记录记录自己做算法题时的心得 一 题目 给定一个数组 nums 编写一个函数将所有 0 移动到数组的末尾 同时保持非零元素的相对顺序 请注意 必须在不复制数组的情况下
  • 用栈实现队列(OJ中报错的处理)

    用栈实现队列 ERROR AddressSanitizer myQueueFree函数中栈的释放处现了问题 没有调用StackDestory而是直接free了 这个是栈初始化时 capacity与malloc申请的空间大小没有匹配 请你仅使
  • 裸机环境下malloc什么时候返回NULL?

    有一个c内存模型如下 Last Address of RAM Stack v RAM Heap ZI RW First Address of RAM 堆栈和堆空间以相反的方向增加 它们会在中间相互重叠
  • Linux 内核如何强制堆栈大小限制?

    我知道堆栈大小可以通过限制工具进行控制 但是内核如何强制执行其中一些限制 例如 RLIMIT STACK 由于linux不涉及堆栈操作 只是mov或push指令 那么当超出限制时内核如何发出SIGSEGV 据我了解 对于虚拟寻址 CPU 提
  • ARM GCC 生成函数序言

    我提到 ARM 工具链可以生成不同的函数序言 实际上 我看到两个 obj 文件 vmlinux 具有完全不同的函数序言 第一种情况如下所示 push some registers maybe fp lr lr ommited in leaf
  • 函数内声明的 const 数组是否存储在堆栈中?

    如果这是在函数中声明的 它会在堆栈上声明吗 它是 const 让我想知道 void someFunction const unsigned int actions 8 e1 e2 etc 是的 它们在堆栈上 您可以通过查看此代码片段来了解这
  • Android:清除后退堆栈

    在 Android 中 我有一些活动 比如说 A B C 在A中 我使用以下代码打开B Intent intent new Intent this B class startActivity intent 在B中 我使用以下代码打开C In
  • Excel VBA 的 LIFO(堆栈)算法/类

    我正在寻找在 Excel 的 VBA 中实现 Stack 类 我想使用后进先出结构 以前有人遇到过这个问题吗 你知道外部库处理结构 如 Stack Hastable Vector 除了原始的 Excel Collection 等 Thank
  • 在堆栈上增长数组

    这本质上是我的问题 在函数的生命周期中 我生成一些整数 然后在也是同一函数一部分的算法中使用整数数组 整数数组仅在函数内使用 因此将数组存储在堆栈上自然是有意义的 问题是在生成所有整数之前我不知道数组的大小 我知道如何在堆栈上分配固定大小和
  • 在 D 中制作结构体的堆副本

    如何创建堆栈上结构的垃圾收集副本 来自 C 背景 我的第一个猜测是像下面这样的复制构造函数 但它对于 D 来说似乎不太惯用 而且我在我看过的任何 D 项目中都没有看到过这样的复制构造函数 struct Foo immutable int b
  • ValueType 堆栈空间耗尽

    我的理解是 Net中的每个新线程都会分配1MB 堆栈空间 https stackoverflow com questions 4088448 the net stack vs windows stack 进一步我的理解是 值类型存储在堆栈上
  • 为什么在函数堆栈上返回值不安全

    我在阅读 bruce eckel 时遇到了以下段落 他试图解释为什么函数在堆栈上返回值不安全 现在想象一下如果一个普通函数尝试在堆栈上返回值会发生什么您不能触及返回地址上方堆栈的任何部分 因此该函数必须将值推入返回地址下方 但是当执行汇编语
  • Bluecove:以编程方式重新启动蓝牙堆栈

    我正在尝试关闭蓝牙服务 但 Bluecove 在连接关闭方法上有错误 https code google com p bluecove issues detail id 90 https code google com p bluecove
  • C 中的递归深度是否有任何硬连线限制

    正在讨论的程序尝试计算sum of first n natural numbers using recursion 我知道这可以使用一个简单的公式来完成n n 1 2但这里的想法是使用recursion 程序如下 include
  • 从 Android 应用程序堆栈中手动删除活动

    我一直在开发 Android Native App 我想做的是 Activities A gt B gt C Then A gt B gt C gt C 从 C Activity 中 如果它再次指向 C 那么我想手动从堆栈中删除 C B 在
  • 每个进程是否都存在内核堆栈?

    每个用户空间进程是否都存在一个内核堆栈和一个用户空间堆栈 如果两个堆栈都存在 那么每个用户空间进程应该有 2 个堆栈指针 对吗 在 Linux 中 每个任务 用户空间或内核线程 都有一个 8kb 或 4kb 的内核堆栈 具体取决于内核配置
  • 堆栈是向上增长还是向下增长?

    我在 C 中有这段代码 int q 10 int s 5 int a 3 printf Address of a d n int a printf Address of a 1 d n int a 1 printf Address of a

随机推荐

  • Spring在代码中获取bean的几种方式

    Spring在代码中获取bean的几种方式 方法一 在初始化时保存ApplicationContext对象 方法二 通过Spring提供的utils类获取ApplicationContext对象 方法三 继承自抽象类ApplicationO
  • 黑客一般是如何入侵电脑的?

    1 无论什么站 无论什么语言 我要渗透 第一件事就是扫目录 最好一下扫出个上传点 直接上传 shell 诸位不要笑 有时候你花很久搞一个站 最后发现有个现成的上传点 而且很容易猜到 不过这种情况发生在 asp 居多 2 asp aspx M
  • CV计算机视觉核心07-目标检测yolo v2、v3(yolo初始版本的v0和v1版本代码)

    CV计算机视觉核心07 目标检测 设计检测类算法的output层 可用已知条件有 1 检测问题的输出是什么 怎么用数字来表示 输入是一个矩阵 输出是 x y w h 其中x和y表示目标的左上角坐标 w和h表示目标的长和宽 因此输出是用四个这
  • 【NLP】维基百科中文数据训练word2vec词向量模型——基于gensim库

    前言 本篇主要是基于gensim 库中的 Word2Vec 模型 使用维基百科中文数据训练word2vec 词向量模型 大体步骤如下 数据预处理 模型的训练 模型的测试 准备条件 Windows10 64位 Python3 6 并安装 ge
  • ‘git‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。

    1 cmd报错内容 C Users 27104 Desktop gt git clone https github com tianyucoder 200826 ajax git 不是内部或外部命令 也不是可运行的程序 或批处理文件 2 原
  • range()函数

    range 函数 创建一个整数列表 一般用于for循环当中 1 语法 range start stop step start 计数从start开始 默认为0 range 9 和range 0 9 是一样的 stop 计数到stop为止 但不
  • 通用智能面临巨大掣肘,国产AIGC还在寻找光明

    无论技术有多先进 符合商业规律才能笑到最后 数科星球 原创 作者丨苑晶 编辑丨十里香 AI GC背后充满了故事 在一家家企业手握巨额融资之时 人们耳边再次响起了警钟 诚然 在新的浪潮之下 符合商业规律的企业才能笑到最后 在国外竞品大踏步前行
  • 关于项目管理的知识点

    转自 http blog joycode com mvm 感觉写的挺好 推荐大家看一下 1 你们的项目组使用源代码管理工具了么 应该用 VSS CVS PVCS ClearCase CCC Harvest FireFly都可以 我的选择是V
  • 【目的:windows下VS2017/2022配置使用opengl - 初探-创建一个空窗口】

    目的 windows下VS2017 2022配置使用opengl 初探 创建一个空窗口 环境 系统 Win10 环境 VS2017 64bit 步骤 windows下visualstudio下使用opengl 搭建配置环境并测试窗口 1 o
  • vue3.0---使用computed来获取vuex里数据

    不再是vue2 0里什么mapGetter mapState那些复杂的获取方式 vue3 0里直接使用computed就可以调用vuex里的数据了 喜大普奔 同时注意 一点 不可以直接使用useStore 方法里的state对象 因为在输出
  • css将文字置于图片上的方法

    我们在开发的时候 有大量的场景需要将文字至于图片之上 如图 以上是将 空山新雨后 天气晚来秋 加在图片之上 对于大多数情况 我们都可以将图片作为背景图引入 但有些时候不能将图片作为背景图引入 这个时候就要用到其他的方法 以下我们提供三种方法
  • MyBatis的lazy-loading是什么?

    MyBatis的lazy loading是什么 MyBatis的lazy loading 延迟加载 是一种数据查询策略 它允许仅在需要时才从数据库中获取相关联的数据 这是通过创建 Java 代理对象来实现的 该代理对象在真正需要相关对象时将
  • linux命令——man

    Shell 也称为终端或壳 用户与 Linux 系统的交互 常见执行Linux命令的格式是这样的 命令名称 命令参数 命令对象 注意 命令名称 命令参数 命令对象之间请用空格键分隔 命令对象一般是指要处理的文件 目录 用户等资源 而命令参数
  • Linux下搭建第一个区块链网络(FISCO BCOS)

    Linux下搭建第一个区块链网络 FISCO BCOS 概述 搭建单群组FISCO BCOS联盟链 配置及使用控制台 部署及调用HelloWorld合约 概述 FISCO BCOS是由国内企业主导研发 对外开源 安全可控的企业级金融联盟链底
  • Error:JAVA_HOME is not set and could not be found 解决般的法

    很多人按照网上的各类教程搭建hadoop 但经常在安装好了后 启动hadoop时出现各类的错误 本文就 Error JAVA HOME is not set and could not be found 这一错误提出解决办法 针对这个错误
  • 10.1~10.3国庆节技术沉淀

    国庆节没怎么学习 玩了一天 宿舍玩游戏两天 一次循环完成百钱白鸡 关键就在于先人工化简一下两个方程式 23456789的各位之和怎么求 现在也不会 好吧 现在会了 不太理解 求整数各位之和 author zlb date 10 3 impo
  • 2020年“金九银十”的面试宝典:腾讯,字节等大厂面试真题汇总

    前言 职场的金九银十跳槽季火热进行中 不同的是 今年的竞争比往年会更加激烈一些 形式更加严峻一些 对于求职者来说 面试是一道坎 很多人会恐惧面试 即使是工作很多年的老鸟 也可能存在面试焦虑 大家多多少少可能都听到或看到一些信息 就是好多公司
  • Spring Boot初识-2

    Spring Boot初识 2 1 整合Redis Spring传统的整合Redis 导入jedis包 利用IoC和DI帮你实现Jedis连接实例的管理 原本 JedisPool JedisPoolConfig 主机地址 数据库索引 密码
  • 操作系统(03)- 操作系统的运行机制和体系结构

    操作系统的运行机制和体系结构 计算机指令系统是计算机硬件的语言系统 也叫机器语言 它是软件和硬件的主要界面 从系统结构的角度看 它是系统程序员看到的计算机的主要属性 我们使用高级语言编写程序 最终都会被编译为机器语言 计算机才能识别 不清楚
  • 数据结构 之 栈【图文详解】

    栈是一种操作受限的线性表只允许从一端插入和删除数据 栈有两种存储方式 即线性存储和链接存储 链表 栈的一个最重要的特征就是栈的插入和删除只能在栈顶进行 所以每次删除的元素都是最后进栈的元素 故栈也被称为后进先出 LIFO 表 每个栈都有一个