持续学习&持续更新中…
学习态度:脚踏实地
排序
排序
初识排序
十大排序算法
排序算法的稳定性
原地算法
常见的递推式与复杂度
抽象基类Sort
简单实现
public abstract class Sort<E extends Comparable<E>> {
private Comparator<E> comparator;
protected E[] array;
protected int cmpCount; // 比较次数
protected int swapCount; // 交换次数
public Sort() {
this(null);
}
public Sort(Comparator<E> comparator) {
this.comparator = comparator;
}
public void sort(E[] array) {
if (null == array || array.length < 2) {
return;
}
this.array = array;
sort();
System.out.println(this.getClass().getSimpleName() + " 比较次数:" + cmpCount + " 交换次数:" + swapCount);
}
protected int compare(E e1, E e2) {
cmpCount++;
return comparator == null ? e1.compareTo(e2) : comparator.compare(e1, e2);
}
protected void swap(int index1, int index2) {
E temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
swapCount++;
}
protected abstract void sort();
}
完善实现
public abstract class Sort<T extends Comparable<T>> implements Comparable<Sort<T>> {
protected T[] array;
private int cmpCount;
private int swapCount;
private long time;
private final DecimalFormat fmt = new DecimalFormat("#.00");
public void sort(T[] array) {
if (array == null || array.length < 2) return;
this.array = array;
long begin = System.currentTimeMillis();
sort();
time = System.currentTimeMillis() - begin;
}
@Override
public int compareTo(Sort<T> o) {
int result = (int) (time - o.time);
if (result != 0) return result;
result = cmpCount - o.cmpCount;
if (result != 0) return result;
return swapCount - o.swapCount;
}
protected abstract void sort();
/*
* 返回值等于0,代表 array[i1] == array[i2]
* 返回值小于0,代表 array[i1] < array[i2]
* 返回值大于0,代表 array[i1] > array[i2]
*/
protected int cmp(int i1, int i2) {
cmpCount++;
return array[i1].compareTo(array[i2]);
}
protected int cmp(T v1, T v2) {
cmpCount++;
return v1.compareTo(v2);
}
protected void swap(int i1, int i2) {
swapCount++;
T tmp = array[i1];
array[i1] = array[i2];
array[i2] = tmp;
}
@Override
public String toString() {
String timeStr = "耗时:" + (time / 1000.0) + "s(" + time + "ms)";
String compareCountStr = "比较:" + numberString(cmpCount);
String swapCountStr = "交换:" + numberString(swapCount);
String stableStr = "稳定性:" + isStable();
return "【" + getClass().getSimpleName() + "】\n"
+ stableStr + " \t"
+ timeStr + " \t"
+ compareCountStr + "\t "
+ swapCountStr + "\n"
+ "------------------------------------------------------------------";
}
private String numberString(int number) {
if (number < 10000) return "" + number;
if (number < 100000000) return fmt.format(number / 10000.0) + "万";
return fmt.format(number / 100000000.0) + "亿";
}
private boolean isStable() {
Student[] students = new Student[20];
for (int i = 0; i < students.length; i++) {
students[i] = new Student(i * 10, 10);
}
sort((T[]) students);
for (int i = 1; i < students.length; i++) {
int score = students[i].score;
int prevScore = students[i - 1].score;
if (score != prevScore + 10) return false;
}
return true;
}
}
冒泡排序
// 旧写法(不推荐使用了)
private static void method1(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) { // n - 1 个循环
for (int j = 0; j < arr.length - 1 - i; j++) { // n - 1 次比较
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
优化1
private static void method(int[] arr) {
for (int end = arr.length; end > 0; end--) {
boolean sorted = true;
for (int begin = 1; begin < end; begin++) {
if (arr[begin - 1] > arr[begin]) {
int temp = arr[begin];
arr[begin] = arr[begin - 1];
arr[begin - 1] = temp;
sorted = false;
}
}
if (sorted) break;
}
}
优化2
public static void sort3(Integer[] arr) {
for (int end = arr.length - 1; end > 0; end--) {
// sortedIndex在元素已经排好序时有用
// 如果有序的话,初始值赋为1,1-0 <= 0,可以让循环结束
// 如果有序的话,初始值赋为1,1经过内层循环后不会改变,1-0 <= 0,就可以让循环结束
// 如果不有序的话,sortedIndex会记录最后一次交换的位置
int sortedIndex = 1;
for (int begin = 1; begin <= end; begin++) {
if (arr[begin - 1] > arr[begin]) {
int temp = arr[begin - 1];
arr[begin - 1] = arr[begin];
arr[begin] = temp;
sortedIndex = begin;
}
}
end = sortedIndex;
}
}
重构后:
@Override
protected void sort() {
for (int end = array.length - 1; end > 0; end--) {
int sortedIndex = 1;
for (int begin = 1; begin <= end; begin++) {
if (compare(array[begin - 1], array[begin]) > 0) {
swap(begin - 1, begin);
sortedIndex = begin;
}
}
end = sortedIndex;
}
}
选择排序
public static void methodMax(Integer[] arr) {
for (int end = arr.length; end > 0; end--) {
int maxIndex = 0;
for (int begin = 1; begin < end; begin++) {
if (arr[begin] > arr[maxIndex]) {
maxIndex = begin;
}
}
int temp = arr[end - 1];
arr[end - 1] = arr[maxIndex];
arr[maxIndex] = temp;
}
}
public static void methodMin(Integer[] 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;
}
}
int temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
重构后:
@Override
protected void sort() {
for (int end = array.length - 1; end > 0; end--) {
int maxIndex = 0;
for (int begin = 1; begin <= end; begin++) {
if (compare(array[begin], array[maxIndex]) > 0) {
maxIndex = begin;
}
}
swap(end, maxIndex);
}
}
堆排序
public class HeapSort<E> extends Sort<E> {
private int size;
@Override
protected void sort() {
this.size = array.length;
heapify();
while (size > 1) {
swap(0, size - 1);
size--;
siftDown(0);
}
}
private void heapify() {
for (int i = (size >> 1) - 1; i >= 0; i--) {
siftDown(i);
}
}
private void siftDown(int index) {
E element = array[index];
int half = size >> 1;
while (index < half) {
int maxIndex;
E maxChild;
int leftChildIndex = index + index + 1;
E leftChild = array[leftChildIndex];
maxIndex = leftChildIndex;
maxChild = leftChild;
int rightChildIndex = leftChildIndex + 1;
if (rightChildIndex < size) {
E rightChild = array[rightChildIndex];
if (compare(leftChild, rightChild) < 0) {
maxIndex = rightChildIndex;
maxChild = rightChild;
}
}
if (compare(element, maxChild) >= 0) {
break;
}
array[index] = maxChild;
index = maxIndex;
}
array[index] = element;
}
}
插入排序
插入排序
/* 从1开始扫描每一个元素,将这个元素和前面已经排好序的元素进行比较,插入到合适的位置 */
protected void sort() {
for (int begin = 1; begin < array.length; begin++) {
int current = begin;
while (current > 0 && cmp(current, current - 1) < 0) {
swap(current, current - 1);
current--;
}
}
}
逆序对
优化1—挪动元素
// 优化:将“交换”更改为“挪动”
@Override
protected void sort() {
for (int begin = 1; begin < array.length; begin++) {
int current = begin;
E element = array[current];
while (current > 0 && cmp(element, array[current - 1]) < 0) {
array[current] = array[current - 1];
current--;
}
array[current] = element;
}
}
二分搜索
public class BinarySearch {
public static final int ELEMENT_NOT_FOUND = -1;
/* 左闭右开 */
public static int indexOf(Integer[] array, int value) {
if (null == array || array.length == 0) return ELEMENT_NOT_FOUND;
int begin = 0;
int end = array.length;
while (begin < end) { // end - begin > 0 => 该区间范围内的元素个数>0
int mid = (begin + end) >> 1;
Integer midElement = array[mid];
if (value < midElement) {
end = mid;
} else if (value > midElement) {
begin = mid + 1;
} else {
return mid;
}
}
return ELEMENT_NOT_FOUND;
}
}
优化2—二分搜索优化
// 优化:使用二分搜索确定插入的位置,减少比较次数
@Override
protected void sort() {
for (int begin = 1; begin < array.length; begin++) {
int current = begin;
E element = array[current];
// 要求获取第一个大于element的位置
int b = 0;
int e = current;
while (b < e) {
int m = (b + e) >> 1;
E midElement = array[m];
if (cmp(element, midElement) < 0) {
e = m;
} else {
b = m + 1;
}
}
while (current > b) {
array[current] = array[current - 1];
current--;
}
array[b] = element;
}
}
归并排序
归并排序
复杂度分析
divide
merge
merge
merge细节
- ai应该是从begin开始的
左边先结束
-
左边先于右边结束的话,就可以提前结束了,因为右边的元素本来就是大的,处于右边,无须额外操作了。
-
左边结束后,就不用做其他操作了,就可以结束当前merge了。
右边先结束
右边先于左边结束的话,将左边数组中剩余的元素一个一个的全部挪到右边数组即可。
merge实现
// 牢记左闭右开
public class MergeSort<T extends Comparable<T>> extends Sort<T> {
private T[] leftArray;
@Override
protected void sort() {
leftArray = (T[]) new Comparable[array.length >> 1];
sort(0, array.length);
}
private void sort(int begin, int end) {
if (end - begin < 2) return; // 如果只有一个元素就不用排序了
int middle = (begin + end) >> 1;
sort(begin, middle);
sort(middle, end);
merge(begin, middle, end);
}
private void merge(int begin, int middle, int end) {
int li = 0, le = middle - begin;
int ri = middle, re = end;
int ai = begin;
// for (int i = 0; i < le; i++) {
// leftArray[i] = array[begin + i];
// }
System.arraycopy(array, begin, leftArray, 0, le);
while (li < le) { // 左边结束后,就不用做其他操作了
if (ri < re && cmp(array[ri], leftArray[li]) < 0) {
array[ai++] = array[ri++];
} else {
array[ai++] = leftArray[li++];
}
}
}
}
merge其他画法
快速排序
简介
nlog(n)级别的排序算法中,Quick Sort是最快的。
执行流程
/**
* 对[begin, end)范围内的元素进行快速排序
*
* @param begin
* @param end
*/
private void quickSort(int begin, int end) {
if (end - begin < 2) return;
int pivotIndex = pivotIndex(begin, end);// 构造轴点并返回轴点位置
quickSort(begin, pivotIndex); // 对左子序列进行快排
quickSort(pivotIndex + 1, end); // 对右子序列进行快排
}
轴点构造
轴点构造时同样是左闭右开,不过在构造之前,由于先要从右往左扫描,所以首先需要end--
一次。
-
从右往左扫描时,如果被扫描元素比轴点元素大,只需end–
-
从右往左扫描时,如果被扫描元素小于或等于轴点元素,array[begin] = array[end]; begin++; 然后更改扫描方向为从左往右
-
从左往右扫描时,如果被扫描元素比轴点元素小,只需begin++
-
从左往右扫描时,如果被扫描元素大于或等于轴点元素,array[end] = array[begin]; end–; 然后更改扫描方向为从右往左
-
begin == end时,结束
// 构造轴点并返回轴点位置
private int pivotIndex(int begin, int end) {
E pivot = array[begin]; // 备份begin位置的元素
end--; // 由于首先是从右往左扫描,所以要将 end-- 一次
while (begin < end) {
while (begin < end) {
// 从右往左扫描(注意观察小于号的箭头方向)
if (cmp(pivot, array[end]) < 0) { // 如果end位置的元素大于pivot元素
end--;
} else {
array[begin++] = array[end];
break;
}
}
while (begin < end) {
// 从左往右扫描(注意观察大于号的箭头方向)
if (cmp(pivot, array[begin]) > 0) { // 如果begin位置的元素小于pivot元素
begin++;
} else {
array[end--] = array[begin];
break;
}
}
}
array[begin] = pivot; // 将备份的元素放到pivot轴点处
return begin; // 返回begin或end都可以,此时begin == end
// return end;
}
与轴点相等的元素
与轴点相等的元素应该移动其位置到轴点元素的另一边。
时间复杂度
实现
public class QuickSort<E extends Comparable<E>> extends Sort<E> {
@Override
protected void sort() {
quickSort(0, array.length);
}
/**
* 对[begin, end)范围内的元素进行快速排序
*
* @param begin
* @param end
*/
private void quickSort(int begin, int end) {
if (end - begin < 2) return;
int pivotIndex = pivotIndex(begin, end);// 构造轴点并返回轴点位置
quickSort(begin, pivotIndex); // 对左子序列进行快排
quickSort(pivotIndex + 1, end); // 对右子序列进行快排
}
// 构造轴点并返回轴点位置
private int pivotIndex(int begin, int end) {
// Math.random() -> [0, 1) // (int)Math.random()永远为0
// Math.random() * (end - begin) -> [0, end - begin)
// begin + Math.random() * (end - begin) -> begin + [0, end - begin) -> [begin, end)
// 随机选取轴点元素
swap(begin, begin + (int) (Math.random() * (end - begin)));
E pivot = array[begin]; // 备份begin位置的元素
end--; // 由于首先是从右往左扫描,所以要将 end-- 一次
while (begin < end) {
while (begin < end) {
// 从右往左扫描
if (cmp(pivot, array[end]) < 0) { // 如果end位置的元素大于pivot元素
end--;
} else {
array[begin++] = array[end];
break;
}
}
while (begin < end) {
// 从左往右扫描
if (cmp(pivot, array[begin]) > 0) { // 如果begin位置的元素小于pivot元素
begin++;
} else {
array[end--] = array[begin];
break;
}
}
}
array[begin] = pivot; // 将备份的元素放到pivot轴点处
return begin; // 返回begin或end都可以,此时begin == end
// return end;
}
}
希尔排序
希尔排序
步长序列
举例1
举例2
实现
public class ShellSort<E extends Comparable<E>> extends Sort<E> {
@Override
protected void sort() {
// 希尔排序可自定义步长序列
// List<Integer> stepSequence = stepSequence();
List<Integer> stepSequence = sedgewickStepSequence();
for (Integer step : stepSequence) {
sort(step);
}
}
// 分为 step 列进行排序
private void sort(Integer step) {
for (int col = 0; col < step; col++) {
// col + row * step;
// col, col + step, col + 2 * step, col + 3 * step...
// col, col + step, col + step + step, col + step + step + step...
// for (int begin = col + step; begin < array.length; begin += step) {
// int current = begin;
// while (current > col && cmp(current, current - step) < 0) {
// swap(current, current - step);
// current -= step;
// }
// }
for (int begin = col + step; begin < array.length; begin += step) {
int current = begin;
E element = array[current];
while (current > col && cmp(element, array[current - step]) < 0) {
array[current] = array[current - step];
current -= step;
}
array[current] = element;
}
}
}
private List<Integer> stepSequence() {
List<Integer> stepSequence = new ArrayList<>();
int step = array.length;
while ((step >>= 1) > 0) {
stepSequence.add(step);
}
return stepSequence;
}
private List<Integer> sedgewickStepSequence() {
List<Integer> stepSequence = new ArrayList<>();
int k = 0, step;
while (true) {
if ((k & 1) == 0) {
int pow = (int) Math.pow(2, k >> 1);
step = 1 + 9 * (pow * pow - pow);
} else {
int pow1 = (int) Math.pow(2, (k - 1) >> 1);
int pow2 = (int) Math.pow(2, (k + 1) >> 1);
step = 1 + 8 * pow1 * pow2 - 6 * pow2;
}
if (step >= array.length) break;
stepSequence.add(0, step);
k++;
}
return stepSequence;
}
}
计数排序
计数排序
适合对一定范围内的整数进行排序
最简单的实现
public class CountingSort extends Sort<Integer> {
@Override
protected void sort() {
// 找出最大值
int max = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i] > max) {
max = array[i];
}
}
// 构建一个计数数组
int[] counts = new int[max + 1];
for (int i = 0; i < array.length; i++) {
counts[array[i]]++;
}
// 排序
int index = 0;
for (int i = 0; i < counts.length; i++) {
while (counts[i]-- > 0) {
array[index++] = i;
}
}
}
}
改进思路—原理
改进思路—过程
改进—实现
protected void sort() {
// 找出最大最小值
int max = array[0];
int min = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i] < min) {
min = array[i];
}
if (array[i] > max) {
max = array[i];
}
}
// 开辟新的counts计数数组
int[] counts = new int[max - min + 1];
for (int i = 0; i < array.length; i++) {
counts[array[i] - min]++;
}
for (int i = 1; i < counts.length; i++) {
counts[i] += counts[i - 1];
}
// 创建一个临时数组,用于存放排序元素
int[] tempArray = new int[array.length];
// 排序 从右往左可以保证稳定性
for (int i = array.length - 1; i >= 0; i--) {
// counts[array[i] - min]--;
// tempArray[counts[array[i] - min]] = array[i];
tempArray[--counts[array[i] - min]] = array[i];
}
for (int i = 0; i < array.length; i++) {
array[i] = tempArray[i];
}
}
对自定义对象进行排序
基数排序
基数排序
实现
public class RadixSort extends Sort<Integer> {
@Override
protected void sort() {
int max = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i] > max) {
max = array[i];
}
}
for (int divider = 1; divider <= max; divider *= 10) {
// 依次对个位、十位、百位...排序
countingSort(divider);
}
}
private void countingSort(int divider) {
// 个位数、十位数等,范围是0-9
int[] counts = new int[10];
for (int i = 0; i < array.length; i++) {
/*
int n = 123;
int g = n / 1 % 10; // 个位数
int s = n / 10 % 10; // 十位数
int b = n / 100 % 10; // 百位数
int g = array[i] / 1 % 10; // 个位数
int s = array[i] / 10 % 10; // 十位数
int b = array[i] / 100 % 10; // 百位数
*/
counts[array[i] / divider % 10]++;
}
for (int i = 1; i < counts.length; i++) {
counts[i] += counts[i - 1];
}
int[] tempArray = new int[array.length];
// 计数排序:从右往左可以保证稳定性
for (int i = array.length - 1; i >= 0; i--) {
tempArray[--counts[array[i] / divider % 10]] = array[i];
}
for (int i = 0; i < array.length; i++) {
array[i] = tempArray[i];
}
}
}
抽取数组出来重新利用:
public class RadixSort extends Sort<Integer> {
@Override
protected void sort() {
int max = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i] > max) {
max = array[i];
}
}
int[] counts = new int[10];
int[] tempArray = new int[array.length];
for (int divider = 1; divider <= max; divider *= 10) {
countingSort(divider, counts, tempArray);
}
}
private void countingSort(int divider, int[] counts, int[] tempArray) {
for (int i = 1; i < counts.length; i++) { // 重置counts计数数组
counts[i] = 0;
}
for (int i = 0; i < array.length; i++) {
counts[array[i] / divider % 10]++;
}
for (int i = 1; i < counts.length; i++) {
counts[i] += counts[i - 1];
}
for (int i = array.length - 1; i >= 0; i--) {
tempArray[--counts[array[i] / divider % 10]] = array[i];
}
for (int i = 0; i < array.length; i++) {
array[i] = tempArray[i];
}
}
}
另一种思路
另一种思路—实现
桶排序
休眠排序
休眠排序——史上最强排序,复杂度竟为O(n)!
C语言实现十大排序算法(除过桶排序)
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <malloc.h>
#define MAX 10
void swap(int* array, int i1, int i2);
int* generateArray(int size);
int* copyArray(int* arr, int size);
void printArray(char* name, int* array, int size);
void isArcSort(char* name, int* array, int size);
void afterSort(char* name, int* array, int size);
typedef struct node {
int step;
struct node* next;
} Node;
void _radixSort(int* counts, int* tempArray, int* array, int size, int divider) {
for (int i = 0; i < 10; i++) {
counts[i] = 0;
}
for (int i = 0; i < size; i++) {
counts[array[i] / divider % 10]++;
}
for (int i = 1; i < 10; i++) {
counts[i] += counts[i - 1];
}
for (int i = size - 1; i >= 0; i--) {
tempArray[--counts[array[i] / divider % 10]] = array[i];
}
for (int i = 0; i < size; i++) {
array[i] = tempArray[i];
}
}
void radixSort(int* arr, int size) {
int* array = copyArray(arr, size);
int max = array[0];
for (int begin = 1; begin < size; begin++) {
if (array[begin] > max) {
max = array[begin];
}
}
int* counts = calloc(sizeof(int), 10);
int* tempArray = malloc(sizeof(int) * size);
for (int divider = 1; divider <= max; divider *= 10) {
_radixSort(counts, tempArray, array, size, divider);
}
afterSort("radixSort", array, size);
}
void countingSort(int* arr, int size) {
int* array = copyArray(arr, size);
int max = array[0];
int min = array[0];
for (int begin = 1; begin < size; begin++) {
if (array[begin] > max) {
max = array[begin];
}
if (array[begin] < min) {
min = array[begin];
}
}
int countsSize = max - min + 1;
int* counts = calloc(sizeof(int), countsSize);
for (int i = 0; i < size; i++) {
counts[array[i] - min]++;
}
for (int i = 1; i < countsSize; i++) {
counts[i] += counts[i - 1];
}
int* tempArray = malloc(sizeof(int)*size);
for (int i = size - 1; i >= 0; i--) {
tempArray[--counts[array[i] - min]] = array[i];
}
for (int i = 0; i < size; i++) {
array[i] = tempArray[i];
}
afterSort("countingSort", array, size);
}
Node* generateStepSequence(int arraySize) {
int step = arraySize;
Node* node = malloc(sizeof(Node));
Node* temp = node;
Node* prevNode = NULL;
while ((step >>= 1) > 0) {
prevNode = node;
node->step = step;
node->next = malloc(sizeof(Node));
node = node->next;
}
free(prevNode->next);
prevNode->next = NULL;
return temp;
}
void _shellSort(int* array, int size, int step) {
for (int col = 0; col < step; col++) {
for (int begin = col + step; begin < size; begin += step) {
int currentElement = array[begin];
int currentIndex = begin;
while (currentIndex > col && currentElement < array[currentIndex - step]) {
array[currentIndex] = array[currentIndex - step];
currentIndex -= step;
}
array[currentIndex] = currentElement;
}
}
}
void shellSort(int* arr, int size) {
int* array = copyArray(arr, size);
Node* stepSequence = generateStepSequence(size);
Node* temp = stepSequence;
while (stepSequence != NULL) {
_shellSort(array, size, stepSequence->step);
stepSequence = stepSequence->next;
}
stepSequence = temp; // 释放内存
while (stepSequence != NULL) {
temp = stepSequence;
stepSequence = stepSequence->next;
free(temp);
}
afterSort("shellSort", array, size);
}
int createPivotIndex(int* array, int begin, int end) {
int pivotElement = array[begin];
end--;
while (begin < end) {
while (begin < end) {
if (array[end] > pivotElement) {
end--;
}
else {
array[begin++] = array[end];
break;
}
}
while (begin < end) {
if (array[begin] < pivotElement) {
begin++;
}
else {
array[end--] = array[begin];
break;
}
}
}
array[begin] = pivotElement;
return begin;
}
void _quickSort(int* array, int begin, int end) {
if (end - begin < 2) return;
int pivotIndex = createPivotIndex(array, begin, end);
_quickSort(array, begin, pivotIndex);
_quickSort(array, pivotIndex + 1, end);
}
void quickSort(int* arr, int size) {
int* array = copyArray(arr, size);
_quickSort(array, 0, size);
afterSort("quickSort", array, size);
}
void merge(int* leftArray, int* array, int begin, int middle, int end) {
int li = 0, le = middle - begin;
int ri = middle, re = end;
int ai = begin;
for (int i = 0; i < le; i++) {
leftArray[i] = array[begin + i];
}
while (li < le) {
if (ri < re && array[ri] < leftArray[li]) {
array[ai++] = array[ri++];
} else {
array[ai++] = leftArray[li++];
}
}
}
void _mergeSort(int* leftArray, int* array, int begin, int end) {
if (end - begin < 2) return;
int middle = (begin + end) >> 1;
_mergeSort(leftArray, array, begin, middle);
_mergeSort(leftArray, array, middle, end);
merge(leftArray, array, begin, middle, end);
}
void mergeSort(int* arr, int size) {
int* array = copyArray(arr, size);
int* leftArray = malloc(sizeof(int) * (size >> 1));
_mergeSort(leftArray, array, 0, size);
afterSort("mergeSort", array, size);
free(leftArray);
}
void insertionSort(int* arr, int size) {
int* array = copyArray(arr, size);
for (int begin = 1; begin < size; begin++) {
int currentIndex = begin;
int currentElement = array[currentIndex];
int b = 0;
int e = begin;
while (b < e) {
int m = (b + e) >> 1;
if (currentElement < array[m]) {
e = m;
} else {
b = m + 1;
}
}
while (currentIndex > b) {
array[currentIndex] = array[currentIndex - 1];
currentIndex--;
}
array[b] = currentElement;
}
afterSort("insertionSort", array, size);
}
void siftDown(int* array, int heapSize, int index) {
int half = heapSize >> 1;
int currentElement = array[index];
while (index < half) {
int leftChildIndex = (index << 1) + 1;
int leftChildElement = array[leftChildIndex];
int rightChildIndex = leftChildIndex + 1;
if (rightChildIndex < heapSize) {
int rightChildElement = array[rightChildIndex];
if (rightChildElement > leftChildElement) {
leftChildElement = rightChildElement;
leftChildIndex = rightChildIndex;
}
}
if (currentElement >= leftChildElement) break;
array[index] = leftChildElement;
index = leftChildIndex;
}
array[index] = currentElement;
}
void heapSort(int* arr, int size) {
int* array = copyArray(arr, size);
int heapSize = size;
for (int i = (size >> 1) - 1; i >= 0; i--) {
siftDown(array, heapSize, i);
}
while (heapSize > 1) {
swap(array, 0, --heapSize);
siftDown(array, heapSize, 0);
}
afterSort("heapSort", array, size);
}
void selectionSort(int* arr, int size) {
int* array = copyArray(arr, size);
for (int end = size - 1; end > 0; end--) {
int max =0;
for (int begin = 1; begin <= end; begin++) {
if (array[begin] > array[max]) {
max = begin;
}
}
swap(array, max, end);
}
afterSort("selectionSort", array, size);
}
void bubbleSort(int* arr, int size) {
int* array = copyArray(arr, size);
for (int end = size - 1; end > 0; end--) {
int sortedIndex = 1;
for (int begin = 1; begin <= end; begin++) {
if (array[begin - 1] > array[begin]) {
swap(array,begin - 1, begin);
sortedIndex = begin;
}
}
end = sortedIndex;
}
afterSort("bubbleSort", array, size);
}
int main() {
int * array = generateArray(MAX);
printArray("original", array, MAX);
bubbleSort(array, MAX);
selectionSort(array, MAX);
heapSort(array, MAX);
insertionSort(array, MAX);
mergeSort(array, MAX);
quickSort(array, MAX);
shellSort(array, MAX);
countingSort(array, MAX);
radixSort(array, MAX);
free(array);
return 0;
}
void afterSort(char* name, int* array, int size) {
printArray(name, array, size);
isArcSort(name, array, size);
free(array);
}
void swap(int* array, int i1, int i2) {
int temp = array[i1];
array[i1] = array[i2];
array[i2] = temp;
}
void isArcSort(char* name, int* array, int size) {
int isArc = 1;
for (int i = 1; i < size; i++) {
if (array[i - 1] > array[i]) {
isArc = 0;
}
}
if (!isArc) printf("%s is not arc!\n", name);
}
int* copyArray(int* arr, int size) {
int* array = malloc(sizeof(int) * size);
for (int i = 0; i < size; i++) {
array[i] = arr[i];
}
return array;
}
int* generateArray(int size) {
int* array = malloc(sizeof(int) * size);
srand((unsigned)time(NULL));
for (int i = 0; i < size; i++) {
array[i] = rand() % (size << 2);
}
return array;
}
void printArray(char* name, int* array, int size) {
//if (1) return;
printf("%13s : ", name);
for (int i = 0; i < size; i++) {
printf("%d ", array[i]);
}
printf("\n");
}
注意
- 左闭右开
-
类似于最大堆和最小堆那样:最大堆其实就是最小堆,最小堆其实也是最大堆。(只不过比较时对元素大小的看法不同)
-
排序时,升序排序或者降序排序其实可以理解为是同一种排序(从小到大排或者从大到小排都行,以从小到大升序为例),当实现了一个从小到大的升序排序算法时,也就相当于实现了一个从大到小的降序排序算法,只不过,在比较元素大小时(compare),看你如何认为什么是大的元素如何认为什么是小的元素。
-
如果认为值比较大的元素比较大,那么就是正常的升序排序。
-
而如果认为值比较小的元素比较大,那么就是降序排序了。
- 求某个数的个位数、百位数、十位数…
int i = 423;
int g = i / 1 % 10; // 个位数
int s = i / 10 % 10; // 十位数
int b = i / 100 % 10; // 百位数
// int q = i / 1000 % 10; // 千位数
// ......
参考
小码哥李明杰老师课程: 恋上数据结构与算法 第二季.
本文完,感谢您的关注支持!