数据结构与算法(五)栈的顺序存储结构

简介: 栈是限定仅在表尾进行插入和删除操作的线性表。我们将允许插入和删除的一端称为栈顶,另一端称为栈底。不含任何元素的栈称为空栈。栈又被称为先进后出的线性表。也就是说栈是一个特殊的线性表,其只在线性表的表尾进行添加删除数据操作,也就是说上边提到的栈底是固定的,添加删除操作只在栈顶进行。

QQ图片20220425220227.jpg

栈是限定仅在表尾进行插入和删除操作的线性表。


我们将允许插入和删除的一端称为栈顶,另一端称为栈底


不含任何元素的栈称为空栈


栈又被称为先进后出的线性表。


也就是说栈是一个特殊的线性表,其只在线性表的表尾进行添加删除数据操作,也就是说上边提到的栈底是固定的,添加删除操作只在栈顶进行。

 

栈的写入操作,叫做进栈,也称压栈或入栈。


栈的删除操作,叫做出栈,也称弹出栈。


栈限定了只在线性表的末尾进行数据写入删除操作,但是这并不意味着最先进栈的元素一定要最后出栈,这个要看具体情况,举个书上的小例子


【进栈出栈的变化形式】


如果3个整数1,2,3依次入栈,会有哪些出栈次序?


第一种:1-2-3进栈,即3-2-1出栈。


第二种:1进,1出,2斤,2出,3进,3出,进一个出一个,即1-2-3出栈。


第三种:1进,2进,2出,1出,3进,3出,即2-1-3出栈。


第四种:1进,1出,2进,3进,3出,2出,即1-3-2出栈。


第五种:1进,2进,2出,3进,3出,2出,即2-3-1出栈

 

下边我们来定义栈顺序存储结构的接口:


/// <summary>
    /// 栈接口
    /// </summary>
    /// <typeparam name="T"></typeparam>
    interface IStack<T>
    {
        /// <summary>
        /// 清空栈
        /// </summary>
        /// <returns></returns>
        bool ClearStack();
        /// <summary>
        /// 判断栈是否为空
        /// </summary>
        /// <returns>true:空、false:不空</returns>
        bool IsEmptyStack();
        /// <summary>
        /// 获取栈顶元素
        /// </summary>
        /// <returns></returns>
        T GetTopStack();
        /// <summary>
        /// 入栈
        /// </summary>
        /// <returns></returns>
        bool PushStack(T val);
        /// <summary>
        /// 出栈
        /// </summary>
        /// <returns></returns>
        bool PopStack();
        /// <summary>
        /// 获取栈长度
        /// </summary>
        /// <returns></returns>
        int LengthStack();
        /// <summary>
        /// 判断栈是否已满
        /// </summary>
        /// <returns></returns>
        bool IsFull();
        /// <summary>
        /// 打印栈
        /// </summary>
        void paint();
    }

 

定义一个类来实现这个接口:


首先定义三个全局变量


/// <summary>
        /// 顺序栈的容量(数组最大长度)
        /// </summary>
        private int maxsize;
        /// <summary>
        /// 数组,用于存储顺序栈中的数据元素
        /// </summary>
        private T[] data;
        /// <summary>
        /// 指示顺序栈的栈顶(top = -1 时表示栈为空)
        /// </summary>
        private int top;


这个和线性表(顺序存储结构)是一致的。


这里要说明一下顶栈top这个变量,当栈为空时,其为值-1,因此当想清空栈的时候,不需要将链表循环清空,只需将顶栈置为-1即可。


下方是我整个类的代码:具体调用的实例在文末,可下载:


