数据结构(栈)

news2024/11/17 20:45:40

目录

栈的定义

 形象比喻

栈的相关术语 

 栈的抽象数据类型(栈Stack的ADT)

顺序栈 

顺序栈类的声明

 顺序栈类成员函数的实现

基本效率分析

顺序栈的应用(小测试)

 main.cpp

共享栈

双共享栈 

链式栈 

 链式栈基本操作分析

链式栈类的声明

链式栈基本操作的实现


栈的定义

如果元素到达线性结构的时间越晚,离开的时间就越早,这种线性结构称为栈(Stack)或堆栈

因为元素之间的关系是由到达、离开的时间决定的,因此栈通常被称为时间有序表。

而到达和离开的含义就是插入和删除操作,因此栈可以看作是插入和删除操作位置受限的线性表。

 形象比喻

 乒乓球盒的进球和出球,它遵循了最后进盒的球反而最先出盒,即所谓的后进先出(LIFO, Last In First Out)或先进后出(FILO, First In Last Out)结构。

 

栈的相关术语 

栈的首部(元素最早到达的部分)称为栈底(bottom) ,栈结构的尾部(元素最晚到达的部分)称为栈顶(top)

为了保证栈的先进后出或后进先出的特点,元素的插入和删除操作都必须在栈顶进行。元素从栈顶删除的行为,称为出栈或者弹栈操作(pop); 元素在栈顶位置插入的行为,称为进栈或者压栈操作(push)。

读取栈顶元素数据值的操作,称为取栈顶内容操作(top)。

当栈中元素个数为零时,称为空栈

 栈的抽象数据类型(栈Stack的ADT)

Data: { xi | xiÎ ElemSet, i=1,2,3,……n, n > 0} 或 Φ; ElemSet为元素集合。

Relation: {<xi,xi+1>|xi,xi+1ÎElemSet, i=1,2,3,……n-1}, x1为栈底,xn为栈顶。

Operations:

操作前提结果
initialize栈初始化为一个空栈。
isEmpty栈Stack空返回true,否则返回false。
isFull栈Stack满返回true,否则返回false。
top栈Stack非空。返回栈顶元素的值,栈顶元素不变。
push栈Stack非满,已知待插入的元素。将该元素压栈,使其成为新的栈顶元素。
pop栈Stack非空。将栈顶元素弹栈,该元素不再成为栈顶元素。
destroy释放栈Stack占用的所有空间。

顺序栈 

 栈的顺序存储即使用连续的空间存储栈中的元素。可以将栈底放在数组的0下标位置,进栈和出栈总是在栈的同一端(栈顶)进行,顺序方式存储的栈称为顺序栈

 

栈空标志:top=-1

栈满标志:top=maxSize-1

 

顺序栈类的声明

 顺序栈的描述:数组指针array,数组大小maxSize,栈顶下标Top。

class illegalSize{};
class outOfBound{};
 
template <class elemType>
class seqStack
{  private:
        elemType *array;    //栈存储数组,存放实际的数据元素。
        int Top;            //栈顶下标。
        int maxSize;	    //栈中最多能存放的元素个数。
        void doubleSpace();
 public:
        seqStack(int initSize = 100); //初始化顺序栈
        bool isEmpty () { return ( Top == -1 ); } ; //栈空返回true,否则返回false。
        bool isFull () { return (Top == maxSize-1); };//栈满返回true,否则返回false。
        elemType top ();// 返回栈顶元素的值,不改变栈顶
        void push (const elemType &e );//将元素e压入栈顶,使其成为新的栈顶。
        void pop (); //将栈顶元素弹栈。
        ~seqStack(){ delete []array;}; //释放栈占用的动态数组
};

 顺序栈类成员函数的实现

template <class elemType>
seqStack<elemType>::seqStack(int initSize)//初始化顺序栈
{	array = new elemType[initSize];
	if (!array) throw illegalSize();
	Top=-1;    maxSize=initSize;
}

template <class elemType>
elemType seqStack<elemType>::top ()// 返回栈顶元素的值,不改变栈顶
{   if (isEmpty()) throw outOfBound();
    return array[Top];
}
template <class elemType>
void seqStack<elemType>::push(const elemType &e )
//将元素e压入栈顶,使其成为新的栈顶元素。
{     if  (isFull()) doubleSpace();
      //栈满时从新分配2倍的空间,并将原空间内容拷入
     array[++Top] = e;      	// 新结点放入新的栈顶位置。
}
template <class elemType>
void seqStack<elemType>::pop()//将栈顶元素弹栈。
{   if (Top==-1) throw outOfBound();
    Top--;
}

