排序算法之归并快排
排序算法
归并排序
思想: 经过多次递归,变为一个个数字。再经多次merge就可以变为有序。merge 方法中只有一个 for 循环,直接就可以得出每次合并的时间复杂度为 O(n) ,而分解数组每次对半切割,属于对数时间 O(log n) ,合起来等于 O(log2n) ,也就是说,总的时间复杂度为 O(nlogn) 。
public static void sort(int[] arr) {
int[] tempArr = new int[arr.length];//只定义一个临时数组,空间复杂度降低
sort(arr, tempArr, 0, arr.length-1);
}
/**
* 归并排序
* @param arr 排序数组
* @param tempArr 临时存储数组
* @param startIndex 排序起始位置
* @param endIndex 排序终止位置
*/
private static void sort(int[] arr,int[] tempArr,int startIndex,int endIndex){
if(endIndex <= startIndex){
return;
}
//中部下标
int middleIndex = startIndex + (endIndex - startIndex) / 2;
//分解
sort(arr,tempArr,startIndex,middleIndex);
sort(arr,tempArr,middleIndex + 1,endIndex);
//归并
merge(arr,tempArr,startIndex,middleIndex,endIndex);
}
/**
* 归并
* @param arr 排序数组
* @param tempArr 临时存储数组
* @param startIndex 归并起始位置
* @param middleIndex 归并中间位置
* @param endIndex 归并终止位置
*/
private static void merge(int[] arr, int[] tempArr, int startIndex, int middleIndex, int endIndex) {
//***要合并的数据
for (int s = startIndex; s <= endIndex; s++) {
tempArr[s] = arr[s];
}
int left = startIndex;//左边部分首位下标
int right = middleIndex + 1;//右边部分首位下标
for (int k = startIndex; k <= endIndex; k++) {
if(left > middleIndex){
//如果左边的首位下标大于中部下标,证明左边的数据已经排完了。
arr[k] = tempArr[right++];
} else if (right > endIndex){
//如果右边的首位下标大于了数组长度,证明右边的数据已经排完了。
arr[k] = tempArr[left++];
} else if (tempArr[right] < tempArr[left]){
arr[k] = tempArr[right++];//将右边的首位排入,然后右边的下标指针+1。
} else {
arr[k] = tempArr[left++];//将左边的首位排入,然后左边的下标指针+1。
}
}
} 快速排序
思想: 定义第一个为基准数,先从右边扫描,找到第一个小于他的数,再从左边扫描,直到找到一个比他大的。交换,直到两个指针相遇。3,1,2,5,4到2,1,3,5,4
public class Main{
public static void main(String[] args) {
int[] a={1,3,5,2,7,9,0};
quickSort(a,0,6);
for (int i =0;i<a.length;i++){
System.out.println(a[i]);
}
}
private static void quickSort(int[] arr, int low, int high) {
if (low < high) {
// 找寻基准数据的正确索引
int index = getIndex(arr, low, high);
// 进行迭代对index之前和之后的数组进行相同的操作使整个数组变成有序
quickSort(arr, 0, index - 1);
quickSort(arr, index + 1, high);
}
}
private static int getIndex(int[] arr, int low, int high) {
// 基准数据
int tmp = arr[low];
while (low < high) {
// 当队尾的元素大于等于基准数据时,向前挪动high指针
while (low < high && arr[high] >= tmp) {
high--;
}
// 如果队尾元素小于tmp了,需要将其赋值给low
arr[low] = arr[high];
// 当队首元素小于等于tmp时,向前挪动low指针
while (low < high && arr[low] <= tmp) {
low++;
}
// 当队首元素大于tmp时,需要将其赋值给high
arr[high] = arr[low];
}
// 跳出循环时low和high相等,此时的low或high就是tmp的正确索引位置
// 由原理部分可以很清楚的知道low位置的值并不是tmp,所以需要将tmp赋值给arr[low]
arr[low] = tmp;
return low; // 返回tmp的正确位置
}
}
