【C#基础】C# 常用数据结构

简介: 编程语言 C# 常用数据结构的介绍。
序号 系列文章
4 【C#基础】C# 变量和常量的使用
5 【C#基础】C# 运算符总结
6 【C#基础】C# 常用语句讲解

@[TOC]

前言

:grinning:大家好,我是writer桑,前面一章已经学习了 C# 中常用语句的用法,那本章就开始学习 C# 程序中 常用的数据结构的介绍与用法,希望看完大家能够有所收获,感谢支持!

数据结构的概念

数据结构是一种计算机科学技术领域广泛使用的专业术语,指的是计算机存储组织数据的方式。正所谓 程序 = 数据结构 + 算法, 而数据结构 = 数据 + 结构,指的是相互之间存在一种或多种特定关系的数据元素的集合。 一般情况下选用合适的数据结构可以让程序运行的效率变得更高。

1,数组 (Array)

数组是一个存储相同类型元素的固定大小的顺序集合。数组是用来存储数据的集合,通常认为数组是一个同一类型变量的集合。

示例如下:

using System;

public class Program
{
    static void Main(string[] args)
    {
        // 声明一个整数类型的数组 
        int[] arr = { 1, 2, 3, 4, 5, 6, 7 };

        // 通过下标访问数组 
        Console.WriteLine(arr[0]);      
        Console.WriteLine(arr[1]);
        Console.WriteLine(arr[2]);

        // 通过 foreach 语句访问 
        foreach(int i in arr)
        {
            Console.Write(i + " ");     // 1 2 3 4 5 6 7 
        }
        Console.WriteLine();

        // Array类的使用, 反转数组 
        Array.Reverse(arr);

        foreach(int i in arr)
        {
            Console.Write(i + " ");     // 7 6 5 4 3 2 1 
        }
        Console.WriteLine();    

        // 清空数组 
        Array.Clear(arr);

        foreach (int i in arr)
        {
            Console.Write(i + " ");     // 0 0 0 0 0 0 0
        }
    }
}

1.1,声明并初始化赋值

声明数组的语法: datatype[] arrayName; 其中,datatype 表示存储在数组中元素的类型。 标记符 [] 声明表示建立数组的维度,也就是指定数组的长度大小。arrayName 是指定数组的名称,注意数组名称必须符合 C# 的命名规范。

示例如下:

// 数组的声明
int[] arr;
数组是引用类型,需要使用 new 运算符来初始化,该运算符指定 数组元素类型元素数量 n 。其中,数组元素可以是任何类型,数组元素的索引从 0 开始到 n-1。而且数组元素在没有初始化赋值的情况下,数值数组元素的默认值为0,而引用类型元素设置为 null 。

示例如下:

// 数组初始化
int[] arr = new int[7];
数组元素可以指定索引赋值一个单独的元素,也可以在数组初始化时赋值指定的元素,此时可以省略长度说明,因为 C# 编译器会直接根据初始化列表中的元素数量推断得出。在声明初始化数组时,也可以省略掉 new 运算符的使用,这称为隐式类型化数组。

示例如下:

// 给定索引单独赋值 
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
arr[3] = 4;
arr[4] = 5;
arr[5] = 6;
arr[6] = 7; 
// 初始化时赋值 
int[] arr = new int[] { 1, 2, 3, 4, 5, 6, 7 };
// 隐式类型化数组
int[] arr = { 1, 2, 3, 4, 5, 6, 7 };

1.2,访问数组元素

可以使用索引输出指定的元素,也可以使用 foreach 语句列举出数组中的所有元素。

示例如下:

// 通过下标访问数组 
Console.WriteLine(arr[0]);      
Console.WriteLine(arr[1]);
Console.WriteLine(arr[2]);
// 通过 foreach 语句访问 
foreach(int i in arr)
{
    Console.Write(i + " ");     // 1 2 3 4 5 6 7 
}
注意,在 C# 程序中数组可以是一维数组、多维数组和交错数组,它们之间的区别在于声明数组的维度上。更详细的介绍: C#一维数组、多维数组和交错数组的区别

