数据结构与算法(六)栈的链式存储结构

简介: 栈的链式存储结构,简称为链栈。栈的链式存储结构与线性表的链式存储结构差不多,但是其相对比较简单,只在表尾进行操作。

QQ图片20220425220708.jpg

栈的链式存储结构,简称为链栈。


想想看,栈只是栈顶来做插入和删除操作,栈顶放在链表的头部还是尾部呢?


由于单链表有头指针,而栈顶指针也是必须的,那么干嘛不让他们合二为一呢,所以比较好的办法是把栈顶放到单链表的头部。


另外栈顶在头部了,那么单链表的头结点也就失去了意义,通常对于链栈来说,是不需要头结点的。


同样对于链栈来说,基本不存在栈满的情况,除非内存已经没有可用的空间了。


栈的链式存储结构与线性表的链式存储结构差不多,但是其相对比较简单,只在表尾进行操作。


刚好复习下之前学习的线性表中的链表。


但是链栈和线性表的链式存储结构是有区别的,链栈不需要头结点,有栈顶就可以了。


首先定义一个链栈的接口:


/// <summary>
    /// 链栈接口
    /// </summary>
    public interface IChainStack<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>
    public class ChainStackNode<T>
    {
        /// <summary>
        /// 链表中的数据域
        /// </summary>
        public T data;
        /// <summary>
        /// 链表中的下一个节点的指针域
        /// </summary>
        public ChainStackNode<T> Next;
        // 每个结点有两部分组成,指针+数据,第一个节点没有数据,只有指针,最后一个节点只有数据,没有指针。
        // 那么构造函数需要有三次重载。
        /// <summary>
        /// 中间节点构造函数
        /// </summary>
        /// <param name="val"></param>
        /// <param name="index"></param>
        public ChainStackNode(T val, ChainStackNode<T> index)
        {
            this.data = val;
            this.Next = index;
        }
        /// <summary>
        /// 最后一个节点构造函数
        /// </summary>
        /// <param name="val"></param>
        public ChainStackNode(T val)
        {
            this.data = val;
            this.Next = null;
        }
        /// <summary>
        /// 第一个节点构造函数
        /// </summary>
        /// <param name="val"></param>
        /// <param name="index"></param>
        public ChainStackNode(ChainStackNode<T> index)
        {
            // 默认值
            this.data = default(T);
            this.Next = index;
        }
        /// <summary>
        /// 定义一个空节点
        /// </summary>
        /// <param name="val"></param>
        /// <param name="index"></param>
        public ChainStackNode()
        {
            this.data = default(T);
            this.Next = null;
        }
    }

 

最后我们定义一个类来实现上边定义的接口;实现链栈的操作功能。


