栈和队列,及其低层实现

一.栈

1)栈的概念:栈是操作限定在表的尾端进行的线性表。表尾由于要进行插入、删除等操作,所以,它具有特殊的含义,把表尾称为栈顶,另一端是固定的,叫栈底。当栈中没有数据元素时叫作空栈。
2)栈的特点:先进后出
3)栈的好处:单纯从功能上讲,数组或者链表可以替代栈。它们的操作过于灵活,,当数据量很大的时候就会出现一些隐藏的风险。虽然栈限定降低了操作的灵活性,但这也使得栈在处理只涉及一端新增和删除数据的问题时效率更高,更不容易出错。

1. 顺序栈

(1)顺序栈的概念:用一片连续的存储空间来存储栈中的数据元素(使用数组),这样的栈称为顺序栈。类似于顺序表,用一维数组来存放顺序栈中的数据元素。栈顶指示器 top 设在数组下标为 0 的端, top 随着插入和删除而变化,当栈为空时,top=-1。下图是顺序栈的栈顶指示器 top 与栈中数据元素的关系图。

在这里插入图片描述

(2)顺序栈的实现:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 栈和队列
{
    /// <summary>
    /// 顺序栈
    /// </summary>
    /// <typeparam name="T"></typeparam>
    class StackSelf<T>
    {
        //  int Count { get; }//栈中元素的个数
        //void Push(T item); //入栈操作
        //T Pop(); //出栈操作
        //T Peek(); //取栈顶元素
        //bool IsEmpty(); //判断栈是否为空
        // void Clear(); //清空操作

        private int top;
        private T[] stack;
        public int Count { get => top + 1; }
       
        public int Capacity { get => stack.Length; }//容量,用于扩容
        public StackSelf()
        {
            stack = new T[4];
            top = -1;
        }
        public StackSelf(int size)
        {
            stack = new T[size];
            top = -1;
        }
        public void Push(T item) //入栈操作
        {
            //扩容
            if (Count == Capacity)
            {
                T[] newstack = new T[Count * 2];
                Array.Copy(stack, newstack, Count);
                stack = newstack;
            }
           
                stack[top+1] = item;
                top++;
            

        }
        public T Pop() //出栈操作
        {
            if (top == -1)
            {
                throw new Exception("现为空栈");
            }
            top--;
            return stack[top + 1];
        }

        public T Peek()//取栈顶元素
        {
          return stack[top];
        }

        public bool IsEmpty() //判断栈是否为空
        {
            if (top==-1)
            {
                return true;
            }
            return false;
        }

        public void Clear()//清空操作
        {
            top = -1;
        }
    }
}

链栈

(1)链栈通常用单链表来表示,它的实现是单链表的简化。栈顶放在单链表头部,即不需要头指针,使用head指针代替。增加与删除操作在头部即head指向处进行。
(2)在链栈中进行删除操作时,只能在栈顶进行操作。因此,将栈顶的head指针指向栈顶节点(head)的next指针即可完成删除。具体操作可看代码实现

节点代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 栈和队列
{
    /// <summary>
    /// 节点类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    class StackNode<T>
    {
        private T data;
        private StackNode<T> next;

        public StackNode()
        {
            Data = default(T);
            Next = null;
        }
        public StackNode(T item)
        {
            Data = item;
            Next = null;

        }
        public T Data { get => data; set => data = value; }
        internal StackNode<T> Next { get => next; set => next = value; }
    }
}

链栈代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 栈和队列
{
    /// <summary>
    /// 链栈
    /// </summary>
    /// <typeparam name="T"></typeparam>
    class ChainStackSelf<T>
    {
        //  int Count { get; }//栈中元素的个数
        //void Push(T item); //入栈操作
        //T Pop(); //出栈操作
        //T Peek(); //取栈顶元素
        //bool IsEmpty(); //判断栈是否为空
        // void Clear(); //清空操作

        private StackNode<T> top;//栈顶元素节点
        private int count;
        public int Count { get => count;}

        public ChainStackSelf()
        {
            top = null;
            count = 0;
        }

       public void Push(T item) //入栈操作
        {
            StackNode<T> node = new StackNode<T>(item);
            if (top==null)
            {            
                top = node;
            }
            else
            {//让新节点指向原顶部节点,然后在把新节点的位置赋予给新结点,
             //如此top永远是顶部节点,后续操作访问栈顶就很方便

                node.Next = top;
                top = node;
            }
            count++;
        }

        public T Pop() //出栈操作
        {
            if (count==0)
            {
                throw new Exception("现为空栈");
            }

            T data = top.Data;
            top = top.Next;
            count--;
            return data;
        }

        public T Peek()//取栈顶元素
        {
            return top.Data;
        }

        public bool IsEmpty() //判断栈是否为空
        {
            
            return Count==0;
        }

        public void Clear()//清空操作
        {
            top = null;
            count = 0;
        }
    }
}

栈的应用:递归,进制转换,匹配,表达式求值等

二.队列

1)队列的基本概念:队列是插入操作限定在表的尾部而其它操作限定在表的头部进行的线性表。把进行插入操作的表尾称为队尾,把进行其它操作的头部称为队头。当队列中没有数据元素时称为空队列

2)队列的特点:先进先出
3)队列的好处:与栈类似,只是两者的特点不同

1 顺序队列