1.3,Array 类的使用

Array 类是支持数组语言实现的基类,它在 System 命名空间中定义。 Array 类提供了各种用于数组的属性和方法。

示例如下:

// Array类的使用, 反转数组 
Array.Reverse(arr);

foreach(int i in arr)
{
    Console.Write(i + " ");     // 7 6 5 4 3 2 1 
}

// 清空数组 
Array.Clear(arr);

foreach(int i in arr)
{
    Console.Write(i + " ");     // 0 0 0 0 0 0 0
} 

列举 Array 类中的属性:

属性 描述
IsFixedSize 获取一个值,该值指示 Array 是否具有固定大小。
IsReadOnly 获取一个值,该值指示 Array 是否为只读。
IsSynchronized 获取一个值,该值指示是否同步对 Array 的访问(线程安全)。
Length 获取 Array 的所有维度中的元素总数。
LongLength 获取一个 64 位整数,该整数表示 Array 的所有维数中元素的总数。
MaxLength 获取数组中可能包含的最大元素数。
Rank 获取 Array 的秩(维数)。 例如,一维数组返回 1,二维数组返回 2,依次类推。
SyncRoot 获取可用于同步对 Array 的访问的对象。

列举 Array 类中常用的方法:

方法 描述
Clear(Array) 清除数组的内容。
Copy(Array, Array, Int32) 从第一个元素开始复制 Array 中的一系列元素,将它们粘贴到另一 Array 中(从第一个元素开始)。 长度指定为 32 位整数。
CopyTo(Array, Int32) 从指定的目标数组索引处开始,将当前一维数组的所有元素复制到指定的一维数组中。 索引指定为 32 位整数。
GetLength(Int32) 获取一个 32 位整数,该整数表示 Array 的指定维中的元素数。
GetLongLength(Int32) 获取一个 64 位整数,该整数表示 Array 的指定维中的元素数。
GetLowerBound(Int32) 获取数组中指定维度第一个元素的索引。
GetType() 获取当前实例的 Type。(继承自 Object)
GetUpperBound(Int32) 获取数组中指定维度最后一个元素的索引。
GetValue(Int32) 获取一维 Array 中指定位置的值。 索引指定为 32 位整数。
IndexOf(Array, Object) 在一个一维数组中搜索指定对象,并返回其首个匹配项的索引。
Reverse(Array) 反转整个一维 Array 中元素的顺序。
SetValue(Object, Int32) 将值设置为一维 Array 中指定位置的元素。 索引指定为 32 位整数。
Sort(Array) 使用 Array 中每个元素的 IComparable 实现,对整个一维 Array 中的元素进行排序。
ToString 返回表示当前对象的字符串。(继承自 Object)

Array 类更多方法请点击。

2,字符串 (String)

string 表示零个或多个 Unicode 字符的序列。string 是 System.String 在 .NET 中的别名。 在 C# 程序中使用 string 关键字和变量名称来声明一个字符串变量,其中变量名称需要符合 C# 的命名规范。

示例如下:

using System;

public class Program
{
    static void Main(string[] args)
    {
        // 声明一个 string 类型的字符串 
        string str = "Hello,world";
        string str2 = "Hello, C#";  

        // 通过下标访问字符串 
        Console.Write(str[0]);
        Console.Write(str[1]);
        Console.Write(str[2]);
        Console.Write(str[3]);
        Console.WriteLine();           // 输出:Hell
 
        // 直接输出 
        Console.WriteLine(str);        // 输出:Hello,world 
 
        // 运算符的使用
        Console.WriteLine(str2 == str);     // True
        Console.WriteLine(str2 != str);     // False 


        // String 类的使用 
        string[] splitStr = str.Split(",");  // ["Hello","World"]
        
        Console.WriteLine(splitStr);     // System.String[] 

        string str3 = String.Join("", splitStr);
        Console.WriteLine(str3);    //  HelloWorld
    }
}

2.1,声明并初始化赋值

字符串的声明初始化有多种形式, 其中包括单行双引号、多行三个双引号、使用 string 构造函数、使用 String 类的属性方法和使用运算符等。

