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

序号系列文章
4【C#基础】C# 变量和常量的使用
5【C#基础】C# 运算符总结
6【C#基础】C# 常用语句讲解

前言

😀大家好,我是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)返回一个布尔值,该值指示给定的整数值或其名称字符串是否存在于指定的枚举中。

更多类方法点击。


结语

⭐️ 以上就是 C# 常用数据结构的介绍,希望能够对大家有所帮助。望大家多多支持,你们的支持就是笔者创作最大的动力!

  • 31
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 20
    评论
数据结构C#语言和.NET框架结合是本书的一大特点。本书分为8章,第1章介绍了数据结构和算法的基本概念及本书用到的数学和C#的知识;第2章至第6章分别讨论了线性表、栈和队列、串和数组、树型结构和图结构等常用数据结构及其应用,以及在.NET框架中相应的数据结构;第7、8两章分别讨论了排序和查找常用的各种方法及其应用以及在.NET框架中相应的算法。 第1章绪论...........................................................................................................................1 1.1 数据结构...................................................................................................................1 1.1.1 学习数据结构的必要性...................................................................................1 1.1.2 基本概念和术语...............................................................................................1 1.2 算法...........................................................................................................................4 1.2.1算法的特性............................................................................................................4 1.2.2算法的评价标准....................................................................................................5 1.2.3算法的时间复杂度................................................................................................6 1.3 数学预备知识...........................................................................................................7 1.3.1 集合...................................................................................................................7 1.3.2 常用的数学术语...............................................................................................8 1.3.3 对数...................................................................................................................8 1.3.4 递归...................................................................................................................9 1.4 C#预备知识.............................................................................................................10 1.4.1 接口.................................................................................................................10 1.4.2 泛型编程.........................................................................................................13 本章小结................................................................................................................................20 习题一....................................................................................................................................20 第2章线性表.....................................................................................................................22 2.1 线性表的逻辑结构.........................................................................................................22 2.1.1 线性表的定义.....................................................................................................22 2.1.2 线性表的基本操作.............................................................................................22 2.2 顺序表.............................................................................................................................24 2.2.1 顺序表的定义.....................................................................................................24 2.2.2 顺序表的基本操作实现.....................................................................................29 2.2.3 顺序表应用举例.................................................................................................35 2.3 单链表.............................................................................................................................38 2.3.1 单链表的定义.....................................................................................................39 2.3.2 单链表的基本操作实现.....................................................................................46 2.3.3 单链表应用举例.................................................................................................56 2.4 其他链表.........................................................................................................................61 2.4.1 双向链表.............................................................................................................61 2.4.2循环链表..............................................................................................................64 2.5 C#中的线性表.................................................................................................................64 本章小结................................................................................................................................67 习题二....................................................................................................................................67 第3章栈和队列.................................................................................................................69 3.1 栈....................................................................................................................................69 3.1.1 栈的定义及基本运算.........................................................................................69 3.1.2 栈的存储和运算实现.........................................................................................70 3.1.3 栈的应用举例.....................................................................................................82 3.1.4 C#中的栈.............................................................................................................87 3.2 队列................................................................................................................................87 3.2.1队列的定义及基本运算......................................................................................87 数据结构C#语言版) 目录 II 3.2.2 队列的存储和运算实现.....................................................................................89 3.2.3 队列的应用举例...............................................................................................103 3.2.4 C# 中的队列.....................................................................................................104 本章小结...............................................................................................................................105 习题三..................................................................................................................................105 第4章串和数组...............................................................................................................106 4.1 串..................................................................................................................................106 4.1.1 串的基本概念...................................................................................................106 4.1.2 串的存储及类定义...........................................................................................106 4.1.3 串的基本操作的实现.......................................................................................111 4.1.4 C#中的串...........................................................................................................115 4.2 数组...............................................................................................................................117 4.2.1 数组的逻辑结构...............................................................................................117 4.2.2 数组的内存映象...............................................................................................118 4.2.3 C#中的数组.......................................................................................................119 本章小结...............................................................................................................................121 习题四..................................................................................................................................121 第5章树和二叉树...........................................................................................................123 5.1 树..................................................................................................................................123 5.1.1 树的定义...........................................................................................................123 5.1.2 树的相关术语...................................................................................................124 5.1.3 树的逻辑表示...................................................................................................125 5.1.4 树的基本操作...................................................................................................126 5.2 二叉树...........................................................................................................................126 5.2.1 二叉树的定义...................................................................................................127 5.2.2 二叉树的性质...................................................................................................128 5.2.3 二叉树的存储结构...........................................................................................129 5.2.4二叉链表存储结构的类实现............................................................................132 5.2.5 二叉树的遍历...................................................................................................137 5.3 树与森林.......................................................................................................................141 5.3.2 树、森林与二叉树的转换...............................................................................144 5.3.3 树和森林的遍历...............................................................................................147 5.4哈夫曼树........................................................................................................................147 5.4.1哈夫曼树的基本概念........................................................................................147 5.4.2哈夫曼树类的实现............................................................................................149 5.4.3哈夫曼编码........................................................................................................153 5.5 应用举例...............................................................................................................154 5.6 C#中的树...............................................................................................................157 本章小结...............................................................................................................................158 习题五..................................................................................................................................159 第6章图...........................................................................................................................161 6.1 图的基本概念................................................................................................................161 6.1.1 图的定义.............................................................................................................161 6.1.2 图的基本术语...................................................................................................161 数据结构C#语言版) 目录 III 6.1.3 图的基本操作...................................................................................................165 6.2 图的存储结构...............................................................................................................166 6.2.1邻接矩阵............................................................................................................167 6.2.2 邻接表...............................................................................................................172 6.3 图的遍历.......................................................................................................................185 6.3.1 深度优先遍历...................................................................................................185 6.3.2 广度优先遍历...................................................................................................188 6.4 图的应用.......................................................................................................................189 6.4.1 最小生成树.......................................................................................................189 6.4.2 最短路径...........................................................................................................199 6.4.3 拓扑排序...........................................................................................................207 本章小结...............................................................................................................................210 习题六..................................................................................................................................210 第7章排序.......................................................................................................................213 7.1 基本概念.......................................................................................................................213 7.2 简单排序方法...............................................................................................................214 7.2.1 直接插入排序...................................................................................................214 7.2.2 冒泡排序...........................................................................................................216 7.2.3 简单选择排序...................................................................................................217 7.3 快速排序.......................................................................................................................219 7.4 堆排序...........................................................................................................................222 7.5 归并排序.......................................................................................................................230 7.6 基数排序.......................................................................................................................232 7.6.1 多关键码排序...................................................................................................232 7.6.2 链式基数排序...................................................................................................233 7.7 各种排序方法的比较与讨论.......................................................................................235 7.8 C#中排序方法...............................................................................................................235 本章小结...............................................................................................................................236 习题七..................................................................................................................................236 第8章查找.......................................................................................................................238 8.1 基本概念和术语............................................................................................................238 8.2 静态查找表...................................................................................................................238 8.2.1 顺序查找...........................................................................................................238 8.2.2 有序表的折半查找...........................................................................................239 8.2.3 索引查找...........................................................................................................242 8.3 动态查找表...................................................................................................................243 8.4 哈希表...........................................................................................................................252 8.4.1 哈希表的基本概念...........................................................................................252 8.4.2 常用的哈希函数构造方法...............................................................................253 8.4.3 处理冲突的方法...............................................................................................254 8.5 C#中的查找方法...........................................................................................................256 本章小结...............................................................................................................................256 习题八..................................................................................................................................256 参考文献......................................................................................................................................257
C#版本数据结构,用C#的同志们有福啦 本书节选: 第1章 绪论 数据是外部世界信息的计算机化,是计算机加工处理的对象。运用计算机处 理数据时,必须解决四个方面的问题:一是如何在计算机中方便、高效地表示和 组织数据;二是如何在计算机存储器(内存和外存)中存储数据;三是如何对存 储在计算机中的数据进行操作,可以有哪些操作,如何实现这些操作以及如何对 同一问题的不同操作方法进行评价;四是必须理解每种数据结构的性能特征,以 便选择一个适合于某个特定问题的数据结构。这些问题就是数据结构这门课程所 要研究的主要问题。本章首先说明学习数据结构的必要性和本书的目的,然后解 释数据结构及其有关概念,接着讨论算法的相关知识,最后简单介绍本书所要用 到的相关数学知识和C#知识。 1.1 数据结构 1.1.1 学习数据结构的必要性 我们知道,虽然每个人都懂得英语的语法与基本类型,但是对于同样的题目, 每个人写出的作文,水平却高低不一。程序设计也和写英语作文一样,虽然程序 员都懂得语言的语法与语义,但是对于同样的问题,程序员写出来的程序不一样。 有的人写出来的程序效率很高,有的人却用复杂的方法来解决一个简单的问题。 当然,程序设计水平的提高仅仅靠看几本程序设计书是不行的。只有多思索、 多练习,才能提高自己的程序设计水平;否则,书看得再多,提高也不大。记得 刚学程序设计时,常听人说程序设计水平要想提高,最重要的是多看别人写的程 序,多去思考问题。从别人写的程序中,我们可以发现效率更高的解决方法;从 思考问题的过程中,我们可以了解解决问题的方法常常不只一个。运用先前解决 问题的经验,来解决更复杂更深入的问题,是提高程序设计水平的最有效途径。 数据结构正是前人在思索问题的过程中所想出的解决方法。一般而言,在学 习程序设计一段时间后,学习“数据结构”便能让你的程序设计水平上一个台阶。 如果只学会了程序设计的语法和语义,那么你只能解决程序设计三分之一的问 题,而且运用的方法并不是最有效的。但如果学会了数据结构的概念,就能在程 序设计上,运用最有效的方法来解决绝大多数的问题。 《数据结构》这门课程的目的有三个。第一个是讲授常用数据结构,这些 数据结构形成了程序员基本数据结构工具箱(toolkit)。对于许多常见的问题,工 具箱里的数据结构是理想的选择。就像.NET Framework 中Windows应用程序开 发中的工具箱,程序员可以直接拿来或经过少许的修改就可以使用,非常方便。 第二个是讲授常用的算法,这和数据结构一样,是人们在长期实践过程中的总结, 程序员可以直接拿来或经过少许的修改就可以使用。可以通过算法训练来提高程 序设计水平。第三个目的是通过程序设计的技能训练促进程序员综合能力的提 高。 1.1.2 基本概念和术语 在本小节中,将对一些常用的概念和术语进行介绍,这些概念和术语在以后 的章节中会多次出现。 1、数据(Data) 数据是外部世界信息的载体,它能够被计算机识别、存储和加工处理,是计 算机程序加工的原料。计算机程序处理各种各样的数据,可以是数值数据,如整 数、实数或复数;也可以是非数值数据,如字符、文字、图形、图像、声音等。 2、数据元素(Data Element)和数据项(Data Item) 数据结构C#语言版) 1.1 数据结构2 数据元素是数据的基本单位,在计算机程序中通常被作为一个整体进行考虑 和处理。数据元素有时也被称为元素、结点、顶点、记录等。一个数据元素可由 若干个数据项(Data Item)组成。数据项是不可分割的、含有独立意义的最小数据 单位,数据项有时也称为字段(Field)或域(Domain)。例如,在数据库信息处理系 统中,数据表中的一条记录就是一个数据元素。这条记录中的学生学号、姓名、 性别、籍贯、出生年月、成绩等字段就是数据项。数据项分为两种,一种叫做初 等项,如学生的性别、籍贯等,在处理时不能再进行分割;另一种叫做组合项, 如学生的成绩,它可以再分为数学、物理、化学等更小的项。 3、数据对象(Data Object) 数据对象是性质相同的数据元素的集合,是数据的一个子集。例如,整数数 据对象是{0,±1,±2,±3,…},字符数据对象是{a,b,c,…}。 4、数据类型(Data Type) 数据类型是高级程序设计语言中的概念,是数据的取值范围和对数据进行操 作的总和。数据类型规定了程序中对象的特性。程序中的每个变量、常量或表达 式的结果都应该属于某种确定的数据类型。例如,C#语言中的字符串类型(String, 经常写为string)。一 个String表示一个恒定不变的字符序列集合,所有的字符序 列集合构成String的取值范围。我们可以对String进行求长度、复制、连接两个 字符串等操作。 数据类型可分为两类:一类是非结构的原子类型,如C#语言中的基本类型 (整型、实型、字符型等);另一类是结构类型,它的成分可以由多个结构类型 组成,并可以分解。结构类型的成分可以是非结构的,也可以是结构的。例如, C#语言中数组的成分可以是整型等基本类型,也可以是数组等结构类型。 5、数据结构(Data Structure) 数据结构是相互之间存在一种或多种特定关系的数据元素的集合。在任何问 题中,数据元素之间都不是孤立的,而是存在着一定的关系,这种关系称为结构 (Structure)。根据数据元素之间关系的不同特性,通常有4类基本数据结构: (1) 集合(Set):如图1.1(a)所示,该结构中的数据元素除了存在“同属于一个集 合”的关系外,不存在任何其它关系。 (2) 线性结构(Linear Structure):如图1.1(b)所示,该结构中的数据元素存在着一 对一的关系。 (3) 树形结构(Tree Structure):如图1.1(c)所示,该结构中的数据元素存在着一对 多的关系。 (4) 图状结构(Graphic Structure):如图1.1(d)所示,该结构中的数据元素存在着 多对多的关系。 (a) 集合 (b) 线性结构 (c) 树形结构 (d)图状结构 图 1.1 4 类基本数据结构关系图 由于集合中的元素的关系极为松散,可用其它数据结构来表示,所以本书不 做专门介绍。关于集合的概念在1.3.1小节中有介绍。 数据结构的形式化定义为: 数据结构C#语言版) 1.1 数据结构3 数据结构(Data Structure)简记为DS,是一个二元组, DS = (D,R) 其中:D是数据元素的有限集合, R是数据元素之间关系的有限集合。 下面通过例题来进一步理解后3类数据结构。 【例1-1】 学生信息表(如表1.1所示.)是一个线性的数据结构,表中的每 一行是一个记录(在数据库信息处理系统中,表中的一个数据元素称为一个记 录)。一条记录由学号、姓名、行政班级、性别和出生年月等数据项组成。表中 数据元素之间的关系是一对一的关系。 表 1.1 学生信息表 学号 姓名 行政班级 性别 出生年月 040303001 雷洪 软件04103 男 1986.12 040303002 李春 软件04103 女 1987.3 040303003 周刚 软件04103 男 1986.9 【例1-2】 家族关系是典型的树形结构,图1.2是一个三代的家族关系。在 图中,爷爷、儿子、女儿、孙子、孙女或外孙女是一个结点(在树形结构中,数 据元素称为结点),他们之间是一对多的关系。其中,爷爷有两个儿子和一个女 儿,这是一对三的关系;一个儿子有两个儿子(爷爷的孙子),这是一对二的关 系;另一个儿子有一个儿子(爷爷的孙子)和一个女儿(爷爷的孙女),这是一 对二的关系;女儿有三个女儿(爷爷的外孙女),这是一对三的关系。树形结构 具有严格的层次关系,爷爷在树形结构的最上层,中间层是儿子和女儿,最下层 是孙子、孙女和外孙女。不能把这种关系倒过来,因为绝对不会先有儿子或女儿 再有爷爷,也不会先有孙子或孙女再有儿子、先有外孙女再有女儿。 外孙女 爷爷 儿子 儿子 女儿 孙子 孙子 孙子 孙女 外孙女 外孙女 图 1.2 家族关系图 【例1-3】 图1.3是四个城市的公路交通图,这是一个典型的图状结构。在 图中,每个城市是一个顶点(在图状结构中,数据元素称为顶点),它们之间是 多对多的关系。成都与都江堰、雅安直接通公路,都江堰与成都、青城山直接通 公路,青城山与都江堰、成都及雅安直接通公路,雅安与成都、青城山直接通公 路。这些公路构成了一个公路交通网,所以,又把图状结构称为网状结构(Network Structure) 数据结构C#语言版) 1.2 算法4 成都 都江堰 青城山 雅安 图 1.3 四城市交通图 从数据类型和数据结构的概念可知,二者的关系非常密切。数据类型可以看 作是简单的数据结构。数据的取值范围可以看作是数据元素的有限集合,而对数 据进行操作的集合可以看作是数据元素之间关系的集合。 数据结构包括数据的逻辑结构和物理结构。上述数据结构的定义就是数据的 逻辑结构(Logic Structure),数据的逻辑结构是从具体问题抽象出来的数学模型, 是为了讨论问题的方便,与数据在计算机中的具体存储没有关系。然而,我们讨 论数据结构的目的是为了在计算机中实现对它的操作,因此还需要研究在计算机 中如何表示和存储数据结构,即数据的物理结构(Physical Structure)。数据的物理 结构又称为存储结构(Storage Structure),是数据在计算机中的表示(又叫映像) 和存储,包括数据元素的表示和存储以及数据元素之间关系的表示和存储。 数据的存储结构包括顺序存储结构和链式存储结构两种。顺序存储结构 (Sequence Storage Structure)是通过数据元素在计算机存储器中的相对位置来表 示出数据元素的逻辑关系,一般把逻辑上相邻的数据元素存储在物理位置相邻的 存储单元中。在C#语言中用数组来实现顺序存储结构。因为数组所分配的存储 空间是连续的,所以数组天生就具有实现数据顺序存储结构的能力。链式存储结 构(Linked Storage Structure)对逻辑上相邻的数据元素不要求其存储位置必须相 邻。链式存储结构中的数据元素称为结点(Node),在结点中附设地址域(Address Domain)来存储与该结点相邻的结点的地址来实现结点间的逻辑关系。这个地址 称为引用(Reference),这个地址域称为引用域(Reference Domain)。 从20世纪60年代末到70年代初,出现了大型程序,软件也相对独立,人 们越来越重视数据结构,认为程序设计的实质是确定数据结构,加上设计一个好 的算法,这就是人们常说的“程序=数据结构+算法”。下一节谈谈算法的问题。 1.2 算法 从上节我们知道,算法与数据结构和程序的关系非常密切。进行程序设计时, 先确定相应的数据结构,然后再根据数据结构和问题的需要设计相应的算法。由 于篇幅所限,下面只从算法的特性、算法的评价标准和算法的时间复杂度等三个 方面进行介绍。 1.2.1 算法的特性 算法(Algorithm)是对某一特定类型的问题的求解步骤的一种描述,是指令的 有限序列。其中的每条指令表示一个或多个操作。一个算法应该具备以下5个特 性: 1、有穷性(Finity):一个算法总是在执行有穷步之后结束,即算法的执行时间是 有限的。 2、确定性(Unambiguousness):算法的每一个步骤都必须有确切的含义,即无二 义,并且对于相同的输入只能有相同的输出。 3、输入(Input):一个算法具有零个或多个输入。它即是在算法开始之前给出的 数据结构C#语言版) 1.2 算法5 量。这些输入是某数据结构中的数据对象。 4、 输出(Output):一个算法具有一个或多个输出,并且这些输出与输入之间存 在着某种特定的关系。 5、 能行性(realizability):算法中的每一步都可以通过已经实现的基本运算的有 限次运行来实现。 算法的含义与程序非常相似,但二者有区别。一个程序不一定满足有穷性。 例如操作系统,只要整个系统不遭破坏,它将永远不会停止。还有,一个程序只 能用计算机语言来描述,也就是说,程序中的指令必须是机器可执行的,而算法 不一定用计算机语言来描述,自然语言、框图、伪代码都可以描述算法。 在本书中我们尽可能采用C#语言来描述和实现算法,使读者能够阅读或上 机执行,以便更好地理解算法。 1.2.2 算法的评价标准 对于一个特定的问题,采用的数据结构不同,其设计的算法一般也不同,即 使在同一种数据结构下,也可以采用不同的算法。那么,对于解决同一问题的不 同算法,选择哪一种算法比较合适,以及如何对现有的算法进行改进,从而设计 出更适合于数据结构的算法,这就是算法评价的问题。评价一个算法优劣的主要 标准如下: 1、正确性(Correctness)。算法的执行结果应当满足预先规定的功能和性能的要求, 这是评价一个算法的最重要也是最基本的标准。算法的正确性还包括对于输入、 输出处理的明确而无歧义的描述。 2、可读性(Readability)。算法主要是为了人阅读和交流,其次才是机器的执行。 所以,一个算法应当思路清晰、层次分明、简单明了、易读易懂。即使算法已转 变成机器可执行的程序,也需要考虑人能较好地阅读理解。同时,一个可读性强 的算法也有助于对算法中隐藏错误的排除和算法的移植。 3、健壮性(Robustness)。一个算法应该具有很强的容错能力,当输入不合法的数 据时,算法应当能做适当的处理,使得不至于引起严重的后果。健壮性要求表明 算法要全面细致地考虑所有可能出现的边界情况和异常情况,并对这些边界情况 和异常情况做出妥善的处理,尽可能使算法没有意外的情况发生。 4、运行时间(Running Time)。运行时间是指算法在计算机上运行所花费的时间, 它等于算法中每条语句执行时间的总和。对于同一个问题如果有多个算法可供选 择,应尽可能选择执行时间短的算法。一般来说,执行时间越短,性能越好。 5、占用空间(Storage Space)。占用空间是指算法在计算机上存储所占用的存储空 间,包括存储算法本身所占用的存储空间、算法的输入及输出数据所占用的存储 空间和算法在运行过程中临时占用的存储空间。算法占用的存储空间是指算法执 行过程中所需要的最大存储空间,对于一个问题如果有多个算法可供选择,应尽 可能选择存储量需求低的算法。实际上,算法的时间效率和空间效率经常是一对 矛盾,相互抵触。我们要根据问题的实际需要进行灵活的处理,有时需要牺牲空 间来换取时间,有时需要牺牲时间来换取空间。 通常把算法在运行过程中临时占用的存储空间的大小叫算法的空间复杂度 (Space Complexity)。算法的空间复杂度比较容易计算,它主要包括局部变量所占 用的存储空间和系统为实现递归所使用的堆栈占用的存储空间。 如果算法是用计算机语言来描述的,还要看程序代码量的大小。对于同一个 问题,在用上面5条标准评价的结果相同的情况下,代码量越少越好。实际上, 代码量越大,占用的存储空间会越多,程序的运行时间也可能越长,出错的可能 数据结构C#语言版) 1.2 算法6 性也越大,阅读起来也越麻烦。 在以上标准中,本书主要考虑程序的运行时间,也考虑执行程序所占用的空 间。影响程序运行时间的因素很多,包括算法本身、输入的数据以及运行程序的 计算机系统等。计算机的性能由以下因素决定: 1、硬件条件。包括所使用的处理器的类型和速度(比如,使用双核处理器还是 单核处理器)、可使用的内存(缓存和RAM)以及可使用的外存等。 2、实现算法所使用的计算机语言。实现算法的语言级别越高,其执行效率相对 越低。 3、所使用的语言的编译器/解释器。一般而言,编译的执行效率高于解释,但解 释具有更大的灵活性。 4、所使用的操作系统软件。操作系统的功能主要是管理计算机系统的软件和硬 件资源,为计算机用户方便使用计算机提供一个接口。各种语言处理程序如编译 程序、解释程序等和应用程序都在操作系统的控制下运行。 1.2.3 算法的时间复杂度 一个算法的时间复杂度(Time Complexity)是指该算法的运行时间与问题规 模的对应关系。一个算法是由控制结构和原操作构成的,其执行的时间取决于二 者的综合效果。为了便于比较同一问题的不同算法,通常把算法中基本操作重复 执行的次数(频度)作为算法的时间复杂度。算法中的基本操作一般是指算法中 最深层循环内的语句,因此,算法中基本操作语句的频度是问题规模n的某个函 数f(n),记作:T(n)=O(f(n))。其中“O”表示随问题规模n的增大,算法执行时 间的增长率和f(n)的增长率相同,或者说,用“O”符号表示数量级的概念。例 如,如 )1n(n 2 1 )n(T −= ,则 )1n(n 2 1 −的数量级与n2 相同,所以T(n)=O(n2 )。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哈桑indie

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值