快速排序
我们会以最左边的元素作为标准,
从高位取值和他比较,找到高位比他小的元素和low互换,如果比他大则坐标减一继续找
从低位取值找到比他大的元素,和high互换填补到high的位置,如果比他小则继续找
直到low = high循环结束,此时low或者high的坐标就是standard的坐标,返回之后继续递归
public static int parition(int[] arr, int low, int high) {
int standard = arr[low];
while (high > low) {
while (high > low && arr[high] >= standard) {
high--;
}
arr[low] = arr[high];
while (high > low && arr[low] <= standard) {
low++;
}
arr[high] = arr[low];
}
arr[low] = standard;
return low;
}
这里需要注意:必须要检查from要小于等于end
public static void quickSort(int[] arr, int from, int end) {
if (arr.length <= 1 || from >= end) {
return;
}
int partition = parition(arr, from, end);
quickSort(arr, from, partition - 1);
quickSort(arr, partition + 1, end);
}
归并排序
主体思想是先把数组分为不可分的整体每个整体看作一个数组,然后数组合并排序然后再合并最终变成一整个排序好的数组。但是直接这样可能不太好理解。
可以先用二分的方式把数组分成两个部分,然后再二分,直到不可分,然后merge
public static void mergeSort(int[] arr) {
if (arr.length < 2) {
return;
}
dichotomy(arr, 0, arr.length - 1);
}
public static void dichotomy(int[] arr, int low, int high) {
if (high <= low) {
return;
}
int mid = low + (high - low) / 2;
// 继续二分
dichotomy(arr, low, mid);
dichotomy(arr, mid + 1, high);
merge(arr, low, mid, high);
}
当有任意一方到头了,则另一方全部灌入目标数组
public static void merge(int[] arr, int low, int mid, int high) {
int leftIndex = low;
int rightIndex = mid + 1;
int[] result = new int[high - low + 1];
for(int i = 0; i < result.length; i++) {
// 两边都还没到头则互相比较
if (leftIndex <= mid && rightIndex <= high) {
if (arr[leftIndex] <= arr[rightIndex]) {
result[i] = arr[leftIndex];
leftIndex++;
} else {
result[i] = arr[rightIndex];
rightIndex++;
}
} else if (leftIndex <= mid) {
// 右边到头了
result[i] = arr[leftIndex];
leftIndex++;
} else {
// 左边到头了
result[i] = arr[rightIndex];
rightIndex++;
}
}
// 目标数组归入原数组
for(int i = 0; i < result.length;i++) {
arr[i + low] = result[i];
}
}
堆排序
通过大根堆的性质,把最大值放到堆顶,然后和数组最后一位互换,堆长度--
整个过程堆长度要始终传入。
数组元素i的左右堆元素分别为 2*i + 1,2*i+2
数组最大非叶子节点为(length - 2)/2
public static void heapsort(int[] arr) {
if (arr.length < 2) {
return;
}
int heapLen = arr.length;
for (int i = arr.length - 1; i > 0; i--) {
findBiggestHeap(arr, heapLen);
// 此时和大根堆的0位置互换
swap(arr, 0, i);
heapLen--;
}
}
public static void findBiggestHeap(int[] arr, int heapLen) {
int notLeafNode = (heapLen - 2) / 2;
int leftNode, rightMode;
for(int i = notLeafNode; i >= 0;i--) {
leftNode = i*2 + 1;
rightMode = leftNode + 1;
leftRightCompare(arr, leftNode, rightMode, heapLen, i);
}
}
public static void downAdjust(int[] arr, int i, int heapLen) {
int leftNode = i*2 + 1;
int rightMode = leftNode + 1;
leftRightCompare(arr, leftNode, rightMode, heapLen, i);
}
public static void leftRightCompare(int[] arr, int leftNode, int rightMode, int heapLen, int i) {
if (rightMode < heapLen) {
// 有两个节点
if (arr[leftNode] > arr[i] && arr[leftNode] >= arr[rightMode]) {
// 左节点最大
swap(arr, leftNode, i);
// i节点下放之后还得处理
downAdjust(arr, leftNode, heapLen);
} else if (arr[rightMode] > arr[i] && arr[rightMode] > arr[leftNode]) {
// 右节点最大
swap(arr, rightMode, i);
// i节点下放之后还得处理
downAdjust(arr, rightMode, heapLen);
}
} else if (leftNode < heapLen) {
// 仅有左边的节点
if (arr[leftNode] > arr[i]) {
swap(arr, leftNode, i);
// i节点下放之后还得处理
downAdjust(arr, leftNode, heapLen);
}
}
}
半插入排序
我的半插入排序习惯从第三位开始排序,即默认前两个位置已经有序
public static void dInsertSort(int[] arr) {
if (arr.length < 2) {
return;
}
if(arr[0] > arr[1]) {
swap(arr, 0, 1);
}
int mid, low, high, tmp;
for(int i = 2; i < arr.length; i++) {
if (arr[i] >= arr[i-1]) {
continue;
}
low = 0;
high = i;
mid = low + (high - low)/2;
while (high >= low) {
if (arr[i] > arr[mid]) {
low = mid + 1;
} else {
high = mid - 1;
}
mid = low + (high - low)/2;
}
// 当low比high要大的时候
// 移动数组,1,4,5,3 => 1,4,4,5
tmp = arr[i];
moveArr(arr, low, i);
// 1,4,4,5 -> 1,3,4,5
arr[low] = tmp;
}
}
public static void moveArr(int[] arr, int low, int to) {
for(int i = to; i > low; i--) {
arr[i] = arr[i - 1];
}
}
桶排序
希尔排序
public static void shell(int[] arr) {
int gap = arr.length >> 1;
while (gap >= 1) {
shell1(arr, gap);
if(gap == 1) {
break;
}
gap = gap >> 1;
}
}
public static void shell1(int[] arr, int gap) {
for(int i = 0; i < gap; i++) {
isGap(arr, gap);
}
}
public static void isGap(int[] arr, int gap) {
for(int i = gap; i < arr.length; i += gap) {
for(int j = i; j > 0; j -= gap) {
if(arr[j - gap] > arr[j]) {
swap(arr, j - gap, j);
}
}
}
}