栈及其在.NET FrameWork中的源码分析

简介:

1.栈是操作限定在表的尾端进行的线性表,表尾要进行插入,删除等操作。我们把表尾称为栈顶,另一端叫做栈底。栈的操作是按照后进先出(LIFO:Last
In First Out)或是先进后出(FILO)的原则进行的,所以也叫做LIFO表或FILO表。
clip_image002

2.我们将栈的几个常用操作用接口表示如下:

public interface IStack<T>

{

        int GetLength();

        bool IsEmpty();

        void Clear();

        void Push(T item);//入栈

        T Pop();//出栈

        T GetTop()
}

3.使用连续空间来存储栈中的元素我们称为顺序栈,我们就实现一个简单的顺序栈,代码如下:

public class SeqStack<T>:IStack<T>

    {

        private int maxsize;

        private T[] data;

        private int top;

 

        public T this[int index]

        {

            get { return data[index];}

            set { data[index] = value; }

        }

 

        public int Maxsize

        {

            get { return maxsize; }

            set { maxsize = value; }

        }

        public int Top

        {

            get { return top; }

            set { top = value; }

        }

 

        public SeqStack(int size)

        {

            data = new T[size];

            maxsize = size;

            top = -1;

        }

 

        public int GetLength()

        {

            return top + 1;

        }

        public void Clear()

        {

            top = -1;

        }

        public bool IsEmpty()

        {

            if (top == -1)

                return true;

            else

                return false;

        }

        public bool IsFull()

        {

            if (top == maxsize - 1)

                return true;

            else

                return false;

        }

        public void Push(T item)

        {

            if (IsFull())

            {

                Console.WriteLine("Stack is full");

                return;

            }

            data[++top] = item;

        }

 

        public T Pop()

        {

            T tmp = default(T);

            if (IsEmpty())

            {

                Console.WriteLine("Stack is empty");

                return tmp;

            }

            tmp = data[top];

            --top;

            return tmp;

        }

        public T GetTop()

        {

            if (IsEmpty())

            {

                Console.WriteLine("Stack is empty");

                return default(T);

            }

            return data[top];

        }

    }

 

4.还有一种就是链式存储,实际上就是简化的单链表,节点和单链表的节点也是一样的如下:

public class Node<T>

    {

        private T data;

        private Node<T> next;

 

        public Node(T val, Node<T> p)

        {

            data = val;

            next = p;

        }

        public Node(Node<T> p)

        {         

            next = p;

        }

        public Node()

        {

            data = default(T);

            next = null;

        }

 

        public T Data

        {

            get { return data; }

            set { data = value; }

        }

        public Node<T> Next

        {

            get { return next; }

            set { next = value; }

        }

}

链栈的实现如下:

public class LinkStack<T>:IStack<T>

    {

        public Node<T> top;

        private int num;//栈中结点个数

 

        public Node<T> Top

        {

            get { return top; }

            set { top = value; }

        }

        public int Num

        {

            get { return num; }

            set { num = value; }

        }

        public LinkStack()

        {

            top=null;

            num=0;

        }

 

        public int GetLength()

        {

            return num;

        }

        public void Clear()

        {

            top = null;

            num = 0;

        }

        public bool IsEmpty()

        {

            if ((top == null) && (num == 0))

                return true;

            else

                return false;

        }

        public void Push(T item)

        {

            Node<T> q = new Node<T>(item);

            if (top == null)

                top = q;

            else

            {

                q.Next = top;

                top = q;

            }

            ++num;

        }

        public T Pop()

        {

            if (IsEmpty())

            {

                Console.WriteLine("Stack is empty");

                return default(T);

            }

            Node<T> p = top;

            top = top.Next;

            --num;

            return p.Data;

        }

        public T GetTop()

        {

            if (IsEmpty())

            {

                Console.WriteLine("Stack is empty");

                return default(T);

            }

            return top.Data;

        }

 

    }

5.上面是我们实现的简单的方式,我们下面来看下。Net Framework中的实现方式。C#类库中提供了泛型和非泛型版本的Stack类,主要继承
了IEnumerable和ICollection接口。

我们可以使用Reflector来查看下。Net Framework的实现方式,我们主要看泛型版本Stack<T>

public class Stack<T> : IEnumerable<T>, ICollection, IEnumerable

在。Net Framework中的Stack中的数据以数组形式存在,当数据空间不够时,扩大1倍空间,将数据从原有缓冲区复制到新的缓冲区中会带来O(n)的数据
复制开销,最坏可能带来sizeof(T)*(n-1)的空间浪费。数据Push,Pop的复杂度为O(1)。

我们来看下Push操作,当空间不够的时候会扩大一倍的空间。有数组复制的开销:  public void Push(T item)

 

    {

        if (this._size == this._array.Length)

        {

            T[] destinationArray = new T[(this._array.Length == 0) ? 4 : (2 * this._array.Length)];

            Array.Copy(this._array0, destinationArray, 0this._size);

            this._array = destinationArray;

        }

        this._array[this._size++] = item;

        this._version++;

    }

