C# 实现经典排序算法
using ElementType = System.Int32; // 顶部添加此行,为待排元素的数据类型起别名(以 Int32 为例)
插入排序
- 直接插入排序
public static void StraightInsertSorting(ElementType[] list) { var flag = 0; // 存储需要进行插入的值 for (int i = 1; i < list.Length; i++) { // 判断是否需要向前插入 if (list[i] < list[i-1]) { flag = list[i]; // 将要插入的值存储下来 list[i] = list[i - 1]; // list[i] 已确定要向前插入,因此list[i-1]可向后挪一位 // 寻找目标位置 int j; for (j = i - 2; j >= 0 && list[j] > flag; j--) { list[j + 1] = list[j]; } // 找到目标位置,插入 if (j + 1 >= 0) { list[j + 1] = flag; } } } }
交换排序
-
冒泡排序
public static void BubbleSort(ElementType[] list) { var changed = true; // i 为窗口大小值,即需要进行相邻比较的次数 // list[0] 需要进行 n-1 次; list[1]: n-2; list[n-1]: 1 // 因此 i 从 n-1 开始依次递减,直至 i 为 0 for (int i = list.Length-1; i > 0 && changed; i--) { changed = false; // 相邻元素的比较与交换操作 // 只要进行了交换,则 changed 置为 true, 否则表明当前序列已满足非降序排列,不用再进入后续循环 for (int j = 0; j < i; j++) { if (list[j] > list[j + 1]) { Swap(ref list[j], ref list[j+1]); changed = true; } } } } private static void Swap(ref ElementType a, ref ElementType b) { var temp = a; a = b; b = temp; }
-
快速排序
public static void QuickSort(ElementType[] list) { // low: 0, high: n-1 QSort(list, 0, list.Length - 1); } private static void QSort(ElementType[] list, int low, int high) { if (high <= low) { return; } // 一分为二,分别快排 var pivotIndex = Partition(list, low, high); QSort(list, low, pivotIndex - 1); QSort(list, pivotIndex + 1, high); } private static int Partition(ElementType[] list, int low, int high) { var pivot = list[low]; // 枢纽元素 while (low < high) { // 只要 high 指向的元素值不小于 pivot,就继续向前移动 while (low < high && list[high] >= pivot) { high--; } // 直至找到某元素的值小于 pivot,则应该将其置于 low 区域 list[low] = list[high]; // 只要 low 指向的元素值不大于 pivot,就继续向后移动 while (low < high && list[low] <= pivot) { low++; } // 直至找到某元素的值大于 pivot,则应置于 high 区域 list[high] = list[low]; } list[low] = pivot; // 将枢纽元素归位,其左边均为不大于它的元素,右边均为不小于它的元素 return low; // 返回枢纽元素的下标 }
选择排序
-
简单选择排序
public static void SimpleSelectionSort(ElementType[] list) { for (int i = 0; i < list.Length; i++) { // 挑出 list[i] 至 list[n-1] 中值最小的元素下标 var minElemIndex = SelectMinElemIndex(list, i); // 将当前元素 list[i] 与最小元素进行交换 if (minElemIndex >= 0 && minElemIndex != i) { Swap(ref list[minElemIndex], ref list[i]); } } } private static int SelectMinElemIndex(ElementType[] list, int offset) { if (offset >= list.Length) { return -1; } // 最小值下标默认为 i 的起始值 var minElemIndex = offset; for (int i = offset; i < list.Length; i++) { // 若当前元素的值更小,则更新最小值下标 if (list[i] < list[minElemIndex]) { minElemIndex = i; } } return minElemIndex; }
-
堆排序
public static void HeapSort(ElementType[] input) { // 创建堆空间,增加 1 空闲元素,使各元素的下标,与其作为完全二叉树节点的编号相同 HeapType[] h = new HeapType[input.Length + 1]; for (int i = 0; i < input.Length; i++) { h[i + 1] = input[i]; } // 构建大顶堆, 从第一个非终端节点(因为要判断与其左右孩子的大小关系)开始向前调整 for (int i = h.Length / 2; i > 0; i--) { HeapFilter(h, i, h.Length - 1); } // 将最大元素交换至末端后,对其之前的元素再次构建大顶堆 // 保证每次交换至末端的都是范围内最大的元素 for (int i = h.Length - 1; i > 0; i--) { Swap(ref h[i], ref h[1]); HeapFilter(h, 1, i - 1); } // 将排序结果输出至原数组中 for (int i = 0; i < input.Length; i++) { input[i] = h[i + 1]; } } // 筛选,构建大顶堆 private static void HeapFilter(HeapType[] h, int insertPos, int end) { var insertedValue = h[insertPos]; int maxChildIndex; for (maxChildIndex = insertPos * 2; maxChildIndex <= end; maxChildIndex *= 2) { // 找到较大的孩子 if (maxChildIndex < end && h[maxChildIndex] < h[maxChildIndex+1]) { maxChildIndex = maxChildIndex + 1; } // 与较大的孩子比较,若双亲较大,符合大顶堆,则不用调整 if (insertedValue >= h[maxChildIndex]) { break; } // 若双亲较小,则将较大的孩子放至双亲的当前位置 h[insertPos] = h[maxChildIndex]; // 记录下最大值的节点位置,并进一步迭代,确保该节点及其孩子构成的序列也是大顶堆 insertPos = maxChildIndex; } h[insertPos] = insertedValue; }