当前位置: 首页 > news >正文

深入解析常见排序算法及其 C# 实现

在程序设计中,排序是一个非常常见且重要的操作。掌握各种排序算法对于提高算法的效率、解决实际问题非常有帮助。本文将详细介绍常见的排序算法,包括 冒泡排序选择排序插入排序归并排序快速排序计数排序基数排序,并提供 C# 语言的实现代码。

1. 冒泡排序(Bubble Sort)

冒泡排序是一种简单的排序算法,通过反复比较相邻元素并交换它们的位置,直到整个数组排好序。

原理:
  • 比较数组中的每对相邻元素,如果它们的顺序错误,就交换它们的位置。

  • 重复这一过程,直到没有更多的交换发生,此时数组已排好序。

时间复杂度:
  • 最坏情况:O(n²)

  • 最好情况(数组已排序):O(n)

C# 实现:
using System;class Program
{static void BubbleSort(int[] arr){int n = arr.Length;for (int i = 0; i < n - 1; i++){bool swapped = false;for (int j = 0; j < n - i - 1; j++){if (arr[j] > arr[j + 1])  // 如果当前元素大于下一个元素,则交换{int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;swapped = true;}}if (!swapped) break;  // 如果没有交换,说明数组已经排序好了}}static void Main(){int[] arr = { 64, 34, 25, 12, 22, 11, 90 };BubbleSort(arr);Console.WriteLine("Sorted array:");foreach (var item in arr){Console.Write(item + " ");}}
}

2. 选择排序(Selection Sort)

选择排序是一种简单的排序算法,通过每次选择未排序部分的最小(或最大)元素并将其放到已排序部分的末尾。

原理:
  • 从未排序部分中选择最小的元素,将其与当前未排序部分的第一个元素交换。

  • 重复此过程,直到整个数组排序完成。

时间复杂度:
  • 最坏情况:O(n²)

  • 最好情况:O(n²)

C# 实现:
using System;class Program
{static void SelectionSort(int[] arr){int n = arr.Length;for (int i = 0; i < n - 1; i++){int minIndex = i;for (int j = i + 1; j < n; j++){if (arr[j] < arr[minIndex])  // 找到未排序部分的最小值{minIndex = j;}}if (minIndex != i){// 交换最小值和当前元素int temp = arr[i];arr[i] = arr[minIndex];arr[minIndex] = temp;}}}static void Main(){int[] arr = { 64, 25, 12, 22, 11 };SelectionSort(arr);Console.WriteLine("Sorted array:");foreach (var item in arr){Console.Write(item + " ");}}
}

3. 插入排序(Insertion Sort)

插入排序通过将每个元素插入到已排序部分的适当位置,逐步构建有序序列。

原理:
  • 从数组的第二个元素开始,依次将每个元素插入到前面已排序部分的适当位置。

  • 重复此过程,直到整个数组排好序。

时间复杂度:
  • 最坏情况:O(n²)

  • 最好情况(数组已排序):O(n)

C# 实现:
using System;class Program
{static void InsertionSort(int[] arr){int n = arr.Length;for (int i = 1; i < n; i++)  // 从第二个元素开始处理{int key = arr[i];  // 选取当前元素int j = i - 1;while (j >= 0 && arr[j] > key)  // 查找合适的位置{arr[j + 1] = arr[j];  // 移动元素j--;}arr[j + 1] = key;  // 插入当前元素到合适的位置}}static void Main(){int[] arr = { 64, 34, 25, 12, 22, 11, 90 };InsertionSort(arr);Console.WriteLine("Sorted array:");foreach (var item in arr){Console.Write(item + " ");}}
}

4. 归并排序(Merge Sort)

归并排序是一种典型的分治算法,通过递归将数组分割成两部分,分别排序后再合并成一个有序数组。

原理:
  • 递归地将数组分成两部分,直到每部分只有一个元素。

  • 然后合并这些部分,最终得到有序数组。

时间复杂度:
  • 最坏情况:O(n log n)

  • 最好情况:O(n log n)

C# 实现:
using System;class Program
{static void Merge(int[] arr, int left, int right){if (left < right){int mid = (left + right) / 2;Merge(arr, left, mid);  // 排序左半部分Merge(arr, mid + 1, right);  // 排序右半部分MergeArrays(arr, left, mid, right);  // 合并两部分}}static void MergeArrays(int[] arr, int left, int mid, int right){int n1 = mid - left + 1;int n2 = right - mid;int[] leftArr = new int[n1];int[] rightArr = new int[n2];for (int i = 0; i < n1; i++) leftArr[i] = arr[left + i];for (int i = 0; i < n2; i++) rightArr[i] = arr[mid + 1 + i];int k = left, i = 0, j = 0;while (i < n1 && j < n2){if (leftArr[i] <= rightArr[j]){arr[k] = leftArr[i];i++;}else{arr[k] = rightArr[j];j++;}k++;}while (i < n1){arr[k] = leftArr[i];i++;k++;}while (j < n2){arr[k] = rightArr[j];j++;k++;}}static void Main(){int[] arr = { 64, 34, 25, 12, 22, 11, 90 };Merge(arr, 0, arr.Length - 1);Console.WriteLine("Sorted array:");foreach (var item in arr){Console.Write(item + " ");}}
}

5. 快速排序(Quick Sort)

快速排序通过选择一个基准元素,并将数组分成两部分,分别排序后再合并。

原理:
  • 选择一个基准元素,将数组分为比基准元素小的部分和比基准元素大的部分。

  • 递归地排序这两部分。

时间复杂度:
  • 最坏情况:O(n²)

  • 最好和平均情况:O(n log n)

C# 实现:
using System;class Program
{static void QuickSort(int[] arr, int low, int high){if (low < high){int pi = Partition(arr, low, high);  // 获取基准元素的索引QuickSort(arr, low, pi - 1);  // 排序左部分QuickSort(arr, pi + 1, high);  // 排序右部分}}static int Partition(int[] arr, int low, int high){int pivot = arr[high];  // 选择最后一个元素作为基准int i = low - 1;for (int j = low; j < high; j++){if (arr[j] < pivot){i++;int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}}int temp1 = arr[i + 1];arr[i + 1] = arr[high];arr[high] = temp1;return i + 1;}static void Main(){int[] arr = { 64, 34, 25, 12, 22, 11, 90 };QuickSort(arr, 0, arr.Length - 1);Console.WriteLine("Sorted array:");foreach (var item in arr){Console.Write(item + " ");}}
}

6. 计数排序(Counting Sort)

计数排序是一种非比较排序算法,适用于元素值

较小且数据范围有限的场景。

原理:
  • 通过统计数组中每个元素的出现次数,来确定每个元素在排序后的数组中的位置。

时间复杂度:
  • O(n + k),其中 n 是数组的长度,k 是元素值的范围。

C# 实现:
using System;class Program
{static void CountingSort(int[] arr){int max = arr[0];foreach (var num in arr) if (num > max) max = num;int[] count = new int[max + 1];foreach (var num in arr) count[num]++;int index = 0;for (int i = 0; i <= max; i++){while (count[i] > 0){arr[index++] = i;count[i]--;}}}static void Main(){int[] arr = { 4, 2, 2, 8, 3, 3, 1 };CountingSort(arr);Console.WriteLine("Sorted array:");foreach (var item in arr){Console.Write(item + " ");}}
}

7. 基数排序(Radix Sort)

基数排序是一种非比较的排序算法,通过逐位排序来完成排序操作。

原理:
  • 从最低位开始,按位进行排序,逐步向高位排序,直到所有位数排序完成。

时间复杂度:
  • O(nk),其中 n 是元素数量,k 是元素的位数。

C# 实现:
using System;class Program
{static void CountingSortForRadix(int[] arr, int exp){int n = arr.Length;int[] output = new int[n];int[] count = new int[10];for (int i = 0; i < n; i++){count[(arr[i] / exp) % 10]++;}for (int i = 1; i < 10; i++){count[i] += count[i - 1];}for (int i = n - 1; i >= 0; i--){output[count[(arr[i] / exp) % 10] - 1] = arr[i];count[(arr[i] / exp) % 10]--;}for (int i = 0; i < n; i++){arr[i] = output[i];}}static void RadixSort(int[] arr){int max = arr[0];foreach (var num in arr) if (num > max) max = num;for (int exp = 1; max / exp > 0; exp *= 10){CountingSortForRadix(arr, exp);}}static void Main(){int[] arr = { 170, 45, 75, 90, 802, 24, 2, 66 };RadixSort(arr);Console.WriteLine("Sorted array:");foreach (var item in arr){Console.Write(item + " ");}}
}

总结:

每种排序算法都有其适用的场景。冒泡排序选择排序插入排序适用于小规模数据,时间复杂度为 O(n²)。归并排序快速排序基数排序适用于大规模数据,时间复杂度为 O(n log n) 或 O(nk)。计数排序适用于数据范围较小的情况。理解这些算法的原理并掌握其实现将帮助你在实际开发中解决不同的排序问题。

相关文章:

  • 初识Redis · 分布式锁
  • Go 语言中的 `recover()` 函数详解
  • 医疗生态全域智能化:从技术革新到价值重塑的深度探析
  • 基于Spring Boot 3.0、ShardingSphere、PostgreSQL或达梦数据库的分库分表
  • Go语言之路————接口、泛型
  • 在Anolis OS 8上部署Elasticsearch 7.16.1与JDK 11的完整指南
  • 首页数据展示
  • keep-alive具体使用方法
  • C++多线程与锁机制
  • MySQL 在 CentOS 7 环境下的安装教程
  • 如何解决 Xcode 签名证书和 Provisioning Profile 过期问题
  • 【Linux网络】深入解析I/O多路转接 - Select
  • 基于STM32的DS18B20简易温控系统LCD1602显示仿真设计
  • 论文阅读:2024 arxiv FlipAttack: Jailbreak LLMs via Flipping
  • AI 的未来是开源?DeepSeek 正在书写新篇章!
  • AI+零售:智能推荐、无人店与供应链管理的未来
  • 超越单体:进入微服务世界与Spring Cloud概述
  • 如何知道Ubuntu的端口是否被占用,被那个进程占用?如何终止进程
  • 大数据学习(115)-hive与impala
  • Redis性能优化终极指南:从原理到实战的深度调优策略
  • 这就是上海!
  • 中国农业国际交流协会会长王守聪失联已逾半年,协会启动罢免
  • 五一假期上海推出首批16条“市民健康路线”,这些健康提示请收好
  • 众信旅游:去年盈利1.06亿元,同比增长228.18%
  • 人到中年为何腰围变粗?科学家发现腹部脂肪增加的细胞元凶
  • “五一”假期全国口岸日均出入境人员将达215万人次