另外在Pop的时候,可能出现Stack中只有一个元素,有数组的数据都在,这时就浪费了空间,我们可以使用提供的下面函数来释放,如果元素数小于
当前容量的 90%,将容量设置为 Stack<(Of <(T>)>) 中的实际元素数。

public void TrimExcess()

    {

        int num = (int) (this._array.Length * 0.9);

        if (this._size < num)

        {

            T[] destinationArray = new T[this._size];

            Array.Copy(this._array0, destinationArray, 0this._size);

            this._array = destinationArray;

            this._version++;

        }

    }

6.栈,堆区别

栈负责保存我们的代码执行(或调用)路径,而堆则负责保存对象或者说数据。

NET框架包含一个托管堆,所有的.NET语言在分配引用类型对象时都要使用它。像值类型这样的轻量级对象始终分配在栈中,但是所有的类实例和
数组都被生成在一个内存池中,这个内存池就是托管堆。
垃圾收集器的基本算法很简单:
● 将所有的托管内存标记为垃圾
● 寻找正被使用的内存块,并将他们标记为有效
● 释放所有没有被使用的内存块
● 整理堆以减少碎片


本文转自生鱼片博客园博客,原文链接:http://www.cnblogs.com/carysun/archive/2009/10/09/Stack.html,如需转载请自行联系原作者

相关文章
|
3月前
使用的是.NET Framework 4.0,并且需要使用SMTP协议发送电子邮件
使用的是.NET Framework 4.0,并且需要使用SMTP协议发送电子邮件
68 1
|
3月前
|
开发框架 缓存 监控
NET Framework 到 .NET 5/6 的迁移是重大的升级
本文详细介绍了从 .NET Framework 4.8 迁移到 .NET 5/6 的过程,通过具体案例分析了迁移策略与最佳实践,包括技术栈评估、代码迁移、依赖项更新及数据库访问层的调整,强调了分阶段迁移、保持代码可维护性及性能监控的重要性。
73 3
|
3月前
|
机器学习/深度学习 编解码 算法
【小样本图像分割-4】nnU-Net: Self-adapting Framework for U-Net-Based Medical Image Segmentation
《nnU-Net: 自适应框架用于基于U-Net的医学图像分割》是一篇2018年的论文,发表在Nature上。该研究提出了一种自适应的医学图像分割框架nnU-Net,能够自动调整模型的超参数以适应不同的数据集。通过2D和3D U-Net及级联U-Net的组合,nnU-Net在10个医学分割数据集上取得了卓越的性能,无需手动调整。该方法强调数据增强、预处理和训练策略等技巧,为医学图像分割提供了一个强大的解决方案。
122 0
【小样本图像分割-4】nnU-Net: Self-adapting Framework for U-Net-Based Medical Image Segmentation
winform .net6 和 framework 的图表控件,为啥项目中不存在chart控件,该如何解决?
本文讨论了在基于.NET 6和.NET Framework的WinForms项目中添加图表控件的不同方法。由于.NET 6的WinForms项目默认不包含Chart控件,可以通过NuGet包管理器安装如ScottPlot等图表插件。而对于基于.NET Framework的WinForms项目,Chart控件是默认存在的,也可以通过NuGet安装额外的图表插件,例如LiveCharts。文中提供了通过NuGet添加图表控件的步骤和截图说明。
winform .net6 和 framework 的图表控件,为啥项目中不存在chart控件,该如何解决?
|
5月前
|
开发框架 缓存 前端开发
实战.NET Framework 迁移到 .NET 5/6
从.NET Framework 迁移到.NET 5/6 是一次重要的技术革新,涵盖开发环境与应用架构的全面升级。本文通过具体案例详细解析迁移流程,包括评估现有应用、利用.NET Portability Analyzer 工具识别可移植代码、创建新项目、逐步迁移代码及处理依赖项更新等关键步骤。特别关注命名空间调整、JSON 序列化工具更换及数据库访问层重构等内容,旨在帮助开发者掌握最佳实践,确保迁移过程平稳高效,同时提升应用性能与可维护性。
189 2
|
5月前
|
开发框架 JSON 监控
实战指南:从 .NET Framework 迁移到 .NET 5/6 的策略与最佳实践
【8月更文挑战第28天】从 .NET Framework 迁移到 .NET 5/6 是一次重要的技术升级,涉及开发环境与应用架构的改进。本文通过具体案例分析,介绍迁移策略与最佳实践,帮助开发者顺利完成转变。
112 1
|
5月前
|
缓存 程序员
封装一个给 .NET Framework 用的内存缓存帮助类
封装一个给 .NET Framework 用的内存缓存帮助类
|
25天前
|
监控 前端开发 API
一款基于 .NET MVC 框架开发、功能全面的MES系统
一款基于 .NET MVC 框架开发、功能全面的MES系统
|
4月前
|
开发框架 前端开发 JavaScript
ASP.NET MVC 教程
ASP.NET 是一个使用 HTML、CSS、JavaScript 和服务器脚本创建网页和网站的开发框架。
58 7
|
4月前
|
存储 开发框架 前端开发
ASP.NET MVC 迅速集成 SignalR
ASP.NET MVC 迅速集成 SignalR
104 0