示例如下:

// 单行字符串使用双引号  
string str1 = "Hello,world";

// 多行字符串使用三个双引号
string str2 = """
        This is a multi-line
            string literal with the second line indented.
        """; 
//通过使用 string 构造函数
char[] str = { 'H', 'e', 'l', 'l', 'o' };
string greetings = new string(str);

Console.WriteLine("Greetings: {0}", greetings);        // Greetings: Hello 
// 使用 String 类方法来生成字符串 
string[] strarray = { "Hello", "From", "Tutorials", "Point" };
string message = String.Join(" ", strarray);

Console.WriteLine("Message: {0}", message);      // Message: Hello From Tutorials Point 
// 使用运算符,生成新的字符串 
string str = "Hello," + "World";

Console.WriteLine(str);   // Hello,World 
在字符串的声明时可以使用 @ 和 $ 符号,分别表示逐字字符串和内插字符串。 逐字字符串不处理转义序列,而内插字符串是对整个字符串的格式化。

示例如下:

// 逐字字符串的声明 
string str = @"c:\Docs\Source\a.txt";

Console.WriteLine(str);     // c:\Docs\Source\a.txt 
// 内插字符串的使用 
string s1 = "Hello";
string s2 = "World"; 

Console.WriteLine($"{s1},{s2}");    // Hello,World 

2.2,输出字符串

字符串的访问可以使用 [] 运算符指定下标访问个别字符,也可以直接通过 WriteLine 方法输出和foreach 循环遍历。

示例如下:

// 声明一个 string 类型的字符串 
string str = "Hello,world";
string str2 = "Hello, C#";  

// 通过下标访问字符串 
Console.Write(str[0]);
Console.Write(str[1]);
Console.Write(str[2]);
Console.Write(str[3]);
Console.WriteLine();           // 输出:Hell
// 通过 WriteLine 方法输出
string str = "Hello,World";

Console.WriteLine(str);     // "Hello,World"
// 使用 foreach 循环输出 
string str = "Hello,World"; 

foreach(char c in str)
{
    Console.Write(c);     // "Hello,World" 
}

2.3,String 类的使用

String 类是创建字符串类型的基类。它在 System 命名空间中定义,在 String 类提供了许多支持字符串的操作和方法。

示例如下:

// String 类的使用 
string[] splitStr = str.Split(",");         // ["Hello","World"]

Console.WriteLine(splitStr);        // System.String[] 
// Join 方法指定字符进行连接 
string str3 = String.Join("", splitStr);
Console.WriteLine(str3);    //  HelloWorld

关于 String 类中的定义:

构造函数:

属性 描述
String(Char*) 将 String 类的新实例初始化为由指向 Unicode 字符数组的指定指针指示的值。
String(Char, Int32) 将 String 类的新实例初始化为由重复指定次数的指定 Unicode 字符指示的值。

更多构造函数点击。

字段:

属性 描述
Empty 表示空字符串。 此字段为只读。

属性:

属性 描述
Chars[Int32] 获取当前 Char 对象中位于指定位置的 String 对象。
Length 获取当前 String 对象中的字符数。

方法:

