19个核心算法(C#版)

文章目录

  • 基础排序算法
    • [1. 冒泡排序 (Bubble Sort)](#1. 冒泡排序 (Bubble Sort))
    • [2. 快速排序 (Quick Sort)](#2. 快速排序 (Quick Sort))
    • [3. 插入排序 (Insertion Sort)](#3. 插入排序 (Insertion Sort))
    • [4. 选择排序 (Selection Sort)](#4. 选择排序 (Selection Sort))
  • 进阶搜索与查找
    • [5. 归并排序 (Merge Sort)](#5. 归并排序 (Merge Sort))
    • [6. 堆排序 (Heap Sort)](#6. 堆排序 (Heap Sort))
    • [7. 深度优先搜索 (DFS)](#7. 深度优先搜索 (DFS))
    • [8. 二分查找 (Binary Search)](#8. 二分查找 (Binary Search))
  • 算法设计思想
    • [9. 动态规划 (DP)](#9. 动态规划 (DP))
    • [10. 贪心算法 (Greedy)](#10. 贪心算法 (Greedy))
    • [11. 回溯算法 (Backtracking)](#11. 回溯算法 (Backtracking))
    • [12. 递归算法 (Recursion)](#12. 递归算法 (Recursion))
  • 复杂结构与数学算法
    • [13. 哈希算法 (Hashing)](#13. 哈希算法 (Hashing))
    • [14. 贝叶斯算法 (Naive Bayes)](#14. 贝叶斯算法 (Naive Bayes))
    • [15. 分治算法 (Divide and Conquer)](#15. 分治算法 (Divide and Conquer))
    • [16. K-Means 聚类](#16. K-Means 聚类)
    • [17. 迪杰斯特拉算法 (Dijkstra)](#17. 迪杰斯特拉算法 (Dijkstra))
    • [18. 红黑树 (Red-Black Tree)](#18. 红黑树 (Red-Black Tree))
    • [19. 布隆过滤器 (Bloom Filter)](#19. 布隆过滤器 (Bloom Filter))

基础排序算法

1. 冒泡排序 (Bubble Sort)

本质: 通过相邻元素的"两两比较"和"位置交换",每轮把最大的放到末尾。

csharp 复制代码
public static void BubbleSort(int[] arr)
{
    for (int i = 0; i < arr.Length - 1; i++)
    {
        for (int j = 0; j < arr.Length - 1 - i; j++)
        {
            if (arr[j] > arr[j + 1])
            {
                (arr[j], arr[j + 1]) = (arr[j + 1], arr[j]);
            }
        }
    }
}

2. 快速排序 (Quick Sort)

本质: 选一个基准点 (Pivot),小的放左边,大的放右边,递归执行。

csharp 复制代码
public static void QuickSort(int[] arr, int left, int right)
{
    if (left >= right) return;
    int pivot = arr[left];
    int i = left, j = right;
    while (i < j)
    {
        while (i < j && arr[j] >= pivot) j--;
        arr[i] = arr[j];
        while (i < j && arr[i] <= pivot) i++;
        arr[j] = arr[i];
    }
    arr[i] = pivot;
    QuickSort(arr, left, i - 1);
    QuickSort(arr, i + 1, right);
}

3. 插入排序 (Insertion Sort)

本质: 将未排序序列中的元素,在已排序序列中从后向前扫描,找到相应位置并插入。

csharp 复制代码
public static void InsertionSort(int[] arr)
{
    for (int i = 1; i < arr.Length; i++)
    {
        int current = arr[i];
        int j = i - 1;
        while (j >= 0 && arr[j] > current)
        {
            arr[j + 1] = arr[j];
            j--;
        }
        arr[j + 1] = current;
    }
}

4. 选择排序 (Selection Sort)

本质: 每一轮都从剩余未排序元素中"选中"最小的一个,放到已排序序列的末尾。

csharp 复制代码
public static void SelectionSort(int[] arr)
{
    for (int i = 0; i < arr.Length - 1; i++)
    {
        int minIndex = i;
        for (int j = i + 1; j < arr.Length; j++)
        {
            if (arr[j] < arr[minIndex])
                minIndex = j;
        }
        (arr[i], arr[minIndex]) = (arr[minIndex], arr[i]);
    }
}

进阶搜索与查找

5. 归并排序 (Merge Sort)

本质: 将数组拆成最小单元,再两两有序合并。

csharp 复制代码
public static void MergeSort(int[] arr, int left, int right)
{
    if (left >= right) return;
    int mid = (left + right) / 2;
    MergeSort(arr, left, mid);
    MergeSort(arr, mid + 1, right);
    Merge(arr, left, mid, right);
}

private static void Merge(int[] arr, int left, int mid, int right)
{
    int[] temp = new int[right - left + 1];
    int i = left, j = mid + 1, k = 0;
    while (i <= mid && j <= right)
    {
        temp[k++] = arr[i] <= arr[j] ? arr[i++] : arr[j++];
    }
    while (i <= mid) temp[k++] = arr[i++];
    while (j <= right) temp[k++] = arr[j++];
    for (int p = 0; p < temp.Length; p++)
        arr[left + p] = temp[p];
}

6. 堆排序 (Heap Sort)

本质: 利用大顶堆的性质,把数组构造成堆,再依次取出堆顶元素。

csharp 复制代码
public static void HeapSort(int[] arr)
{
    for (int i = arr.Length / 2 - 1; i >= 0; i--)
        Heapify(arr, arr.Length, i);
    for (int i = arr.Length - 1; i > 0; i--)
    {
        (arr[0], arr[i]) = (arr[i], arr[0]);
        Heapify(arr, i, 0);
    }
}

private static void Heapify(int[] arr, int n, int i)
{
    int largest = i;
    int left = 2 * i + 1;
    int right = 2 * i + 2;
    if (left < n && arr[left] > arr[largest]) largest = left;
    if (right < n && arr[right] > arr[largest]) largest = right;
    if (largest != i)
    {
        (arr[i], arr[largest]) = (arr[largest], arr[i]);
        Heapify(arr, n, largest);
    }
}

7. 深度优先搜索 (DFS)

本质: 从起点出发,尽可能深地访问每个分支,直到无法前进再回溯

csharp 复制代码
public class DFSExample
{
    private static List<int>[] adj;
    private static bool[] visited;

    public static void DFS(int node)
    {
        Console.Write(node + " ");
        visited[node] = true;
        foreach (int neighbor in adj[node])
        {
            if (!visited[neighbor])
                DFS(neighbor);
        }
    }

    public static void Main()
    {
        int n = 5;
        adj = new List<int>[n];
        visited = new bool[n];
        for (int i = 0; i < n; i++) adj[i] = new List<int>();
        adj[0].Add(1); adj[0].Add(2);
        adj[1].Add(3); adj[2].Add(4);
        DFS(0); // 输出: 0 1 3 2 4
    }
}

8. 二分查找 (Binary Search)

本质: 在有序数组中,每次取中间元素和目标值比较,缩小一半范围。前提是数组必须有序。

csharp 复制代码
public static int BinarySearch(int[] arr, int target)
{
    int left = 0, right = arr.Length - 1;
    while (left <= right)
    {
        int mid = left + (right - left) / 2;
        if (arr[mid] == target) return mid;
        if (arr[mid] < target) left = mid + 1;
        else right = mid - 1;
    }
    return -1;
}

算法设计思想

9. 动态规划 (DP)

本质: 拆分重叠子问题,用表格记录中间结果(避免重复计算)。
把大问题拆成重叠的子问题,记录子问题的解避免重复计算(以斐波那契为例)

csharp 复制代码
// 典型:01背包或爬楼梯
public int ClimbStairs(int n)
{
    if (n <= 2) return n;
    int a = 1, b = 2;
    for (int i = 3; i <= n; i++)
        (a, b) = (b, a + b);
    return b;
}

// 斐波那契
public static int FibonacciDP(int n)
{
    if (n <= 1) return n;
    int[] dp = new int[n + 1];
    dp[0] = 0; dp[1] = 1;
    for (int i = 2; i <= n; i++)
        dp[i] = dp[i - 1] + dp[i - 2];
    return dp[n];
}

10. 贪心算法 (Greedy)

本质: 每一步都拿眼前的最优解,不考虑全局,每一步都做出当前最优的选择,希望得到全局最优解(以硬币找零为例)。

csharp 复制代码
public static int CoinChangeGreedy(int[] coins, int amount)
{
    Array.Sort(coins);
    int count = 0;
    for (int i = coins.Length - 1; i >= 0; i--)
    {
        while (amount >= coins[i])
        {
            amount -= coins[i];
            count++;
        }
    }
    return amount == 0 ? count : -1;
}

11. 回溯算法 (Backtracking)

本质: 尝试所有可能的解,遇到错误就回溯(以全排列为例)。

csharp 复制代码
public static IList<IList<int>> Permute(int[] nums)
{
    IList<IList<int>> result = new List<IList<int>>();
    Backtrack(nums, new List<int>(), new bool[nums.Length], result);
    return result;
}

private static void Backtrack(int[] nums, List<int> path, bool[] used, IList<IList<int>> result)
{
    if (path.Count == nums.Length)
    {
        result.Add(new List<int>(path));
        return;
    }
    for (int i = 0; i < nums.Length; i++)
    {
        if (used[i]) continue;
        used[i] = true;
        path.Add(nums[i]);
        Backtrack(nums, path, used, result);
        path.RemoveAt(path.Count - 1);
        used[i] = false;
    }
}

12. 递归算法 (Recursion)

**本质:**函数直接或间接调用自身(以阶乘为例)

csharp 复制代码
public static int Factorial(int n)
{
    if (n == 0) return 1;
    return n * Factorial(n - 1);
}

复杂结构与数学算法

13. 哈希算法 (Hashing)

本质: 将任意长度的数据通过映射,生成固定长度的摘要(键值对存储的基础)。

csharp 复制代码
public class HashExample
{
    public static void Main()
    {
        Dictionary<string, int> hashMap = new Dictionary<string, int>();
        hashMap["Alice"] = 25;
        hashMap["Bob"] = 30;
        Console.WriteLine(hashMap["Alice"]); // 输出 25
    }
}

14. 贝叶斯算法 (Naive Bayes)

本质: 基于贝叶斯定理的概率分类方法。这里给一个简化的文本分类示例。

  • 贝叶斯定理 = 用结果反推原因的概率
  • 贝叶斯分类 = 算属于每个类别的概率,选最大的
  • 最常用场景:文本分类、垃圾邮件、情感判断、新闻分类

它是用来算「逆概率」的公式 ------ 根据已经发生的结果,反推原因的概率。

P(A∣B)=P(B)P(B∣A)×P(A)

已经看到现象 B 发生 的情况下,原因是 A 的概率 =

  1. 【A 发生时,出现 B 的概率】
  2. × 【A 本身发生的概率】
  3. ÷ 【B 出现的总概率】

最经典的例子:垃圾邮件分类

我们要判断一封邮件:是 垃圾邮件 还是 正常邮件?

已知条件

  • 所有邮件里,50% 是垃圾邮件,50% 是正常邮件
  • 垃圾邮件里,80% 包含 "免费" 这个词
  • 正常邮件里,10% 包含 "免费" 这个词

问题

现在收到一封邮件,里面有 "免费",请问它是垃圾邮件的概率是多少?

  • A = 垃圾邮件
  • B = 邮件里有 "免费"

求:P (A|B) = 有免费 → 是垃圾邮件的概率

  1. P (B|A) = 垃圾邮件里有免费 = 80% = 0.8
  2. P (A) = 垃圾邮件本身概率 = 0.5
  3. P (B) = 所有邮件里出现免费的总概率 = 0.5×0.8 + 0.5×0.1 = 0.45

P(A∣B)=(0.8×0.5)÷0.45≈89%

结论:这封邮件有 89% 是垃圾邮件!

csharp 复制代码
public class NaiveBayes
{
    private Dictionary<string, int> spamWordCounts = new Dictionary<string, int>();
    private Dictionary<string, int> hamWordCounts = new Dictionary<string, int>();
    private int spamCount = 0, hamCount = 0;

    public void Train(string[] words, bool isSpam)
    {
        if (isSpam)
        {
            spamCount++;
            foreach (var word in words)
            {
                if (spamWordCounts.ContainsKey(word))
                    spamWordCounts[word]++;
                else
                    spamWordCounts[word] = 1;
            }
        }
        else
        {
            hamCount++;
            foreach (var word in words)
            {
                if (hamWordCounts.ContainsKey(word))
                    hamWordCounts[word]++;
                else
                    hamWordCounts[word] = 1;
            }
        }
    }

    public bool Predict(string[] words)
    {
        double spamProb = Math.Log((double)spamCount / (spamCount + hamCount));
        double hamProb = Math.Log((double)hamCount / (spamCount + hamCount));
        foreach (var word in words)
        {
            spamProb += Math.Log((spamWordCounts.ContainsKey(word) ? spamWordCounts[word] : 0) + 1) / (spamCount + 2);
            hamProb += Math.Log((hamWordCounts.ContainsKey(word) ? hamWordCounts[word] : 0) + 1) / (hamCount + 2);
        }
        return spamProb > hamProb;
    }
}

15. 分治算法 (Divide and Conquer)

本质: 分而治之,如归并、快排、二分,把问题分成多个子问题,分别解决后合并结果(和归并排序类似,这里以最大子数组和为例)。

csharp 复制代码
public static int MaxSubArray(int[] arr, int left, int right)
{
    if (left == right) return arr[left];
    int mid = (left + right) / 2;
    int leftMax = MaxSubArray(arr, left, mid);
    int rightMax = MaxSubArray(arr, mid + 1, right);
    int crossMax = MaxCrossingSum(arr, left, mid, right);
    return Math.Max(Math.Max(leftMax, rightMax), crossMax);
}

private static int MaxCrossingSum(int[] arr, int left, int mid, int right)
{
    int sum = 0, leftSum = int.MinValue;
    for (int i = mid; i >= left; i--)
    {
        sum += arr[i];
        if (sum > leftSum) leftSum = sum;
    }
    sum = 0;
    int rightSum = int.MinValue;
    for (int i = mid + 1; i <= right; i++)
    {
        sum += arr[i];
        if (sum > rightSum) rightSum = sum;
    }
    return leftSum + rightSum;
}

16. K-Means 聚类

本质: 把数据分成 K 个簇,迭代更新簇中心直到收敛。

csharp 复制代码
public class KMeans
{
    public static List<List<double[]>> Cluster(double[][] data, int k, int maxIterations)
    {
        Random rand = new Random();
        List<double[]> centroids = new List<double[]>();
        for (int i = 0; i < k; i++)
            centroids.Add(data[rand.Next(data.Length)]);

        for (int iter = 0; iter < maxIterations; iter++)
        {
            List<List<double[]>> clusters = new List<List<double[]>>();
            for (int i = 0; i < k; i++) clusters.Add(new List<double[]>());
            foreach (var point in data)
            {
                int clusterIndex = 0;
                double minDist = double.MaxValue;
                for (int i = 0; i < k; i++)
                {
                    double dist = Distance(point, centroids[i]);
                    if (dist < minDist)
                    {
                        minDist = dist;
                        clusterIndex = i;
                    }
                }
                clusters[clusterIndex].Add(point);
            }
            List<double[]> newCentroids = new List<double[]>();
            foreach (var cluster in clusters)
            {
                if (cluster.Count == 0) continue;
                double[] newCentroid = new double[cluster[0].Length];
                for (int j = 0; j < cluster[0].Length; j++)
                {
                    double sum = 0;
                    foreach (var p in cluster) sum += p[j];
                    newCentroid[j] = sum / cluster.Count;
                }
                newCentroids.Add(newCentroid);
            }
            if (centroids.SequenceEqual(newCentroids)) break;
            centroids = newCentroids;
        }
        return null;
    }

    private static double Distance(double[] a, double[] b)
    {
        double sum = 0;
        for (int i = 0; i < a.Length; i++)
            sum += Math.Pow(a[i] - b[i], 2);
        return Math.Sqrt(sum);
    }
}

17. 迪杰斯特拉算法 (Dijkstra)

本质: 图论中求单源最短路径,求单源最短路径,每次选距离起点最近的节点更新邻居距离。

csharp 复制代码
public static int[] Dijkstra(int[,] graph, int start)
{
    int n = graph.GetLength(0);
    int[] dist = new int[n];
    bool[] visited = new bool[n];
    Array.Fill(dist, int.MaxValue);
    dist[start] = 0;

    for (int i = 0; i < n; i++)
    {
        int u = -1;
        for (int j = 0; j < n; j++)
        {
            if (!visited[j] && (u == -1 || dist[j] < dist[u]))
                u = j;
        }
        visited[u] = true;
        for (int v = 0; v < n; v++)
        {
            if (!visited[v] && graph[u, v] != 0 && dist[u] + graph[u, v] < dist[v])
                dist[v] = dist[u] + graph[u, v];
        }
    }
    return dist;
}

18. 红黑树 (Red-Black Tree)

本质: 一种自平衡二叉查找树,通过颜色规则保持树的平衡。C# 中 SortedSet 底层就是类似结构,这里给一个简化的节点定义。

csharp 复制代码
public enum NodeColor { Red, Black }

public class RedBlackNode<T> where T : IComparable<T>
{
    public T Value { get; set; }
    public NodeColor Color { get; set; }
    public RedBlackNode<T> Left { get; set; }
    public RedBlackNode<T> Right { get; set; }
    public RedBlackNode<T> Parent { get; set; }

    public RedBlackNode(T value)
    {
        Value = value;
        Color = NodeColor.Red;
    }
}

// C# 标准库 SortedSet<T> 就是基于红黑树实现的,可直接使用:
public class RedBlackExample
{
    public static void Main()
    {
        SortedSet<int> set = new SortedSet<int> { 5, 3, 7, 1, 9 };
        foreach (var item in set) Console.Write(item + " "); // 输出 1 3 5 7 9
    }
}

19. 布隆过滤器 (Bloom Filter)

本质: :用多个哈希函数把元素映射到位数组中,判断元素是否可能存在。

csharp 复制代码
public class BloomFilter
{
    private readonly BitArray bits;
    private readonly int hashCount;

    public BloomFilter(int size, int hashCount)
    {
        bits = new BitArray(size);
        this.hashCount = hashCount;
    }

    public void Add(string item)
    {
        for (int i = 0; i < hashCount; i++)
        {
            int hash = GetHash(item, i) % bits.Length;
            bits.Set(hash, true);
        }
    }

    public bool MightContain(string item)
    {
        for (int i = 0; i < hashCount; i++)
        {
            int hash = GetHash(item, i) % bits.Length;
            if (!bits.Get(hash)) return false;
        }
        return true;
    }

    private int GetHash(string item, int seed)
    {
        unchecked
        {
            int hash = seed;
            foreach (char c in item)
                hash = hash * 31 + c;
            return hash & int.MaxValue;
        }
    }
}
相关推荐
sali-tec2 小时前
C# 基于OpenCv的视觉工作流-章52-交点查找
图像处理·人工智能·opencv·算法·计算机视觉
不会编程的懒洋洋2 小时前
C# Task async/await CancellationToken
笔记·c#·线程·面向对象·task·同步异步
梦想的颜色2 小时前
mongoTemplate + Java 增删改查基础介绍
数据结构·数据库·mysql
yu85939583 小时前
MATLAB连续线性化模型预测控制(SL-MPC)
算法·机器学习·matlab
ytttr8733 小时前
基于ACADO工具包的自主车道跟踪与避障MPC控制
算法
隔壁大炮3 小时前
第一章_机器学习概述_03.机器学习_算法分类
算法·机器学习·分类
WolfGang0073213 小时前
代码随想录算法训练营 Day43 | 图论 part01
算法·深度优先
叶小鸡4 小时前
小鸡玩算法-力扣HOT100-堆
数据结构·算法·leetcode