基本效率分析

函数initialize(seqStack)、isEmpty、isFull、top、pop、destroy(~seqStack)的时间复杂度均为O(1)。

push因某时可能扩大空间,造成O(n)时间消耗,但按照“分期付款式”法,分摊到单次的插入操作,时间复杂度仍为O(1)。

顺序栈的应用(小测试)

编写程序从键盘上依次输入一串字符(以回车键结束)。要求将该串字符按照输入顺序的逆序在屏幕上输出。

在程序中可以建立一个顺序栈,将输入的字符依次入栈,最后再依次出栈,便能得到逆序结果。 

 main.cpp

#include <iostream>
#include "seqStack.h"
using namespace std;
 int main()
{    // 声明一个栈。
     seqStack<char> s;
     char ctemp;
     //从键盘输入若干字符(结束用回车),
     //依照输入次序分别进栈
     cout<<"Input the elements," <<press enter to an end: ";
     ctemp = cin.get(); 
     while ( ctemp!='\n')
     { 	s.push(ctemp);  ctemp = cin.get();   }
          //将栈中的结点逐个出栈,并输出到屏幕上。
	 cout<<"output the elements in the stack one by one:";
	 while (!s.isEmpty()) 
     {
		ctemp = s.top();
        s.pop();
		cout<<ctemp;
     } 	
          cout<<endl;
	return 0;  
}

共享栈

在实际应用中,有时需要同时使用多个数据类型相同的栈。

栈中的元素个数因进栈、出栈操作动态地变化,所有栈不一定同时达到栈满,有时一些栈满而另一些栈尚余空间。

为了提高空间使用率,可以在同一块连续的空间中设置多个栈。

多个栈间共享空间,这些栈称为“共享栈”

共享栈的特点是每个栈拥有一个连续的小空间, 所有共享栈拥有一个大的连续空间。

 

 top指向实际栈顶的后一个位置

假设有m个栈,第i个栈空的条件:top[i]=bottom[i];

第i个栈栈满条件为:    当i<m-1时,top[i]=bottom[i+1];

                                   当i=m-1时,top[i]=maxSize。

 

双共享栈 

 可以将两个栈相向设置,即两个栈的栈底分别设置在连续空间的两个端点。

栈空的条件top[i]=bottom[i], i=0或1,两个栈不一定同时为空;

栈满的条件top[0]=top[1],即两个栈当中只剩下一个空位置的时候栈满,两个栈必定同时栈满。

链式栈 

 用不连续的空间和附加指针来存储元素及元素间的关系。

栈顶指针top指向处于栈顶的结点,即单链表中的首结点。

 

 链式栈基本操作分析

进栈操作push的实现,按照以下操作顺序:

1)申请新的结点空间,data字段为进栈元素值,next字段指向首结点。

2)栈顶指向新结点。

出栈操作pop的实现,按照以下操作顺序:

1)   记住栈顶结点的地址。

2)将原栈顶的直接后继设为新的栈顶。

3)释放原来栈顶结点空间。

链式栈类的声明

class outOfBound{};
template <class elemType>
class linkStack;
template <class elemType>
class Node
{  friend class linkStack<elemType>;
    private:
        elemType data;
        Node *next;
    public:
        Node(){next = NULL;}
        Node(const elemType &x, Node *p=NULL)
        { data = x; next = p; }
};
template <class elemType>
class linkStack
{
    private:
        Node<elemType> *Top;
    public:
        linkStack(){ Top = NULL; }; //初始化栈,使其为空栈
        bool isEmpty(){ return (Top==NULL); }; //栈为空返回true,否则返回false。
        bool isFull(){ return false; }; //栈满true,否则false。结点空间不连续,故总能满足
        elemType top();
        void push(const elemType &e);
        void pop();
        ~linkStack();
};

链式栈基本操作的实现

template <class elemType>
elemType linkStack<elemType>::top()
{
    if (!Top) throw outOfBound();//栈空
    return Top->data;
}
 