属性 描述
Clone() 返回对此 String实例的引用。
Compare(String, Int32, String, Int32, Int32) 比较两个指定的 String 对象的子字符串,并返回一个指示二者在排序顺序中的相对位置的整数。
Compare(String, Int32, String, Int32, Int32, Boolean) 比较两个指定的 String 对象的子字符串(忽略或考虑其大小写),并返回一个整数,指示二者在排序顺序中的相对位置。
Concat(Object) 创建指定对象的字符串表示形式。
Concat(Object, Object) 连接两个指定对象的字符串表示形式。
Contains(Char) 返回一个值,该值指示指定的字符是否出现在此字符串中。
CopyTo(Int32, Char[], Int32, Int32) 将指定数目的字符从此实例中的指定位置复制到 Unicode 字符数组中的指定位置。
CopyTo(Span\<Char>) 将此字符串的内容复制到目标范围。
Equals(Object) 确定此实例是否与指定的对象(也必须是 String 对象)具有相同的值。
Equals(String) 确定此实例是否与另一个指定的 String 对象具有相同的值。
Equals(String, String) 确定两个指定的 String 对象是否具有相同的值。
Format(IFormatProvider, String, Object) 将指定字符串中的一个或多个格式项替换为对应对象的字符串表示形式。 参数提供区域性特定的格式设置信息。
Format(IFormatProvider, String, Object, Object) 将字符串中的格式项替换为两个指定对象的字符串表示形式。 参数提供区域性特定的格式设置信息。
GetEnumerator() 检索一个可以循环访问此字符串中的每个字符的对象。
GetHashCode() 返回该字符串的哈希代码。
GetType() 获取当前实例的 Type。(继承自 Object)
IndexOf(Char) 报告指定 Unicode 字符在此字符串中的第一个匹配项的从零开始的索引。
IndexOf(Char, Int32) 报告指定 Unicode 字符在此字符串中的第一个匹配项的从零开始的索引。 该搜索从指定字符位置开始。
Insert(Int32, String) 返回一个新的字符串,在此实例中的指定的索引位置插入指定的字符串。
IsNullOrEmpty(String) 指示指定的字符串是 null 还是空字符串 ("")。
Join(Char, Object[]) 连接对象数组的字符串表示形式,其中在每个成员之间使用指定的分隔符。
Join(Char, String[]) 连接字符串数组,其中在每个成员之间使用指定的分隔符。
LastIndexOf(Char) 报告指定 Unicode 字符在此实例中的最后一个匹配项的从零开始的索引的位置。
LastIndexOf(Char, Int32) 报告指定 Unicode 字符在此实例中的最后一个匹配项的从零开始的索引的位置。 在指定的字符位置开始和在向后的右边该字符串的开头处理的搜索。
Remove(Int32) 返回当前实例中从指定位置到最后位置的所有以删除的字符的新字符串。
Remove(Int32, Int32) 返回指定数量字符在当前这个实例起始点在已删除的指定的位置的新字符串。
Replace(String, String) 返回一个新字符串,其中当前实例中出现的所有指定字符串都替换为另一个指定的字符串。
Split(Char, Int32, StringSplitOptions) 基于指定的分隔字符和(可选)选项将字符串拆分为最大数量的子字符串。 根据提供的字符分隔符将字符串拆分为最大数量的子字符串,可以选择忽略结果中的空子字符串。
Split(Char, StringSplitOptions) 根据指定的分隔符和(可选)选项将字符串拆分为子字符串。
StartsWith(Char) 确定此字符串实例是否以指定字符开始。
StartsWith(String) 确定此字符串实例的开头是否与指定的字符串匹配。
Substring(Int32) 从此实例检索子字符串。 子字符串在指定的字符位置开始并一直到该字符串的末尾。
Substring(Int32, Int32) 从此实例检索子字符串。 子字符串从指定的字符位置开始且具有指定的长度。
ToCharArray() 将此实例中的字符复制到 Unicode 字符数组。
ToCharArray(Int32, Int32) 将此实例中的指定子字符串内的字符复制到 Unicode 字符数组。
ToLower() 返回此字符串转换为小写形式的副本。
ToLower(CultureInfo) 根据指定区域性的大小写规则返回此字符串转换为小写形式的副本。
ToString() 返回 String 的此实例;不执行实际转换。
ToString(IFormatProvider) 返回 String 的此实例;不执行实际转换。
ToUpper() 返回此字符串转换为大写形式的副本。
ToUpper(CultureInfo) 根据指定区域性的大小写规则返回此字符串转换为大写形式的副本。
Trim() 从当前字符串删除所有前导空白字符和尾随空白字符。
TrimEnd() 从当前字符串删除所有尾随空白字符。
TrimStart() 从当前字符串删除所有前导空白字符。

更多类方法点击。

运算符:

属性 描述
Equality(String, String) 确定两个指定的字符串是否具有相同的值。
Implicit(String to ReadOnlySpan) 定义给定字符串到只读字符范围的隐式转换。
Inequality(String, String) 确定两个指定的字符串是否具有不同的值。

