亲自教你实现栈及C#中Stack源码分析

yizhihongxing

亲自教你实现栈及C#中Stack源码分析

栈的定义

栈是一种具有特殊行为的线性数据结构,栈中的元素遵循 LIFO(Last In First Out) 原则:

  • 入栈(Push):在栈的顶部添加一个元素;
  • 出栈(Pop):从栈的顶部移除一个元素;
  • 取顶(Peek):获取栈顶元素,但不对栈进行操作;
  • 判空(IsEmpty):判断栈中是否有元素。

栈的实现方式有两种:数组和链表。

数组实现栈

数组实现栈思路比较简单,基本原理就是使用数组来存储栈中的元素。具体实现方式请参考以下代码:

class ArrayStack<T>
{
    private T[] stack;
    private int top = -1;

    public ArrayStack(int capacity)
    {
        stack = new T[capacity];
    }

    public void Push(T item)
    {
        if (top == stack.Length - 1)
        {
            throw new StackOverflowException("stack overflow");
        }
        stack[++top] = item;
    }

    public T Pop()
    {
        if (top == -1)
        {
            throw new InvalidOperationException("stack is empty");
        }
        return stack[top--];
    }

    public T Peek()
    {
        if (top == -1)
        {
            throw new InvalidOperationException("stack is empty");
        }
        return stack[top];
    }

    public bool IsEmpty()
    {
        return top == -1;
    }
}

以上代码展示了如何使用数组实现栈类,其支持Push、Pop、Peek和IsEmpty操作。在创建ArrayStack对象时,需要传入一个整数参数capacity,表示栈的最大容量。在Push操作中,如果栈已满,则会抛出StackOverflowException异常,在Pop和Peek操作中,如果栈为空,则会抛出InvalidOperationException异常。示例代码:

static void Main(string[] args)
{
    var stack = new ArrayStack<int>(10);
    stack.Push(1);
    int item = stack.Pop(); // item = 1
    Console.WriteLine(item);
}

链表实现栈

链表实现栈的原理比数组方式更加简单,正是由于链表的“可增长性”,其可以实现 really dynamic stack,而数组实现的最大容量(capacity)是一开始就定好了的。

链表实现栈的具体实现方式请参考以下代码:

class LinkedListStack<T>
{
    private class Node
    {
        public T item;
        public Node next;
    }

    private Node top;

    public void Push(T item)
    {
        Node oldTop = top;
        top = new Node();
        top.item = item;
        top.next = oldTop;
    }

    public T Pop()
    {
        if (top == null)
        {
            throw new InvalidOperationException("stack is empty");
        }
        T item = top.item;
        top = top.next;
        return item;
    }

    public T Peek()
    {
        if (top == null)
        {
            throw new InvalidOperationException("stack is empty");
        }
        return top.item;
    }

    public bool IsEmpty()
    {
        return top == null;
    }
}

在链表实现栈代码中,我们在Push操作中,首先创建一个新的Node实例,并将其设置为top节点,然后将旧的top节点设置为新的top节点的next属性。示例代码:

static void Main(string[] args)
{
    var stack = new LinkedListStack<int>();
    stack.Push(1);
    int item = stack.Pop(); // item = 1
    Console.WriteLine(item);
}

C#中Stack源码分析

Stack是C#内置的一种数据结构,具有Push、Pop、Peek和Count等方法,以支持类似于数组的行为。但是,与数组不同的是,它是一种动态数据结构。以下是Stack的最简示例代码:

Stack<int> stack = new Stack<int>();
stack.Push(1);
int item = stack.Pop(); // item = 1
Console.WriteLine(item);

在源代码中,Stack类是使用动态数组实现的。这意味着,在执行Push操作时,如果已经达到了动态数组的最大容量,则新的容量将是原始容量的两倍。同时,在Pop操作中,如果容量减小到堆栈元素数的四分之一,则Stack将减小其容量到原始容量的一半。

自C#2.0以来,Stack类实现了IEnumerable接口,以支持枚举。如果您希望对Stack中的元素进行枚举,则可以使用foreach循环,如以下示例代码所示:

foreach (int i in stack)
{
    Console.Write(i + " ");
}

示例说明

以下是两个示例程序,在例子1中我们使用的是链表实现,而在例子2中我们使用的是C#内置的Stack数据结构。

示例1

class Program
{
    static void Main(string[] args)
    {
        LinkedListStack<int> stack = new LinkedListStack<int>();
        stack.Push(1);
        stack.Push(2);
        stack.Push(3);

        Console.WriteLine(stack.Pop()); // 输出3
        Console.WriteLine(stack.Pop()); // 输出2
        Console.WriteLine(stack.Pop()); // 输出1
    }
}