顺序队列的概念:用一片连续的存储空间来存储队列中的数据元素,这样的队列称为顺序队列。类似于顺序栈,用一维数组来存放顺序队列中的数据元素。队头位置设在数组下标为 0 的端,用 front 表示;队尾位置设在数组的另一端,用 rear 表示。 front 和 rear 随着插入和删除而变化。当队列为空时, front=rear=-1。
在这里插入图片描述
特殊的,如图(d)如果此时再有一个数据元素入队就会出现溢出。但事实上队列中并未满,还有空闲空间,把这种现象称为“假溢出”。解决办法就是把它看成一个首尾相连的循环队列,也就是当队尾(rear)到达数组顶部时但队列中的元素还未饱和,此时添加元素,则把队尾(rear)重新归置为-1,再进行入队操作,但使用这种方法顺序队列就失去了自动扩容功能,具体实现看代码。

顺序队列的实现

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 队列
{
    /// <summary>
    /// 顺序队列
    /// </summary>
    /// <typeparam name="T"></typeparam>
    class QueueSelf<T>
    {
        private T[] data;
        private int head;//队头
        private int tail;//队尾
        private int count;//队列的元素个数
        public int Count { get => count; }

        public QueueSelf()
        {
            data = new T[4];
            head = -1;
            tail = -1;
            count = 0;
        }

        public QueueSelf(int size)
        {
            data = new T[size];
            head = -1;
            tail = -1;
            count = 0;
        }
       
        //        int Count { get; }//取得队列长度的属性
        //        void Enqueue(T item); //入队
        //        T Dequque(); //出队
        //        T Peek(); //取队头元素
        //        bool IsEmpty(); //判断对列是否为空
        //        void Clear(); //清空队列

        public void Enqueue(T item) //入队
         {
            if (Count == data.Length)
            {
                throw new Exception("队列已满");
            }
            else
            {
                //如果队尾已经到达数组顶端,队列中元素还未满
                则说明存在假溢出现象需要特殊处理
                if (tail == data.Length - 1)
                {
                    tail = -1;
                    data[tail + 1] = item;
                    tail++;
                }
                else
                {
                    data[tail + 1] = item;
                    tail++;
    
                }
                count++;
            }
        }

        public T Dequque() //出队
        {
            if (Count==0)
            {
                throw new Exception("队列为空");
            }
            else
            {
                //如果队头到达数组顶部,队列的元素个数Count还不为零,
                //则说明存在假溢出现象需要特殊处理
                if (head == data.Length - 1&&Count!=data.Length)
                {
                    head = -1;
                }
                T temp = data[head + 1];
                head++;
                count--;
                return temp;
            }
        }

        public T Peek() //取队头元素
        {
            if (Count == 0)
            {
                throw new Exception("队列为空");
            }
            else
            {
                //如果队头到达数组顶部,队列的元素个数Count还不为零,
                //则说明存在假溢出现象需要特殊处理
                if (head == data.Length - 1 && Count != data.Length)
                {
                    head = -1;
                }
                T temp = data[head + 1];              
                return temp;
            }

        }

        public bool IsEmpty() //判断对列是否为空
        {

            return Count == 0;
        }

        public void Clear() //清空队列
        {
            head = -1;
            tail = -1;
            count = 0;
        }
    }
}

链式队列

链式队列的概念:链式队列就是一个单链表,由于链队列的操作只是在一端进行,为了操作方便,把队头设在链表的头部,并且不需要头结点。

新增操作:链式队列进行新增数据操作时,将拥有数值item的新结点 newnode 赋值给原队尾结点的后继,即 tail.next。然后把当前的newnode 设置为队尾结点,指针 tail指向 newnode 。如下图所示:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

删除操作:只需要让头结点指向要删除结点的后继,特殊的删除最后一个节点需要队头和队尾指针置空。具体操作看代码实现。

链式队列的实现:

节点实现:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 队列
{
    class Node<T>
    {
        T data;
        Node<T> next;
        
        public T Data { get => data; set => data = value; }
        internal Node<T> Next { get => next; set => next = value; }

        public Node(T item)
        {
            data = item;
            next = null;
        }
    }
}

链队列实现:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 队列
{
    class ChainQueue<T>
    {
     
        private Node<T> head;//队头
        private Node<T> tail;//队尾
        private int count;//队列的元素个数
        public int Count { get => count; }

        public ChainQueue()
        {
           
            head = null;
            tail = null;
            count = 0;
        }


        //        int Count { get; }//取得队列长度的属性
        //        void Enqueue(T item); //入队
        //        T Dequque(); //出队
        //        T Peek(); //取队头元素
        //        bool IsEmpty(); //判断对列是否为空
        //        void Clear(); //清空队列

        public void Enqueue(T item) //入队
        {

            Node<T> newnode = new Node<T>(item);
            if (Count==0)
            {
                head = newnode;
                tail = newnode;
              
            }
           
            else
            {
                tail.Next = newnode;
                tail = newnode;
            }
            count++;
        }

        public T Dequque() //出队
        {
            if (Count == 0)
            {
                throw new Exception("队列为空");
            }
            else if (Count == 1)
            {

                T temp = head.Data;
                head = null;
                tail = null;
                count--;
                return temp;
            }
            else
            {
                T temp = head.Data;
                head = head.Next;
                count--;
                return temp;
            }
        }

        public T Peek() //取队头元素
        {
            if (Count == 0)
            {
                throw new Exception("队列为空");
            }
           
            else
            {
                             
                return head.Data;
            }

        }

        public bool IsEmpty() //判断对列是否为空
        {

            return Count == 0;
        }

        public void Clear() //清空队列
        {
            head =null;
            tail = null;
            count = 0;
        }

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值