public class ChainStackList<T> : IChainStack<T>
    {
        /// <summary>
        /// 存储栈顶指针,其是有指针,没有数据
        /// </summary>
        public ChainStackNode<T> top = null;
        /// <summary>
        /// 栈数量
        /// </summary>
        public int count = 0;
        public ChainStackList()
        {
            top = new ChainStackNode<T>();
            count = 0;
        }
        /// <summary>
        /// 清空栈
        /// </summary>
        /// <returns></returns>
        public bool ClearStack()
        {
            count = 0;
            top = null;
            return true;
        }
        /// <summary>
        /// 获取栈顶数据
        /// </summary>
        /// <returns></returns>
        public T GetTopStack()
        {
            return top.Next.data;
        }
        /// <summary>
        /// 栈是否为空
        /// </summary>
        /// <returns></returns>
        public bool IsEmptyStack()
        {
            if (top.Next == null || count == 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// 栈是已满,链接基本上不存在满栈的情况,因为满栈基本上意味着系统崩溃
        /// </summary>
        /// <returns></returns>
        public bool IsFull()
        {
            if (top == null)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// 获取栈长度
        /// </summary>
        /// <returns></returns>
        public int LengthStack()
        {
            return count;
        }
        /// <summary>
        /// 打印栈
        /// </summary>
        public void paint()
        {
            ChainStackNode<T> tempTop = top;
            ChainStackNode<T> temp = new ChainStackNode<T>();
            for (int i = 0; i < count+1; i++)
            {
                temp = tempTop.Next;
                Console.WriteLine("data:"+ tempTop.data+"index:"+top.Next);
                tempTop = temp;
            }
        }
        /// <summary>
        /// 出栈
        /// </summary>
        /// <returns></returns>
        public bool PopStack()
        {
            if (IsEmptyStack())
            {
                Console.WriteLine("链栈为空,无法弹出");
                return false;
            }
            // 定义一个节点存储栈顶的下一个节点
            ChainStackNode<T> temp = top.Next;
            // 现在栈顶的下一个节点等于原来栈顶下一个节点的先一个节点
            top.Next = temp.Next;
            count--;
            return true;
        }
        /// <summary>
        /// 入栈
        /// </summary>
        /// <param name="val">入栈数据</param>
        /// <returns></returns>
        public bool PushStack(T val)
        {
            ChainStackNode<T> temp = new ChainStackNode<T>(val);
            if (temp == null)
            {
                Console.WriteLine("栈已满");
                return false;
            }
            // 将栈顶的下一个节点赋值给新节点
            temp.Next = top.Next;
            // 将新节点赋值给栈顶的下一个值
            top.Next = temp;
            count++;
            return true;
        }
    }

 

调用示例:


static void Main(string[] args)
        {
            ChainStackList<string> chainStrackList = new ChainStackList<string>();
            chainStrackList.PushStack("11111");
            chainStrackList.PushStack("22222");
            chainStrackList.PushStack("33333");
            chainStrackList.PushStack("44444");
            chainStrackList.PushStack("55555");
            Console.WriteLine("添加数据");
            Console.WriteLine("=========================================");
            Console.WriteLine("打印数据");
            chainStrackList.paint();
            Console.WriteLine("=========================================");
            chainStrackList.PopStack();
            chainStrackList.PopStack();
            Console.WriteLine("弹出栈");
            Console.WriteLine("=========================================");
            Console.WriteLine("打印数据");
            chainStrackList.paint();
            Console.WriteLine("=========================================");
            Console.WriteLine("获取栈顶数据:"+ chainStrackList.GetTopStack());
            Console.WriteLine("=========================================");
            Console.WriteLine("获取栈的长度:" + chainStrackList.LengthStack());
            Console.WriteLine("=========================================");
            Console.ReadKey();
        }


QQ图片20220425220710.png


如上图所示:


在写链栈的时候,只需要搞清楚一件事情就可以了,栈顶top存储的是事实上的栈顶的指针。


Top.Next = 真正的栈顶。


那么添加数据时:


newNode.Next = top.Next;// 将栈顶的下一个节点赋值给新节点
top.Next = newNode;// 将新节点赋值给栈顶的下一个节点

 

删除数据时:


Temp = top.Next;// 定义一个节点存储栈顶的下一个节点
Top.next = temp.next;// 现在栈顶的下一个节点等于原来栈顶下一个节点的先一个节点

 

以上基本上就是链栈的精髓所在,最后放上一张上边代码最终运行的效果图:代码实例在文末,可下载。


QQ图片20220425220712.png

 



目录
相关文章
|
15天前
|
消息中间件 存储 搜索推荐
深入理解栈和队列(二):队列
深入理解栈和队列(二):队列
29 0
|
14天前
|
负载均衡 算法 应用服务中间件
面试题:Nginx有哪些负载均衡算法?Nginx位于七层网络结构中的哪一层?
字节跳动面试题:Nginx有哪些负载均衡算法?Nginx位于七层网络结构中的哪一层?
31 0
|
25天前
|
存储 NoSQL 算法
【Redis技术进阶之路】「底层源码解析」揭秘高效存储模型与数据结构底层实现(字典)(二)
【Redis技术进阶之路】「底层源码解析」揭秘高效存储模型与数据结构底层实现(字典)
36 0
|
8天前
|
存储 算法 调度
数据结构期末复习(3)栈和队列
数据结构期末复习(3)栈和队列
16 0
|
16天前
|
存储 算法
【算法与数据结构】深入解析二叉树(二)之堆结构实现
【算法与数据结构】深入解析二叉树(二)之堆结构实现
|
20天前
|
存储 缓存 算法
【算法与数据结构】栈的实现详解
【算法与数据结构】栈的实现详解
|
20天前
|
存储 算法 编译器
【数据结构】栈算法(算法原理+源码)
【数据结构】栈算法(算法原理+源码)
【数据结构】栈算法(算法原理+源码)
|
24天前
|
存储
【数据结构】什么是栈?
【数据结构】什么是栈?
26 0
【数据结构】什么是栈?
|
24天前
|
存储 C语言
【数据结构】线性表的链式存储结构
【数据结构】线性表的链式存储结构
18 0
|
24天前
|
存储 vr&ar
数据结构的图存储结构
数据结构的图存储结构
25 0