以上示例演示了如何使用LinkedListStack实现栈。

示例2

class Program
{
    static void Main(string[] args)
    {
        Stack<int> stack = new Stack<int>();
        stack.Push(1);
        stack.Push(2);
        stack.Push(3);

        Console.WriteLine(stack.Pop()); // 输出3
        Console.WriteLine(stack.Pop()); // 输出2
        Console.WriteLine(stack.Pop()); // 输出1
    }
}

以上示例演示了如何使用C#内置的Stack类实现栈。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:亲自教你实现栈及C#中Stack源码分析 - Python技术站

(0)
上一篇 2023年6月1日
下一篇 2023年6月1日

相关文章

  • C#利用后缀表达式解析计算字符串公式

    关于C#利用后缀表达式解析计算字符串公式,我们可以按照以下步骤来实现: 第一步:将中缀表达式转换为后缀表达式 将中缀表达式转换为后缀表达式有许多种算法,这里我们介绍一种简单的算法: 新建一个栈和一个列表; 从左到右遍历中缀表达式的每一个元素,每次处理一个元素; 如果该元素是数字,将其加入列表; 如果该元素是运算符,将其压入栈中,先判断栈顶元素的运算符与其优先…

    C# 2023年6月7日
    00
  • C#实现装箱与拆箱操作简单实例

    C#实现装箱与拆箱操作简单实例 什么是装箱与拆箱 C#中,装箱(boxing)指的是将一个值类型(比如int、float等)转换为一个对象类型(比如object类型、ValueType类型等),拆箱(unboxing)则是相反的过程,将一个对象类型转换为值类型。 装箱和拆箱操作可以在对内存性能要求较高的情况下对程序性能造成影响,因此需要慎重使用。 如何实现装…

    C# 2023年6月6日
    00
  • c# datetime方法应用介绍

    C# DateTime方法应用介绍 在C#中,DateTime是处理日期时间的一个非常重要的类型。它可以用来表示某一时刻的具体日期和时间,也可以通过计算帮助我们实现许多实际应用中的时间处理功能。本文将介绍DateTime常用的方法,以及如何使用这些方法进行日期时间的相关操作。 获取当前时间 我们可以使用DateTime.Now方法获取当前时间。该方法返回系统…

    C# 2023年6月1日
    00
  • .Net行为型设计模式之中介者模式(Mediator)

    .Net行为型设计模式之中介者模式(Mediator) 中介者模式是一种行为型设计模式,它的目的是减少对象之间的耦合度,增强对象之间的协作性,从而提高整个系统的灵活性和可维护性。 在中介者模式中,对象之间的通信都是通过中介者进行的,而不是直接相互引用。这样一来,系统中的每个对象都只需要跟中介者通信,而不用关心其他对象的存在,使得系统更加松耦合,也更加容易扩展…

    C# 2023年5月31日
    00
  • WCF中使用nettcp协议进行通讯的方法

    下面是关于“WCF中使用nettcp协议进行通讯的方法”的完整攻略,包含两个示例。 1. 什么是nettcp协议 nettcp协议是一种用于WCF通信的传输协议。nettcp协议是一种高性能、可靠的协议,适用于在同一局域网内的通信。nettcp协议使用二进制编码,可以提高通信效率。 2. 配置WCF服务使用nettcp协议 以下是配置WCF服务使用nettc…

    C# 2023年5月15日
    00
  • ext combobox动态加载数据库数据(附前后台)

    下面是详细的“ext combobox动态加载数据库数据(附前后台)”攻略。 什么是 ext combobox? ext combobox 是一种基于 ExtJS 框架开发的下拉菜单组件,它可以非常方便的实现下拉菜单的各种交互功能,同时也可以动态加载数据库数据实现自动填充下拉列表。 ext combobox 动态加载数据库数据操作步骤 创建数据库表 我们需要…

    C# 2023年5月31日
    00
  • C#使用Selenium+PhantomJS抓取数据

    我会为您提供一份详细的攻略。 1. 准备工作 如果您需要使用C#编写程序来使用Selenium和PhantomJS抓取网页数据,那么您需要先准备以下几个工具和组件: Visual Studio:C#开发环境 Selenium WebDriver:Selenium C#库 PhantomJS:无头浏览器 2. 安装和设置Selenium和PhantomJS 安…

    C# 2023年5月15日
    00
  • asp.net显示自己的网页图标的几种方式

    下面是“ASP.NET显示自己的网页图标的几种方式”的详细讲解,包括两个示例说明。 方式一:在HTML中引入favicon 在HTML页面的<head>标签中添加如下代码: <link rel="shortcut icon" href="/favicon.ico" type="image/x…

    C# 2023年6月3日
    00
合作推广
合作推广
分享本页
返回顶部