1、排序算法
1.1 快速排序
快排的时间复杂度是O(nlogn)
其实现思想就是随机找到一个中间值 小于这个值得放左边 大于这个值得放右边
然后大于这个值得半部分和小于这个值得半部分分别递归
直到全部排完
实现代码:
```
public class QuickSort {
/**
* 递归 进行排序
* @param arr
* @param left
* @param right
*/
public static void quickSort(int [] arr , int left, int right){
//递归终止条件
if (left < right){
swap(arr,left + ((right - left ) >> 1),right);
int [] p = partition(arr,left,right);
//等于区域的左边界递归(小于区域所有值)
quickSort(arr,left,p[0] -1);
//等于区域的右边界递归(大于区域所有值)
quickSort(arr,p[1]+1,right);
}
}
/**
* 划分数组的partition过程 时间复杂度为O(n) 返回的为等于区域的左右边界
* @param arr
* @param left
* @param right
* @return
*/
private static int[] partition(int[] arr, int left, int right) {
int less = left - 1;
int more = right;
while (left < more){
if (arr[left] < arr[right]){
swap(arr, ++less, left++);
}else if (arr[left] > arr[right]){
swap(arr,--more, left);
}else {
left++;
}
}
swap(arr,more,right);
return new int [] {less +1 ,more};
}
private static void swap(int[] arr, int j, int i) {
int temp = arr[j];
arr[j] = arr[i];
arr[i] = temp;
}
public static void main(String[] args) {
int[] arr = ArrayUtils.getArray(10,20);
ArrayUtils.printArray(arr);
quickSort(arr,0,arr.length -1);
System.out.println();
ArrayUtils.printArray(arr);
}
}
```
1.2 堆排
堆排就是建立一个抽象意义上的堆、算法上的堆是一个完全二叉树结构。
其底层是一个数组,一个节点的左孩子是 index * 2 + 1
右孩子是 index * 2 + 2
父亲节点是 (index - 1)/ 2
大根堆就是在以当前节点作为一个树的时候、此节点是整棵树中的最大值(小根堆反之)。
堆排序主要分为两步:
1、建立一个堆,然后每次将堆顶的元素和最后一层的最后一个元素交换。
2、然后将堆顶的元素进行下沉,直到以他为树的所有节点中只有他最大(小)。
堆排时间复杂度是严格意义上的O(nlogn) 空间复杂度是O(1)
```
public class HeapSort {
public static void heapSort(int [] arr){
if (arr == null || arr.length < 2){
return;
}
//建立大根堆 每个节点是整个子树中的最大值
for (int i = 0 ; i < arr.length ; i++){
heapInsert(arr,i);
}
int size = arr.length;
swap(arr,0,--size);
while (size > 0){
heapify(arr,0,size);
swap(arr,0,--size);
}
}
/**
* 下沉的过程
* @param arr
* @param index
* @param size
*/
private static void heapify(int[] arr, int index, int size) {
int left = index * 2 +1;
while (left < size){
//如果左右孩子都存在 选最大的 作为largest
int largest = left + 1 < size && arr[left + 1] > arr[left] ? left +1 : left;
//largest变为 自己和左右孩子中最大的值
largest = arr[largest] > arr[index] ? largest : index;
if (largest == index){
break;
}
swap(arr,largest,index);
index = largest;
left = index * 2 +1;
}
}
/**
* 从index位置开始进行与父节点的比较 直到不比父节点大 或者到0的位置停止
* @param arr
* @param index
*/
private static void heapInsert(int[] arr, int index) {
while (arr[index] > arr[(index - 1 ) / 2]){
swap(arr,index,(index -1 ) / 2 );
index = (index -1 ) / 2;
}
}
private static void swap(int[] arr, int j, int i) {
int temp = arr[j];
arr[j] = arr[i];
arr[i] = temp;
}
public static void main(String[] args) {
int[] arr = ArrayUtils.getArray(10,20);
ArrayUtils.printArray(arr);
heapSort(arr);
System.out.println();
ArrayUtils.printArray(arr);
}
}
```
1.3 归并排序
归并排序就是将数组递归的两两划分、然后再合并的过程 在合并的过程中排好序
递的过程就是将数组从中间分成两半、直到数组大小为1,
归的过程就是讲两部分合成成一个部分,合成的过程中排好序
时间复杂度O(nlogn)
```
public class MergeSort {
public static void mergeSort(int[] arr) {
if (arr.length < 2 || arr == null) {
return;
}
mergeSort(arr, 0, arr.length - 1);
}
private static void mergeSort(int[] arr, int left, int right) {
if (left == right) {
return;
}
//left 和right的中间位置
int mid = left + ((right - left) >>> 1);
//左半部分递归
mergeSort(arr, left, mid);
//右半部分递归
mergeSort(arr, mid + 1, right);
//最后再合并
merge(arr, left, mid, right);
}
/**
* 合并 l 到 r上以 mid 为划分点的两部分的元素
*
* @param arr
* @param left
* @param mid
* @param right
*/
private static void merge(int[] arr, int left, int mid, int right) {
int[] help = new int[right - left + 1];
int i = 0;
int leftPoint = left;
int rightPoint = mid + 1;
while (leftPoint <= mid && rightPoint <= right) {
help[i++] = arr[leftPoint] < arr[rightPoint] ? arr[leftPoint++] : arr[rightPoint++];
}
while (leftPoint <= mid) {
help[i++] = arr[leftPoint++];
}
while (rightPoint <= right) {
help[i++] = arr[rightPoint++];
}
//将数组拷贝回原数组
for (i = 0; i < help.length; i++) {
arr[left + i] = help[i];
}
}
public static void main(String[] args) {
int[] arr = ArrayUtils.getArray(10, 20);
ArrayUtils.printArray(arr);
mergeSort(arr, 0, arr.length - 1);
System.out.println();
ArrayUtils.printArray(arr);
}
}
```