C#实现顺序栈和链栈的代码实例

C#实现顺序栈和链栈的代码实例可以分成以下几个步骤:

第一步:定义栈的数据结构

在C#中,我们可以使用class或者struct定义一个栈的数据结构。在这里,我们以class为例,定义一个名为Stack的类:

public class Stack<T>
{
    private T[] _items;
    private int _count;

    public Stack(int capacity)
    {
        _items = new T[capacity];
        _count = 0;
    }

    public void Push(T item)
    {
        if (_count >= _items.Length)
        {
            var newItems = new T[_items.Length * 2];
            Array.Copy(_items, newItems, _items.Length);
            _items = newItems;
        }

        _items[_count++] = item;
    }

    public T Pop()
    {
        if (_count <= 0)
            throw new InvalidOperationException("Stack is empty");

        var item = _items[--_count];
        _items[_count] = default(T);
        return item;
    }

    public T Peek()
    {
        if (_count <= 0)
            throw new InvalidOperationException("Stack is empty");

        return _items[_count - 1];
    }

    public bool IsEmpty => _count == 0;
}

在这个实现中,我们使用了一个泛型类型参数T来表示栈的元素类型,使用一个数组_items来保存栈的元素,使用一个整数_count来表示栈的元素个数。在构造函数中,我们使用参数capacity来指定栈的容量。

第二步:实现顺序栈

2.1 栈的创建

首先,我们需要定义一个顺序栈类ArrayStack,并在其中定义一个基于数组的栈实现,代码如下:

public class ArrayStack<T>
{
    private T[] _items;
    private int _count;

    public ArrayStack(int capacity)
    {
        _items = new T[capacity];
        _count = 0;
    }

    // ...
}

同样,我们使用了一个泛型类型参数T来表示栈的元素类型,使用一个数组_items来存储栈中的元素。然后,我们在构造函数中使用参数capacity作为数组的长度,并初始化count为0表示栈中没有任何元素。

2.2 栈的入栈

然后,我们可以实现两个基本的操作:入栈(push)和出栈(pop)。入栈操作将一个元素添加到栈中,代码如下:

public void Push(T item)
{
    if (_count >= _items.Length)
    {
        var newItems = new T[_items.Length * 2];
        Array.Copy(_items, newItems, _items.Length);
        _items = newItems;
    }

    _items[_count++] = item;
}

入栈操作将元素存储在数组的尾部,并将计数器加1。如果数组已经满了,我们将其扩展为原来的两倍。

2.3 栈的出栈

出栈操作是将栈顶元素弹出并返回它的值。如果栈是空的,那么出栈操作将抛出异常。下面是出栈操作的代码:

public T Pop()
{
    if (_count <= 0)
        throw new InvalidOperationException("Stack is empty");

    var item = _items[--_count];
    _items[_count] = default(T);
    return item;
}

出栈操作首先检查栈是否为空,然后将_count减1以获取栈顶元素的索引。接下来,我们从数组中删除该元素,并将其设置为默认值null或0。

至此,我们已经成功地实现了一个基于数组的顺序栈。

第三步:实现链栈

3.1 栈的创建

接下来,我们将实现一个基于链表的链栈。首先,我们需要定义节点类Node,代码如下:

public class Node<T>
{
    public T Value { get; }

    public Node<T> Next { get; set; }

    public Node(T value)
    {
        Value = value;
        Next = null;
    }
}

我们使用泛型类型参数T来表示节点的值类型,使用Value属性来访问节点的值,使用Next属性来访问指向下一个节点的引用。在节点类构造函数中,我们使用参数value来初始化节点的值,将Next属性设置为null。

然后,我们需要定义一个链式栈类LinkedStack,代码如下:

public class LinkedStack<T>
{
    private Node<T> _top;

    public LinkedStack()
    {
        _top = null;
    }

    // ...
}

我们使用泛型类型参数T来表示链栈元素的类型。在构造函数中,我们将栈顶节点_top初始化为null。

3.2 栈的入栈

然后我们可以定义一个入栈(push)方法,将一个元素压入栈中,代码如下:

public void Push(T item)
{
    var newNode = new Node<T>(item);
    newNode.Next = _top;
    _top = newNode;
}

入栈操作首先创建一个新节点newNode,其值为item。然后将新节点的Next属性设置为栈顶节点_top,然后将新节点指定为栈顶节点_top。

3.3 栈的出栈

接下来,我们实现出栈(pop)方法,将栈顶元素弹出并返回它的值,代码如下:

public T Pop()
{
    if (_top == null)
        throw new InvalidOperationException("Stack is empty");

    var item = _top.Value;
    _top = _top.Next;
    return item;
}

出栈操作首先检查栈是否为空。然后,我们获取栈顶元素的值,将_top指向下一个元素,并返回弹出的元素的值。

至此,我们已经成功地实现了一个基于链表的链栈。

示例

示例1:顺序栈使用示例

现在,我们可以使用顺序栈实现一个简单的括号匹配程序。我们需要对字符序列中的括号进行匹配,并报告任何非法的括号匹配。下面是程序的实现:

public bool IsValid(string input)
{
    var stack = new ArrayStack<char>(input.Length);

    foreach (var ch in input)
    {
        if (ch == '(' || ch == '[' || ch == '{')
        {
            stack.Push(ch);
        }
        else if (ch == ')' || ch == ']' || ch == '}')
        {
            if (stack.IsEmpty)
                return false;

            var top = stack.Pop();
            if ((top == '(' && ch != ')') || (top == '[' && ch != ']') || (top == '{' && ch != '}'))
                return false;
        }
    }

    return stack.IsEmpty;
}