3,结构体(Struct)

结构体类型是一种可封装数据和相关功能的值类型。它使得一个单一变量可以存储各种数据类型的相关数据。使用 struct 关键字定义结构体类型。

3.1,结构体的定义

定义结构体类型,需要使用 struct 关键字和变量来生成,在结构体类型内可以定义需要的成员和构造函数。

示例如下:

using System;

public struct Coords
{
    public Coords(double x, double y)
    {
        X = x;
        Y = y;
    }

    public double X { get; }
    public double Y { get; }

    public override string ToString() => $"({X}, {Y})";
}

public class Program
{ 
    static void Main(string[] args)
    {
        Coords coord = new Coords(11, 22);

        Console.WriteLine(coord);       // (11, 22) 
    }
}

3.2,结构体的使用

在结构体定义之后。 可以使用 "结构体名称" + "实例化对象" 来生成实例对象,实例对象就可以操作在结构体内定义的成员。

示例如下:

public class Program
{ 
    static void Main(string[] args)
    {
        Coords coord = new Coords(11, 22);

        Console.WriteLine(coord);       // (11, 22) 
    }
}

3.3,结构体和类的区别

点击跳转:C#面试常见基础知识点整理 第七条。

结构体在以下几个方面不同于类:

  • 结构体是值类型,类是引用类型。
  • 结构体常用于数据存储,类多用于行为。
  • 类支持继承, 而结构体不支持继承。
  • 类可以为抽象类,结构体类型不支持抽象模式。
  • 结构体不支持无参构造函数,也不支持析构函数,并且不能有Protected修饰符。

什么时候使用结构体类型:

通常,可以使用结构体类型来设计以数据为中心的较小类型,这些类型只有很少的行为或没有行为。 例如,.NET 使用结构体类型来表示数字(整数和实数)、布尔值、Unicode 字符以及时间实例。 如果侧重于类型的行为,请考虑定义一个类。 类类型具有引用语义 。也就是说,类类型的变量包含的是对类型的实例的引用,而不是实例本身。

4,枚举(Enum)

枚举类型是由基础整数数值类型的一组命名常量定义的值类型。 若要定义枚举类型,请使用 enum 关键字并指定枚举成员的名称。

4.1,枚举的定义

枚举类型的定义使用 enum 关键字 + 枚举名称创建并且自定义枚举成员,枚举成员是一个用逗号分隔的标识符列表。 默认情况下第一个枚举成员的值为0,并依次递增, 也可以显示指定枚举成员的值。

示例如下:

// 枚举类型的定义 
enum Season
{
    Spring,
    Summer,
    Autumn,
    Winter
}

4.2,枚举的使用

使用枚举类型不需要实例化对象就可以使用。对于任何枚举类型,枚举类型与其基础整型类型之间存在显式转换。 如果将枚举值转换为其基础类型,则结果为枚举成员的关联整数值。

示例如下:

using System;

public class EnumTest
{
    // 枚举类型的定义 
    enum Season
    {
        Spring,
        Summer,
        Autumn,
        Winter
    }

    static void Main()
    {
        int x = (int)Season.Spring;
        int y = (int)Season.Summer; 

        Console.WriteLine("Spring = {0}", x);      // Spring = 0
        Console.WriteLine("Summer = {0}", y);      // Summer = 1 
    }
}

4.3,Enum 类的使用

Enum 类为所有枚举类型提供了基类。 它在 System 命名空间中定义,在 Enum 类提供了许多支持枚举类型的操作和方法。例如使用 Enum.IsDefined 方法来确定枚举类型是否包含具有特定关联值的枚举成员。

示例如下:

int value = 1;

Console.WriteLine(Enum.IsDefined(typeof(Season), value));   // True 

关于 Enum 类中的定义:

构造函数:

属性 描述
Enum() 初始化 Enum 类的新实例。

方法