public class StackList<T> : IStack<T>
    {
        /// <summary>
        /// 顺序栈的容量(数组最大长度)
        /// </summary>
        private int maxsize;
        /// <summary>
        /// 数组,用于存储顺序栈中的数据元素
        /// </summary>
        private T[] data;
        /// <summary>
        /// 指示顺序栈的栈顶(top = -1 时表示栈为空)
        /// </summary>
        private int top;
        /// <summary>
        /// 构造函数
        /// </summary>
        public StackList(int size)
        {
            data = new T[size];
            maxsize = size;
            top = -1;
        }
        /// <summary>
        /// 清空栈(这里不需要将数组清空,只要将顶栈赋值为-1就好)
        /// </summary>
        /// <returns></returns>
        public bool ClearStack()
        {
            top = -1;
            return true;
        }
        /// <summary>
        /// 获取栈顶
        /// </summary>
        /// <returns></returns>
        public T GetTopStack()
        {
            T res = data[top];
            return res;
        }
        /// <summary>
        /// 是否是空栈
        /// </summary>
        /// <returns></returns>
        public bool IsEmptyStack()
        {
            if (top == -1)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// 获取栈的长度
        /// </summary>
        /// <returns></returns>
        public int LengthStack()
        {
            return top + 1;
        }
        /// <summary>
        /// 出栈
        /// </summary>
        /// <returns></returns>
        public bool PopStack()
        {
            if (IsEmptyStack())
            {
                Console.WriteLine("栈为空,无法删除!");
                return false;
            }
            T temp = default(T);
            data[top] = temp;
            top--;
            return true;
        }
        /// <summary>
        /// 入栈
        /// </summary>
        /// <returns></returns>
        public bool PushStack(T val)
        {
            if (IsFull())
            {
                Console.WriteLine("栈已满,写入失败!");
                return false;
            }
            top++;
            data[top] = val;
            return true;
        }
        /// <summary>
        /// 判断栈是否已满
        /// </summary>
        /// <returns></returns>
        public bool IsFull()
        {
            if (top == maxsize - 1)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// 打印栈
        /// </summary>
        public void paint()
        {
            Console.WriteLine("栈顶:"+top);
            for (int i = 0; i < data.Length; i++)
            {
                Console.WriteLine("index:"+i + " | data:"+data[i]);
            }
        }
    }

 

顺序栈的操作和线性表顺序存储结构相比其实要简单,它的写入和删除操作只发生在表尾,因此在使用它的时候,大概参照线性表的顺序存储结构的用法就好了。


下图是具体调用的实例:


QQ图片20220425220230.jpg

 

两栈共享空间


栈还有一个在我看来比较高级的用法叫两栈共享空间。


大概是一个栈在表首,一个栈在表尾,每个栈都有一个顶栈。


当两个顶栈彼此相遇的时候,就证明两栈已满,无法再继续操作。


具体代码不在这里进行展示,文末有实例,可下载。


共享栈最后效果如下图所示


QQ图片20220425220233.png

 



目录
相关文章
|
10月前
|
存储 算法 C++
【C++数据结构——图】图的邻接矩阵和邻接表的存储(头歌实践教学平台习题)【合集】
本任务要求编写程序实现图的邻接矩阵和邻接表的存储。需掌握带权有向图、图的邻接矩阵及邻接表的概念。邻接矩阵用于表示顶点间的连接关系,邻接表则通过链表结构存储图信息。测试输入为图的顶点数、边数及邻接矩阵,预期输出为Prim算法求解结果。通关代码提供了完整的C++实现,包括输入、构建和打印邻接矩阵与邻接表的功能。
321 10
|
11月前
|
算法
【算法】栈
栈相关算法题,供参考,附有链接地址及板书
103 14
|
缓存 算法 Java
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
659 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
214 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
存储 安全 数据库
除了 HashMap,还有哪些数据结构可以实现键值对存储?
【10月更文挑战第11天】 除了`HashMap`,其他常见支持键值对存储的数据结构包括:`TreeMap`(基于红黑树,键有序)、`LinkedHashMap`(保留插入顺序)、`HashTable`(线程安全)、`B-Tree`和`B+Tree`(高效存储大量数据)、`SkipList`(通过跳跃指针提高查找效率)及`UnorderedMap`(类似`HashMap`)。选择合适的数据结构需根据排序、并发、存储和查找性能等需求。
|
12月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
257 59
|
5月前
|
编译器 C语言 C++
栈区的非法访问导致的死循环(x64)
这段内容主要分析了一段C语言代码在VS2022中形成死循环的原因,涉及栈区内存布局和数组越界问题。代码中`arr[15]`越界访问,修改了变量`i`的值,导致`for`循环条件始终为真,形成死循环。原因是VS2022栈区从低地址到高地址分配内存,`arr`数组与`i`相邻,`arr[15]`恰好覆盖`i`的地址。而在VS2019中,栈区先分配高地址再分配低地址,因此相同代码表现不同。这说明编译器对栈区内存分配顺序的实现差异会导致程序行为不一致,需避免数组越界以确保代码健壮性。
94 0
栈区的非法访问导致的死循环(x64)
232.用栈实现队列,225. 用队列实现栈
在232题中,通过两个栈(`stIn`和`stOut`)模拟队列的先入先出(FIFO)行为。`push`操作将元素压入`stIn`,`pop`和`peek`操作则通过将`stIn`的元素转移到`stOut`来实现队列的顺序访问。 225题则是利用单个队列(`que`)模拟栈的后入先出(LIFO)特性。通过多次调整队列头部元素的位置,确保弹出顺序符合栈的要求。`top`操作直接返回队列尾部元素,`empty`判断队列是否为空。 两题均仅使用基础数据结构操作,展示了栈与队列之间的转换逻辑。
|
10月前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
429 77

热门文章

最新文章