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

亲自教你实现栈及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#基于WinForm实现串口通讯

    下面是详细的C#基于WinForm实现串口通讯的攻略,包括必要的示例代码和步骤。 1. 前置知识 在进行串口通讯之前,需要掌握以下基本知识: 串口的通信原理和相关协议 C#的基本语法和WinForm编程基础 .NET Framework中用于串口通讯的命名空间SerialPort的相关使用方法 2. 创建WinForm应用程序 首先,我们需要在Visual …

    C# 2023年5月15日
    00
  • c# Newtonsoft 六个值得使用的特性(上)

    C# Newtonsoft 六个值得使用的特性(上) 1. JsonProperty public class User { [JsonProperty("ID")] public int Id { get; set; } [JsonProperty("Name")] public string UserName { …

    C# 2023年5月31日
    00
  • Unity输出带点击跳转功能的Log实现技巧详解

    Unity输出带点击跳转功能的Log实现技巧详解 在Unity开发中,我们经常需要输出Log信息来检查程序运行的过程,但是在大项目中,很难快速定位到特定的代码行,于是带有点击跳转功能的Log输出就显得尤为重要。本文将详细介绍如何实现带有点击跳转功能的Log输出。 1. 前提条件 在实现具有点击跳转功能的Log输出之前,我们需要确保我们已经掌握了以下基础知识:…

    C# 2023年5月15日
    00
  • C# 泛型的简单理解(安全、集合、方法、约束、继承)分享

    下面我来详细讲解一下 C# 泛型的相关知识。 什么是泛型 泛型是 C# 语言的一个重要特性,它能使你编写出更加灵活和可重用的代码。泛型和类、接口、委托和方法一样,是 C# 中的一种类型。它允许你定义一种类型,这种类型可以在使用时指定其具体的类型参数。这相当于抽象出了一种通用的类型,只有在具体使用时才会确定其具体类型。 泛型的优势 安全性:泛型能提供编译时类型…

    C# 2023年5月15日
    00
  • C#中使用Microsoft Unity记录日志

    下面是“C#中使用Microsoft Unity记录日志”的完整攻略: 1. Microsoft Unity是什么? Microsoft Unity是一个开源的轻量级IoC容器,它可以让您实现面向对象编程的优秀设计模式,如依赖注入和控制反转。同时,它还提供一些内置服务,如类型注册、对象解析和构建器模式等。 2. 使用Microsoft Unity记录日志 在…

    C# 2023年6月6日
    00
  • c# 如何用组合替代继承

    组合和继承都是面向对象编程中的两个重要概念。在某些情况下,使用组合可以更好地设计我们的类和对象结构。下面是一些完整的攻略,说明如何使用组合来替代继承。 什么是继承(Inheritance)? 在面向对象编程中,继承是一种实现代码复用的方式。通过继承,子类可以从父类中继承属性和方法,从而可以减少代码冗余并增加可维护性。C# 中使用 : 符号来表示继承关系。 c…

    C# 2023年6月6日
    00
  • C#查找字符串所有排列组合的方法

    我们可以使用递归的方法来查找字符串所有排列组合的方法。 首先,我们需要明确排列和组合的概念。排列指从n个不同元素中取出m个元素,有序排列成一列的所有可能情况。组合指从n个不同元素中取出m个元素,不考虑顺序的所有可能情况。 接下来,我们编写一个递归函数 PermuteString 来实现字符串的全排列: public static void PermuteSt…

    C# 2023年6月7日
    00
  • 深入解析C#编程中struct所定义的结构

    深入解析C#编程中struct所定义的结构 什么是struct? struct是C#语言中用来定义结构体的关键字,它像类一样可以定义成员变量和方法,但是,它有以下特点: struct是值类型,而类则是引用类型 在定义struct时,成员变量不会进行初始化,必须在创建实例时自行初始化 struct的实例通常存储在栈中,而类的实例存储在堆中 使用struct可以…

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