属性 描述
CompareTo(Object) 将此实例与指定对象进行比较并返回一个对二者的相对值的指示。
Equals(Object) 返回一个值,该值指示此实例是否等于指定的对象。
Format(Type, Object, String) 根据指定格式将指定枚举类型的指定值转换为其等效的字符串表示形式。
GetHashCode() 返回该实例的值的哈希代码。
GetName(Type, Object) 在指定枚举中检索具有指定值的常数的名称。
GetType() 获取当前实例的 Type。(继承自 Object)
IsDefined(Type, Object) 返回一个布尔值,该值指示给定的整数值或其名称字符串是否存在于指定的枚举中。

更多类方法点击。


结语

:star: 以上就是 C# 常用数据结构的介绍,希望能够对大家有所帮助。望大家多多支持,你们的支持就是笔者创作最大的动力!
目录
相关文章
|
3月前
|
存储 C#
揭秘C#.Net编程秘宝:结构体类型Struct,让你的数据结构秒变高效战斗机,编程界的新星就是你!
【8月更文挑战第4天】在C#编程中,结构体(`struct`)是一种整合多种数据类型的复合数据类型。与类不同,结构体是值类型,意味着数据被直接复制而非引用。这使其适合表示小型、固定的数据结构如点坐标。结构体默认私有成员且不可变,除非明确指定。通过`struct`关键字定义,可以包含字段、构造函数及方法。例如,定义一个表示二维点的结构体,并实现计算距离原点的方法。使用时如同普通类型,可通过实例化并调用其成员。设计时推荐保持结构体不可变以避免副作用,并注意装箱拆箱可能导致的性能影响。掌握结构体有助于构建高效的应用程序。
115 7
|
4月前
|
Dart 算法 JavaScript
C#数据结构与算法入门教程,值得收藏学习!
C#数据结构与算法入门教程,值得收藏学习!
|
6月前
|
存储 算法 C#
C#编程与数据结构的结合
【4月更文挑战第21天】本文探讨了C#如何结合数据结构以构建高效软件,强调数据结构在C#中的重要性。C#作为面向对象的编程语言,提供内置数据结构如List、Array和Dictionary,同时也支持自定义数据结构。文章列举了C#实现数组、链表、栈、队列等基础数据结构的示例,并讨论了它们在排序、图算法和数据库访问等场景的应用。掌握C#数据结构有助于编写高性能、可维护的代码。
56 3
|
6月前
|
存储 程序员 编译器
C#基本数据结构
C#基本数据结构
30 0
|
11月前
|
Rust Dart 算法
支持C#的开源免费、新手友好的数据结构与算法入门教程 - Hello算法
支持C#的开源免费、新手友好的数据结构与算法入门教程 - Hello算法
108 1
|
机器学习/深度学习 人工智能 C#
C#<数据结构>栈的应用——括号分配问题
C#<数据结构>栈的应用——括号分配问题
77 0
C#《数据结构》二叉树的创建和遍历
C#《数据结构》二叉树的创建和遍历
182 0
|
存储 C# 索引
C#(四十八)之三种数据结构 stack queue sortedList
堆栈(Stack):代表了一个后进先出的对象集合。当您需要对各项进行后进先出的访问时,则使用堆栈。当您在列表中添加一项,称为推入元素,当您从列表中移除一项时,称为弹出元素。 System.Collections.Queue类表示对象的先进先出集合,存储在 Queue(队列) 中的对象在一端插入,从另一端移除。 SortedList 类代表了一系列按照键来排序的键/值对,这些键值对可以通过键和索引来访问。
164 0
C#(四十八)之三种数据结构 stack queue sortedList
|
算法 C# C++
【愚公系列】2021年11月 C#版 数据结构与算法解析(AVL树)
【愚公系列】2021年11月 C#版 数据结构与算法解析(AVL树)
144 0
【愚公系列】2021年11月 C#版 数据结构与算法解析(AVL树)
|
存储 算法 C#
【愚公系列】2021年11月 C#版 数据结构与算法解析(红黑树)
【愚公系列】2021年11月 C#版 数据结构与算法解析(红黑树)
176 0
【愚公系列】2021年11月 C#版 数据结构与算法解析(红黑树)