update 数据还原到5分钟前_每天5分钟用C#学习数据结构(11)栈 Part 2

本文介绍栈的链式存储实现及应用案例,通过C#代码详细展示了节点定义、入栈、出栈等操作,并提供了进制转换的示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

a2ffe881e8a62126e844c089202c7511.png【基础知识作者 / Edison Zhou这是恰童鞋骚年的第200篇原创文章
上一篇介绍了栈的基本概念及其顺序存储方式的实现,本篇将会介绍链式存储方式的实现 以及 一个应用案例。1栈的基本实现(链式存储)

对栈的链式存储结构,我们可以参照单链表,为其设置一个头结点。这里,我们先来看看节点的定义:

(1)节点的定义实现

/// /// 基于链表的栈节点/// /// public class Node{    public T Item { get; set; }    public Node Next { get; set; }    public Node(T item){        this.Item = item;    }    public Node(){ }}

(2)入栈操作的实现

e98a6d69e2a4473cafd0c1812cc087f3.png

实现Push方法,即向栈顶压入一个元素,首先保存原先的位于栈顶的元素,然后新建一个新的栈顶元素,然后将该元素的下一个指向原先的栈顶元素。

/// /// 入栈/// /// 新节点public void Push(T item){        Node oldNode = first;        first = new Node();        first.Item = item;        first.Next = oldNode;        index++;}

(3)出栈操作的实现

c3ba9e4db0f235389facb382738ad89c.png

实现Pop方法,首先保存栈顶元素的值,然后将栈顶元素设置为下一个元素:

    ///     /// 出栈    ///     /// 出栈元素    public T Pop()    {        T item = first.Item;        first = first.Next;        index--;        return item;    }

这里还可以考虑将出栈元素的实例对象进行释放资源操作。

(4)完整的代码实现

/// /// 基于链表的栈节点/// /// 元素类型public class Node{    public T Item { get; set; }    public Node Next { get; set; }    public Node(T item){        this.Item = item;    }    public Node(){ }}/// /// 基于链表的栈实现/// /// 类型public class MyLinkStack{    private Node first;    private int index;    public MyLinkStack(){        this.first = null;        this.index = 0;    }    ///     /// 入栈    ///     /// 新节点    public void Push(T item){        Node oldNode = first;        first = new Node();        first.Item = item;        first.Next = oldNode;        index++;    }    ///     /// 出栈    ///     /// 出栈元素    public T Pop(){        T item = first.Item;        first = first.Next;        index--;        return item;    }    ///     /// 是否为空栈    ///     /// true/false    public bool IsEmpty(){        return this.index == 0;    }    ///     /// 栈中节点个数    ///     public int Size    {        get        {            return this.index;        }    }}

(5)简单的功能测试

这里跟顺序存储结构的测试代码一致,就不再贴出来,直接看运行结果吧:

33dbb3a5f1f378c6685091296a0f846c.png

2栈的基本应用

栈的应用场景很多,最常见的莫过于递归操作了,另外在运算表达式的求值上也有应用。这里看一个最经典的应用场景,进制转换问题。讲一个非负的十进制整数N转换成其他D进制数是计算机计算的一个基本问题,如(135)10进制=(207)8进制。最简单的解决办法就是连续取模%和整除/,例如将10进制的50转换为2进制数的过程如下图所示:

865d3dcbbdd519f4caa7bfed9b8bc807.png

由上图的计算过程可知,D进制各位数的产生顺序是从低位到高位,而输出顺序却是从高位到低位,刚好和计算过程是相反的,因此可以利用栈进行逆序输出。

private static string DecConvert(int num, int dec){    if (dec < 2 || dec > 16)    {        throw new ArgumentOutOfRangeException("dec",             "只支持将十进制数转换为二进制到十六进制数");    }    MyLinkStack stack = new MyLinkStack();    int residue;    // 余数入栈    while (num != 0)    {        residue = num % dec;        if (residue >= 10)        {            // 如果是转换为16进制且余数大于10则需要转换为ABCDEF            residue = residue + 55;        }        else        {            // 转换为ASCII码中的数字型字符1~9            residue = residue + 48;        }        stack.Push((char)residue);        num = num / dec;    }    // 反序出栈    string result = string.Empty;    while (stack.Size > 0)    {        result += stack.Pop();    }    return result;}

这里考虑到输出,所以使用了char类型作为节点数据类型,因此需要考虑ASCII码中的数字型字符与字母型字符。运行结果如下图所示:

① 10进制数:350=>8进制数:536

b30f3b90bf8e397ae7830da56117904f.png

② 10进制数:72=>16进制数:48

f5fd29aa729755f9e940308944e6346c.png

③ 10进制数:38=>2进制数:100110

a94a9041dd8b96b925d9e17bcf56e0f0.png

3.NET中的Stack

在.NET中,微软已经为我们提供了一个强大的栈类型:Stack,这里我们使用Reflector工具查看其具体实现,具体看看Push和Pop两个方法,其他的各位童鞋可以自己去查看。

b73ab4118445554ca924dd05d1949e85.png

 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._array, 0, destinationArray, 0, this._size);        this._array = destinationArray;    }    this._array[this._size++] = item;    this._version++;}

 Pop方法源码

public T Pop(){    if (this._size == 0)    {        ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EmptyStack);    }    this._version++;    T local = this._array[--this._size];    this._array[this._size] = default(T);    return local;}

可以看出,在.NET中Stack的实现是基于数组来实现的,在初始化时为其设置了一个默认的数组大小,在Push方法中当元素个数达到数组长度时,扩充2倍容量,然后将原数组拷贝到新的数组中。Pop方法中则跟我们刚刚实现的代码基本相同。

3小结

本文介绍了栈的链式存储的实现以及一个应用案例,最后带你看了.NET中的Stack的部分源码,下一篇我们会开始学习另一种操作受限的线性表:队列!

4参考资料程杰,《大话数据结构》陈广,《数据结构(C#语言描述)》段恩泽,《数据结构(C#语言版)》往期精彩回顾

每天5分钟用C#学习数据结构(10)

每天5分钟用C#学习数据结构(9)

每天5分钟用C#学习数据结构(8)

每天5分钟用C#学习数据结构(7)

基于Jenkins的开发测试全流程持续集成实践

基于Jenkins的ASP.NET Core持续集成实践

c70ff51b03eacd0e660d0df435d58d55.png

点个“在看”/转发朋友圈就是对我最大的支持

e8bf53b123d38f9b0c41d022d7579013.png

?点击

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值