上面的方法使用了一个顺序栈来保存左括号字符('(', '[', '{')。对于每个右括号字符(')', ']', '}'),我们从栈中弹出一个字符,并将其与当前字符进行比较。如果匹配,则继续进行下一个字符;否则,表示括号匹配非法,返回false。如果字符串处理完毕后栈为空,则表示括号匹配合法,返回true。

示例2:链栈使用示例

下面是一个示例程序,使用链栈实现基本的计算器:

public class Calculator
{
    private readonly LinkedStack<double> _stack;

    public Calculator()
    {
        _stack = new LinkedStack<double>();
    }

    public double Evaluate(string expression)
    {
        var tokens = expression.Split();
        foreach (var token in tokens)
        {
            switch (token)
            {
                case "+":
                    _stack.Push(_stack.Pop() + _stack.Pop());
                    break;
                case "-":
                    _stack.Push(-_stack.Pop() + _stack.Pop());
                    break;
                case "*":
                    _stack.Push(_stack.Pop() * _stack.Pop());
                    break;
                case "/":
                    var numerator = _stack.Pop();
                    var denominator = _stack.Pop();
                    _stack.Push(denominator / numerator);
                    break;
                default:
                    _stack.Push(double.Parse(token));
                    break;
            }
        }

        var result = _stack.Pop();
        if (!_stack.IsEmpty)
            throw new ArgumentException("Expression contains too many values");

        return result;
    }
}

上面的程序使用了一个链栈来保存运算符和操作数。对于输入表达式的每个单词(由空格分隔),我们根据语法规则将其转换为一个数字或一个运算符,并在栈上执行相应的操作。最后,我们从栈中弹出结果值,并检查栈是否为空(如果不为空,则表示表达式中包含过多的数字)。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C#实现顺序栈和链栈的代码实例 - Python技术站

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

相关文章

  • efcore性能调优

    性能调优——EFCore调优 按下硬件、网络不提,我们单表从程序层面对系统的性能进行优化,翻来覆去无外乎三个方面 缓存 异步 sql本片文章,我们针对.net core web项目的ef core框架进行性能优化。 1. EF Core框架已经本地缓存机制memorycache,所以我们访问一个接口,二次访问的性能相比首次会提升一大截 2.尽可能的通过主键查…

    C# 2023年5月5日
    00
  • C# Request.Form用法案例详解

    C# Request.Form用法案例详解 简介 Request对象是ASP.NET Web应用程序中的内置对象,用于在Web服务器上处理HTTP请求。其中,Request.Form是一个集合,用于获取HTTP POST的表单值。Request.Form的用法非常简单,可以通过指定表单控件的名称来获取该表单控件的值。 使用方法 //获取提交表单值 strin…

    C# 2023年6月1日
    00
  • c#中如何获取指定字符前的字符串

    在C#中获取指定字符(或字符串)前的字符串,可以采用String类的Substring和IndexOf方法来实现。 方法1:Substring方法 Substring方法是String类提供的一个获取子字符串的方法,可以通过指定起始位置和截取长度来获取指定范围的子字符串。我们可以通过查找指定字符(或字符串)的位置,然后取其前面的子串来获取需要的字符串。 示例…

    C# 2023年6月6日
    00
  • C#:foreach与yield语句的介绍

    C#: foreach与yield语句的介绍 什么是foreach foreach 是 C# 中常用的遍历集合的循环结构,它可以方便地遍历数组、集合、字典等集合数据类型。其基本语法结构如下: foreach (var item in collection) { // 循环体 } 其中,item 为当前循环的元素,collection 为要遍历的集合,可以是数…

    C# 2023年6月7日
    00
  • c# delegate和event的使用说明

    下面是关于”C# delegate和event的使用说明”的完整攻略。 什么是C# delegate? C# delegate是一种类型,该类型可以保存对一个或多个方法的引用并允许在需要时调用这些方法。可以将Delegate看作是函数指针的高级版本。Delegate对象保存的不是方法,而是指向方法的引用。这使得我们可以通过传递委托对象作为参数,从一个方法调用…

    C# 2023年6月7日
    00
  • jQuery ajax调用webservice注意事项

    在使用jQuery调用Web服务时,需要注意一些事项,以确保调用成功并获得正确的响应。本文将提供详细的“jQuery ajax调用Web服务注意事项”的完整攻略,包括如何正确设置Web服务、如何处理Web服务响应以及两个示例。 设置Web服务 在使用jQuery调用Web服务时,需要正确设置Web服务。以下是正确设置Web服务的步骤: 在Web服务中启用PO…

    C# 2023年5月15日
    00
  • 学习Winform分组类控件(Panel、groupBox、TabControl)

    学习Winform分组类控件是Winform桌面应用程序开发的基础知识之一。分组类控件包括Panel、groupBox和TabControl等,可以将窗体内的控件进行分组,方便用户的操作和管理。 1. Panel控件 Panel控件是Winform中最基本的分组类控件,可作为容器承载其他控件。下面是Panel控件的一些常用属性: Dock:控制Panel控件…

    C# 2023年6月7日
    00
  • Asp.net Core Jenkins Docker实现一键化部署的实现

    Asp.net Core Jenkins Docker实现一键化部署的实现 在本攻略中,我们将深入讲解如何使用Asp.net Core、Jenkins和Docker实现一键化部署,并提供两个示例说明。 准备工作 在开始之前,您需要完成以下准备工作: 安装Docker和Docker Compose。 安装Jenkins并配置好.NET Core插件。 创建一个…

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