一、归并排序(二路)
归并排序是两两合并
先写合并的代码
// 合并arr[low]... ...arr[mid] 和 arr[mid+1]... ...arr[high]
public static void merge(int[] arr, int low, int mid, int high){
int index = 0;
int i = low;
int j = mid + 1;
int[] temp = new int[high - low + 1]; // 用来暂存合并结果
while (i <= mid && j <= high){
if (arr[i] <= arr[j]){
temp[index++] = arr[i++]; // 这两句互换,可以决定正序或逆序排
}else {
temp[index++] = arr[j++]; // 这两句互换,可以决定正序或逆序排
}
}
while (i <= mid){
temp[index++] = arr[i++];
}
while (j <= high){
temp[index++] = arr[j++];
}
index = 0;
// 将合并结果赋值回原数组arr
for (int k = low; k <= high; k++){
arr[k] = temp[index++];
}
}
然后是主干函数
static void mergeSort(int[] arr, int low, int high){
if (low < high){
int mid = (low + high) / 2;
// 对左边进行归并排序
mergeSort(arr, low, mid);
// 对右边进行归并排序
mergeSort(arr, mid + 1, high);
// 合并
merge(arr, low, mid, high);
}
}
二、快速排序
快速排序的一种思想是,取数组的第一个数为标杆pivot,然后两个指针low和high,分别指向两头,指针向两头靠拢,如果arr[low] 大于pivot,则把arr[low]赋值给arr[high],如果arr[high]的值小于pivot,则把arr[high]的值赋给arr[low]。当low不小于high时,第一轮排序结束,此时,将pivot的值赋给arr[low],而数组low下标的数所处的位置是其最终位置。
这样每一轮就可以让一个数找到自己最终的位置。
快速排序其实也使用了分治的思想。
先看一轮排序的代码
public static int Partition(int[] arr, int low, int high){
int pivot = arr[low];
while (low < high){
while (low < high && arr[high] >= pivot){
high--;
}
arr[low] = arr[high]; // ++?
while (low < high && arr[low] <= pivot){
low++;
}
arr[high] = arr[low]; // --?
}
arr[low] = pivot;
return low;
}
然后是主干代码
public static void QuickSort(int[] arr, int low, int high){
if (low < high){
// mid相当于是已经排好序的了
int mid = Partition(arr, low, high);
// 对mid左边再进行快速排序
QuickSort(arr, low, mid - 1);
// 对mid右边再进行快速排序
QuickSort(arr, mid + 1, high);
}
}
三、堆排序
这里给出大顶堆
public class HeadSort {
public static void main(String[] args){
int[] arr = {14, 9, 6, 13, 21, 10, 16, 17, 2, 12};
// int[] arr = {21, 17, 16, 14, 12, 10, 6, 13, 2, 9, 18};
BuildMaxHead(arr, arr.length - 1);
int[] newArr = insertN(arr, 18);
System.out.println("test");
}
// 堆排序主干代码
public static void HeadSort(int[] arr){
int len = arr.length - 1;
BuildMaxHead(arr, len);
for (int i = len; i >= 0; i--){
System.out.println(arr[0]);
int temp = arr[i];
arr[i] = arr[0];
arr[0] = temp;
AdjustDown(arr, 0, i-1);
}
}
// 向已经构建好的堆中插入一个数
public static int[] insertN(int[] arr, int insert_n){
int[] new_arr = Arrays.copyOf(arr, arr.length + 1);
new_arr[arr.length] = insert_n;
AdjustUp(new_arr);
return new_arr;
}
public static void BuildMaxHead(int[] arr, int len){
for (int k = len / 2; k >= 0; k--){
AdjustDown(arr, k, len);
}
}
// 调整arr的k号节点,从上往下调整
public static void AdjustDown(int[] arr, int k, int len){
int temp = arr[k];
// 2*k+1是左孩子,2*k + 2是右孩子
for(int i = k*2 + 1; i <= len; i = i*2 + 1){
// 如果有右孩子,且右孩子比左孩子大,则取右孩子
if (i < len && arr[i] < arr[i+1]){
i++;
}
if (arr[i] > temp){
arr[k] = arr[i]; // 交换过后,要继续看被交换那个节点的子节点
k = i;
}else {
break; // 如果已经满足,则break
}
}
arr[k] = temp;
}
// 自底向上调整
// 用于在已经构建好的大顶堆中插入一个新的数,这个新的数插在数组最后一个
// 然后从其父母 节点开始调整
public static void AdjustUp(int[] arr){
int temp = arr[arr.length - 1];
int i = arr.length - 1;
int parent = (i-1) / 2;
while (parent >= 0 && temp > arr[parent]){
arr[i] = arr[parent];
i = parent;
parent = (i-1) / 2;
}
arr[i] = temp;
}
}