template <class elemType>
void linkStack<elemType>::push(const elemType &e)
{  Top = new Node<elemType>(e, Top);  }
template <class elemType>
void linkStack<elemType>::pop()
{
    Node<elemType> *tmp;
    if (!Top) throw outOfBound();//栈空
 
    tmp = Top; //用tmp记住原栈顶结点空间,用于弹栈后的空间释放
    Top = Top->next; //实际将栈顶结点弹出栈
 
    delete tmp;//释放原栈顶结点空间
}
template <class elemType>
linkStack<elemType>::~linkStack()
{
    Node<elemType> *tmp;
    while (Top)
    {
        tmp = Top;
        Top=Top->next;
        delete tmp;
    }
}
函数将 栈中的所有结点清除 空间回收, 时间 复杂度为 O(n )
构造 函数、 isEmpty isFull top push pop 的时间复杂 度均 O(1)

 

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

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

相关文章

cf Educational Codeforces Round 134 E. Prefix Function Queries

原题&#xff1a; You are given a string s, consisting of lowercase Latin letters. You are asked q queries about it: given another string t, consisting of lowercase Latin letters, perform the following steps: concatenate s and t; calculate the prefix func…

实战打靶集锦-001-Funbox2

**写在前面&#xff1a;**这应该是本人第一次自主成功完成的打靶&#xff0c;纪念一下下。 目录1. 主机发现2. 端口扫描3. 服务枚举4. 服务探查4.1 Apache探查4.1.1 浏览器访问4.1.2 站点地图查看4.1.3 目录枚举4.1.4 公共EXP搜索4.2 FTP探查4.2.1 手工登录FTP4.2.2 公共EXP搜索…

基于决策树模型和支持向量机模型的手写数字识别

目录 1、导入库和手写数字数据集 2、 把数据可视化 3、把数据分成训练数据集和测试数据集 4、训练SVM模型 5、训练决策树模型 6、对所使用的模型进行评估 7、对手写数字图像进行预测 本项目实现了 第一个功能&#xff1a;可以通过导入库和数据集、通过对数据集的预处理…

JavaScript基础(17)_Function方法(call、apply)、arguments

概念 call&#xff0c;apply都属于Function.prototype的一个方法&#xff0c;它是JavaScript引擎内在实现的&#xff0c;因为属于Function.prototype&#xff0c;所以每个Function对象实例(就是每个方法)都有call&#xff0c;apply属性&#xff0c;可以通过函数对象来调用。 a…

2023牛客寒假算法基础集训营3 赛时思路+正解

这场数学和思维偏多&#xff0c;特别是数学&#xff0c;五个小时过于充实了&#xff0c;而且更加考验你的心态。 这场不乏码量大的毒瘤题&#xff0c;也不乏人类智慧妙妙题。 A 不断减损的时间 题意 给定一个数组aaa&#xff0c;我们可以执行任意次操作&#xff0c;该操作定义…

Rethinking Performance Gains in Image Dehazing Networks

论文源码&#xff1a;https://download.csdn.net/download/zhouaho2010/87393184 Abstract 图像去雾是低层视觉中的一个活跃话题&#xff0c;随着深度学习的快速发展&#xff0c;许多图像去雾网络被提出。尽管这些网络的工作良好&#xff0c;但提高图像去雾性能的关键机制仍不…

守望者的逃离

题目说明【问题描述】恶魔猎手尤迫安野心勃勃.他背叛了暗夜精灵&#xff0c;率深藏在海底的那加企图叛变&#xff1a;守望者在与尤迪安的交锋中遭遇了围杀.被困在一个荒芜的大岛上。为了杀死守望者&#xff0c;尤迪安开始对这个荒岛施咒&#xff0c;这座岛很快就会沉下去&#…

【java入门系列五】java基础-面向对象**

学习记录&#x1f914;类与对象内存中的布局堆栈成员方法 类内的函数传参机制传进来的是一个数组/对象&#xff0c;类似于py的list调用递归-在栈空间方法递归汉诺塔八皇后方法重载overload可变参数作用域**scope构造器/构造方法&#xff1a;新对象的初始化构造器细节对象创建流…

pytorch 笔记:torch.nn.init

这个模块中的所有函数都是用来初始化神经网络参数的&#xff0c;所以它们都在torch.no_grad()模式下运行&#xff0c;不会被autograd所考虑。 1 计算gain value 1.1 介绍 这个在后面的一些nn.init初始化中会用到 1.2 用法 torch.nn.init.calculate_gain(nonlinearity, para…

【LeetCode】回溯算法总结

