zoukankan      html  css  js  c++  java
  • 数据结构与算法:堆栈

    一、堆栈

    堆栈(Stack)是一组相同数据类型的组合,所有的操作均在堆栈的顶端进行,具有“先进后出”(First In Last Out,FILO)的特性。堆栈结构在计算机中的应用相当广泛,时常被用来解决计算机的问题,例如递归调用,子程序的调用等。堆栈的数据结构原理,类似于下图:

    1、堆栈简介

    谈到先进后出(First In Last Out)的概念,其实就如同自助餐中餐盘由桌面网上一个一个叠放,且取用时由最上面先拿,这就是典型堆栈概念的应用。由于堆栈是一种抽象数据结构(Abstract Data Type),它有一下特性:

    1. 只能从堆栈的顶端存取数据。
    2. 数据的存取符合“先进后出”的原则。

    可以参考下面的堆栈操作示意图:

    堆栈的基本运算入下表所示:

    create 创建一个空堆栈
    push 把数据存压入堆栈顶端,并返回新堆栈
    pop 从堆栈顶端弹出数据,并返回新堆栈
    isEmpty 判断堆栈是否为空堆栈,是则返回true,不是则返回false
    full 判断堆栈是否已满,是则返回true,不是则返回false

    堆栈在程序设计领域中,包含数组结构与链表结构两种设计方式,下面分别介绍。

    二、使用数组来实现堆栈

    以数组结构来实现堆栈的好处是设计的算法都相当简单,但是如果堆栈本身的大小是变动的,而数组的大小只能事先定义好,那么数组规划太大了又浪费空间,规划太小了则又不够用。看下面的一个示例:使用数组结构来设计一个C#程序,并使用循环来控制准备压入或弹出的元素,模仿堆栈的各种操作,其中必须包括压入(push)与弹出(pop)方法,最后还要输出堆栈内所有的元素。代码如下:

    定义堆栈类:

    using System;
    
    namespace StackByArray
    {
        public class StackArray
        {
            // 使用数组来模拟堆栈的声明
            private int[] Stack;
            // 定义指向堆栈顶端的指针
            private int top;
    
            // 构造函数
            public StackArray(int stackSize)
            {
                // 建立数组
                Stack = new int[stackSize];
                // 数组的索引从0开始,当数组为空时,堆栈的顶端指针为-1
                top = -1;
            }
    
            /// <summary>
            /// 入栈 把指定的数据压入堆栈顶端
            /// </summary>
            /// <param name="data"></param>
            /// <returns></returns>
            public bool Push(int data)
            {
                // 判断堆栈顶端的索引是否大于数组大小
                if(top>=Stack.Length)
                {
                    Console.WriteLine("堆栈已满,无法在加入");
                    return false;
                }
                else
                {
                    // 将数据压入堆栈,同时top上移一位
                    Stack[++top] = data;
                    return true;
                }
            }
    
            /// <summary>
            /// 判断堆栈是否为空堆栈,如果是则返回true,否则返回false
            /// </summary>
            /// <returns></returns>
            public bool IsEmpty()
            {
                return top == -1 ? true : false;
            }
    
            /// <summary>
            /// 出栈 从堆栈的顶端弹出数据
            /// </summary>
            /// <returns></returns>
            public int Pop()
            {
                if(IsEmpty())
                {
                    return -1;
                }
                else
                {
                    // 先将数据弹出,然后在将堆栈指针下移
                    return Stack[top--];
                }
            }
        }
    }

    在Main方法中调用:

    using System;
    
    namespace StackByArray
    {
        class Program
        {
            static void Main(string[] args)
            {
                int value;
                StackArray stack = new StackArray(10);
                Console.WriteLine("按顺序输入10个数:");
                for (int i = 0; i < 10; i++)
                {
                    value = int.Parse(Console.ReadLine());
                    // 入栈
                    stack.Push(value);
                }
                Console.WriteLine("=================");
                while(!stack.IsEmpty())
                {
                    Console.WriteLine($"堆栈弹出顺序:{stack.Pop()}");
                }
    
                Console.ReadKey();
            }
        }
    }

    程序输出结果:

    三、使用链表来实现堆栈

    虽然以数组结构来制作堆栈的好处是制作与设计的算法都相当简单,但是如果堆栈本身是变动的话,数组大小就无法事先规划声明。此时往往会考虑使用最大可能性的数组空间,但是这将造成内存空间的浪费,而用链表来制作堆栈的优点是随时可以动态改变链表的长度,不过缺点是设计时算法较为复杂。下面我们用链表来实现堆栈。

    Node节点类:

    namespace StackByLinked
    {
        /// <summary>
        /// 节点
        /// </summary>
        public class Node
        {
            public int Data { get; set; }
    
            public Node Next { get; set; }
    
            public Node(int data)
            {
                Data = data;
                Next = null;
            }
        }
    }

    堆栈类:

    using System;
    
    namespace StackByLinked
    {
        public class StackLinked
        {
            // 定义指向堆栈底端的指针
            public Node Front;
            // 定义指向堆栈顶端的指针
            public Node Rear;
    
            /// <summary>
            /// 判断堆栈是否为空堆栈
            /// </summary>
            /// <returns></returns>
            public bool IsEmpty()
            {
                return Front == null;
            }
    
            /// <summary>
            /// 打印输出堆栈的内容
            /// </summary>
            public void Print()
            {
                Node current = Front;
                while(current!=null)
                {
                    Console.Write(current.Data + " ");
                    current = current.Next;
                }
                Console.WriteLine();
            }
    
            /// <summary>
            /// 入栈
            /// </summary>
            /// <param name="data"></param>
            /// <returns></returns>
            public void Push(int data)
            {
                Node newNode = new Node(data);
                if(IsEmpty())
                {
                    Front = newNode;
                    Rear = newNode;
                }
                else
                {
                    Rear.Next = newNode;
                    Rear = newNode;
                }
            }
    
            /// <summary>
            /// 出栈 返回栈顶元素
            /// </summary>
            /// <returns></returns>
            public int Pop()
            {
                Node newNode;
                if(IsEmpty())
                {
                    Console.WriteLine("当前为空队列");
                    return -1;
                }
                newNode = Front;
                if(newNode == Rear)
                {
                    Front = null;
                    Rear = null;
                    Console.WriteLine("当前为空队列");
                    return -1;
                }
                else
                {
                    while(newNode.Next!=Rear)
                    {
                        newNode = newNode.Next;
                    }
                    int value = Rear.Data;
                    // newNode被null赋值,相当于移除了Rear
                    newNode.Next = Rear.Next;
                    Rear = newNode;
                    return value;
                }
            }
        }
    }

    Main方法调用:

    using System;
    
    namespace StackByLinked
    {
        class Program
        {
            static void Main(string[] args)
            {
                StackLinked stack = new StackLinked();
                int choice = 0;
                while(true)
                {
                    Console.Write("0结束 1把数据加入堆栈 2从堆栈弹出数据:");
                    choice = int.Parse(Console.ReadLine());
                    if(choice==2)
                    {
                        int value= stack.Pop();
                        Console.WriteLine($"弹出的栈顶元素:{value}");
                        Console.WriteLine("数据弹出后堆栈中的内容");
                        stack.Print();
                    }
                    else if(choice == 1)
                    {
                        Console.WriteLine("请输入要加入堆栈的数据:");
                        choice = int.Parse(Console.ReadLine());
                        stack.Push(choice);
                        Console.WriteLine("数据加入后堆栈中的内容:");
                        stack.Print();
                    }
                    else if(choice == 0)
                    {
                        break;
                    }
                    else
                    {
                        Console.WriteLine("输入错误");
                    }
                }
    
                Console.ReadKey();
            }
        }
    }

    程序运行结果:

  • 相关阅读:
    2020.2.14
    2020.2.13
    规划极限编程阅读笔记03
    学习进度——第十六周
    JSP跳转到Servlet的两种配置
    规划极限编程阅读笔记02
    规划极限编程阅读笔记01
    单词接龙
    学习进度——第十五周
    输入法评价
  • 原文地址:https://www.cnblogs.com/dotnet261010/p/12324551.html
Copyright © 2011-2022 走看看