[C++/数据结构] C#语言教程(初级+中级+高级+数据结构算法)(14.8G)

43 阅读5分钟

C#数据结构与算法:从基础到高阶

数据结构与算法是计算机科学的基石,在C#开发中更是提升代码性能、优化资源利用的核心工具。本文将从基础线性结构出发,逐步深入树、图等复杂结构,结合C#语言特性与实际代码示例,解析数据结构与算法的设计精髓。

一、线性结构:从数组到队列

1. 数组的底层优化

数组是C#中最基础的线性结构,其内存连续分配的特性使其具备O(1)时间复杂度的随机访问能力。例如,处理图像像素数据时,数组的缓存友好性可显著提升性能:

csharp
1// 图像灰度化处理示例
2int[,] image = new int[1024, 768]; // 假设为1024x768分辨率
3for (int y = 0; y < 768; y++) {
4    for (int x = 0; x < 1024; x++) {
5        image[x, y] = (image[x, y] >> 1) & 0x7F; // 简单灰度化
6    }
7}

此代码利用数组的连续内存特性,通过双重循环高效遍历所有像素点。但数组的固定长度限制了其动态扩展能力,此时可使用List<T>动态数组实现类似功能:

csharp
1List<int> dynamicList = new List<int>(100); // 初始容量100
2dynamicList.Add(10); // 自动扩容

2. 链表的灵活操作

链表通过节点指针连接实现动态内存分配,适合频繁插入/删除的场景。C#的LinkedList<T>已封装双向链表实现:

csharp
1LinkedList<string> tasks = new LinkedList<string>();
2tasks.AddLast("任务1");
3tasks.AddAfter(tasks.First, "任务2"); // 在"任务1"后插入
4LinkedListNode<string> node = tasks.Find("任务2");
5tasks.Remove(node); // 删除节点

该示例展示了链表在任务调度中的优势:插入/删除操作无需移动元素,时间复杂度为O(1)。

3. 栈与队列的场景化应用

栈的LIFO特性使其成为递归回溯的理想选择,而队列的FIFO特性则广泛应用于消息队列。C#标准库提供了Stack<T>Queue<T>泛型实现:

csharp
1// 栈实现括号匹配检测
2Stack<char> stack = new Stack<char>();
3string input = "{[()]}";
4foreach (char c in input) {
5    if (c == '(' || c == '[' || c == '{') stack.Push(c);
6    else {
7        if (stack.Count == 0) return false;
8        char top = stack.Pop();
9        if ((c == ')' && top != '(') || 
10            (c == ']' && top != '[') || 
11            (c == '}' && top != '{')) return false;
12    }
13}
14return stack.Count == 0;

此代码通过栈的压入/弹出操作,高效验证括号匹配性。

二、非线性结构:树与图的深度探索

1. 二叉搜索树的平衡优化

二叉搜索树(BST)通过左右子树分治实现高效查找,但极端情况下可能退化为链表。AVL树通过旋转操作维持平衡,保证O(log n)的查找效率:

csharp
1class AVLNode {
2    public int Value;
3    public AVLNode Left, Right;
4    public int Height;
5    public AVLNode(int value) { Value = value; Height = 1; }
6}
7
8// 右旋操作示例
9AVLNode RightRotate(AVLNode y) {
10    AVLNode x = y.Left;
11    AVLNode T2 = x.Right;
12    x.Right = y;
13    y.Left = T2;
14    y.Height = Math.Max(Height(y.Left), Height(y.Right)) + 1;
15    x.Height = Math.Max(Height(x.Left), Height(x.Right)) + 1;
16    return x;
17}

该代码通过节点旋转重构树结构,维持平衡因子在[-1,1]范围内。

2. 图的遍历算法实践

图结构在社交网络、路径规划等领域应用广泛。C#可通过邻接表表示图,并实现深度优先搜索(DFS)和广度优先搜索(BFS):

csharp
1// 图的邻接表表示
2Dictionary<int, List<int>> graph = new Dictionary<int, List<int>>();
3graph[0] = new List<int> { 1, 2 };
4graph[1] = new List<int> { 2 };
5graph[2] = new List<int> { 0, 3 };
6graph[3] = new List<int> { 3 };
7
8// BFS实现
9void BFS(Dictionary<int, List<int>> graph, int start) {
10    Queue<int> queue = new Queue<int>();
11    HashSet<int> visited = new HashSet<int>();
12    queue.Enqueue(start);
13    visited.Add(start);
14    while (queue.Count > 0) {
15        int vertex = queue.Dequeue();
16        Console.Write(vertex + " ");
17        foreach (int neighbor in graph[vertex]) {
18            if (!visited.Contains(neighbor)) {
19                visited.Add(neighbor);
20                queue.Enqueue(neighbor);
21            }
22        }
23    }
24}

此代码通过队列实现BFS,逐层遍历图节点,适用于最短路径查找等场景。

三、算法设计范式:从分治到动态规划

1. 快速排序的分治策略

快速排序通过选择基准元素将数组分为两部分,递归排序子数组:

csharp
1void QuickSort(int[] arr, int left, int right) {
2    if (left < right) {
3        int pivotIndex = Partition(arr, left, right);
4        QuickSort(arr, left, pivotIndex - 1);
5        QuickSort(arr, pivotIndex + 1, right);
6    }
7}
8
9int Partition(int[] arr, int left, int right) {
10    int pivot = arr[right];
11    int i = left - 1;
12    for (int j = left; j < right; j++) {
13        if (arr[j] < pivot) {
14            i++;
15            Swap(ref arr[i], ref arr[j]);
16        }
17    }
18    Swap(ref arr[i + 1], ref arr[right]);
19    return i + 1;
20}

该实现通过分治策略将时间复杂度优化至平均O(n log n),但最坏情况下可能退化为O(n²)。

2. 动态规划的背包问题

0-1背包问题通过构建状态转移表避免重复计算:

csharp
1int Knapsack(int[] weights, int[] values, int capacity) {
2    int n = weights.Length;
3    int[,] dp = new int[n + 1, capacity + 1];
4    for (int i = 1; i <= n; i++) {
5        for (int w = 1; w <= capacity; w++) {
6            if (weights[i - 1] <= w) {
7                dp[i, w] = Math.Max(values[i - 1] + dp[i - 1, w - weights[i - 1]], dp[i - 1, w]);
8            } else {
9                dp[i, w] = dp[i - 1, w];
10            }
11        }
12    }
13    return dp[n, capacity];
14}

此代码通过二维数组存储中间结果,将时间复杂度从暴力枚举的O(2ⁿ)降至O(nW)。

结语

从数组的内存优化到图的遍历算法,从快速排序的分治策略到动态规划的状态转移,C#的数据结构与算法体系为开发者提供了强大的工具集。掌握这些核心知识,不仅能提升代码效率,更能在复杂问题求解中游刃有余。