回溯法解决的问题 回溯法模板 返回值&#xff1a;一般为void参数&#xff1a;先写逻辑&#xff0c;用到啥参数&#xff0c;再填啥参数终止条件&#xff1a;到达叶子节点&#xff0c;保存当前结果&#xff0c;返回遍历过程&#xff1a;回溯法一般在集合中递归搜索&#xff0c;集…

使用DiskGenius进行硬盘数据迁移

克隆硬盘 - DiskGenius 1.迁移磁盘 选择自己想要迁移的磁盘&#xff0c;点击工具-克隆磁盘 首先选择源硬盘&#xff0c;点击确定 之后选择想要迁移到的硬盘&#xff0c;点击确定 检查一下原硬盘和目标硬盘是否正确&#xff0c;此外还可以对这个空间进行二次调整。最终如果没有…

Android 中关于 FileObserver类监听文件状态的实践

文章目录需求背景走进源码实现示例参考需求背景 当某一个目录的文件发生变化&#xff08;创建、修改、删除、移动&#xff09;时&#xff0c;需要给一个回调事件给其他端调用。 其他场景&#xff1a;阅后即焚等等。 比如在 Android 的 VR 设备中&#xff0c;有一个用于部署的文…

Oracle P6 Professional专业版 22.12 中的热门新功能

目录 并排查看项目 在复制与 WBS 元素的关系时具有更大的灵活性 更轻松地确定要分配的正确基线 复制并粘贴电子表格中的单元格区域 更好地控制导入数据 检查 P6 专业版中提供的时间表报告 在排序对话框中排列字段顺序 创建导入和导出模板的副本 指定完成日期筛选器如何…

光流估计(一) 光流的简介与操作

今天是大年29&#xff0c;明天要贴春联了&#xff01;算是在年前赶出来一篇文章发&#xff08;太长时间没发东西了O。o&#xff09;&#xff0c;也算是自己在光流估计深度学习部分研究的开始~ 明年开学就是研二下学期了&#xff0c;时间过得飞快&#xff0c;毕设、实习、工作等…

MyBatis | 使用插件better-mybatis-generator自动生成dao、pojo

0️⃣简介&#x1f5fc;简介在我们编写MyBatis的项目时&#xff0c;常常需要为数据表编写大量的SQL语句以及dao类。better-mybatis-generator作为一款IDEA插件&#xff0c;可以自动为我们生成所需要的pojo类、dao类&#xff0c;并提供相当多的SQL单表查询操作。利用该插件&…

Python小技巧:富比较方法的妙用,__lt__、__le__、__eq__、__ne__、__gt__、__ge__。。。

前言 这里是Python小技巧的系列文章。这是第二篇&#xff0c;富比较方法的妙用。 在 Python中&#xff0c;富比较方法共6个&#xff0c;如下表所示&#xff1a; 见名知意&#xff0c;富比较主要用于比较。 富比较方法使用释义释义object.__lt__(self, other)x.__lt__(y)x<…

Springboot+mybatis使用PageHelper实现vue前端分页

Springbootmybatis使用PageHelper实现vue前端分页1、未分页前的vue前端效果图2、Springbootmybatis使用PageHelper分页逻辑&#xff1a;&#xff08;1&#xff09;Springboot、mybatis、PageHelper的版本&#xff1a;&#xff08;2&#xff09;yml文件配置pagehelper&#xff1…

带你了解docker是什么----初始篇

docker容器docker简介docker、虚拟环境与虚拟机docker 的核心概念Docker 镜像Docker 仓库Docker容器镜像、容器、仓库&#xff0c;三者之间的联系容器 容器一词的英文是container&#xff0c;其实container还有集装箱的意思&#xff0c;集装箱绝对是商业史上了不起的一项发明&…

11.3 关联容器操作

文章目录关联容器迭代器关键字成员不可修改&#xff0c;值可修改关于泛型算法添加元素向set插入元素向map插入数据insert操作总结检测insert的返回值展开递增语句向multiset和multimap添加元素删除元素map下标操作访问元素类型别名&#xff1a;类型别名说明key_type关键字类型&…

第一个Spring、第一个SpringBoot、Spring-Mybatis整合、SpringBoot-Mybatis整合

目录一、第一个Spring程序二、第一个SpringBoot三、Spring-Mybatis整合四、SpringBoot-Mybatis整合第一个程序一、第一个Spring程序 添加依赖——用以支持spring <dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</a…