左神系列|关于排序的小总结

    技术2022-07-11  89

    文章目录

    排序选择排序简介代码实现 冒泡排序简介代码实现 插入排序代码实现 归并排序简介代码实现 堆排序简介代码实现 快速排序简介代码实现 桶系列--(偷个懒)排序总结

    排序

    选择排序

    简介

    选择排序的排序方式:一个数组,我们假定长度为n,从头(索引为0)遍历,第一次,我从0 ~ n-1的数中挑出一个最小值放到0位置,第二次,我从1 ~ n-1的数中挑出一个最小值放到1位置,依此类推,一直到n-1位置结束,至此排序完成

    代码实现

    /** * Author:markusZhang * Date:Create in 2020/6/29 9:27 * todo: */ public class SelectSort { public static void selectSort(int []arr){ if (arr==null || arr.length<=0){ return ; } for(int i=0;i<arr.length-1;i++){ int minIndex = i; for (int j=i+1;j<arr.length;j++){ minIndex = arr[minIndex]>arr[j]?j:minIndex; } swap(arr,minIndex,i); } } public static void swap(int[] arr, int i, int j) { int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } public static void main(String[] args) { int []arr = {5,4,2,3,1}; selectSort(arr); for (int i : arr) { System.out.print(i+" "); } } }

    冒泡排序

    简介

    冒泡排序的思想就是,我从头遍历,每次比较相邻的两个数,然后遍历一遍结束之后,最大值都放到最后。然后待排序子序列长度-1,继续从头遍历,重复上述过程。

    代码实现

    /** * Author:markusZhang * Date:Create in 2020/6/29 9:23 * todo: */ public class BubbleSort { public static void bubbleSort(int []arr){ if (arr==null || arr.length<=0){ return; } for(int i=0;i<arr.length;i++){ for (int j=0;j<arr.length-1-i;j++){ if (arr[j]>arr[j+1]){ int temp= arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } } } public static void main(String[] args) { int []arr = {4,5,3,2,1}; bubbleSort(arr); for (int i : arr) { System.out.print(i+" "); } } }

    插入排序

    插入排序的思想:我第一次保证0 ~ 0序列上有序,第二次保证0 ~ 1序列上有序,以此类推,到最后0 ~ n上有序。

    代码实现

    /** * Author:markusZhang * Date:Create in 2020/6/29 9:34 * todo: */ public class InsertSort { public static void insertSort(int []arr){ if (arr==null || arr.length<=0){ return ; } for (int i=1;i<arr.length;i++){ for (int j=i;j>0 && arr[j]<arr[j-1];j--){ swap(arr,j,j-1); } } } public static void swap(int[] arr, int i, int j) { int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } public static void main(String[] args) { int []arr = {5,4,2,3,1}; insertSort(arr); for (int i : arr) { System.out.print(i+" "); } } }

    归并排序

    简介

    归并排序的思想:先将数组分成左右两份,我先保证左右两份各是有序的,最后我再合并左右,保证整个是有序的。

    代码实现

    /** * Author:markusZhang * Date:Create in 2020/6/29 12:39 * todo: */ public class MergeSort { public static void mergeSort(int []arr){ if (arr == null || arr.length<=0){ return ; } sort(arr,0,arr.length-1); } private static void sort(int []arr,int left,int right){ if (left >= right){ return; } int mid = left+((right-left)>>1); sort(arr,left,mid); sort(arr,mid+1,right); merge(arr,left,mid,right); } private static void merge(int []arr,int start,int mid,int end){ int []temp = new int[end-start+1]; int index = 0; int left = start; int right = mid+1; while(left<=mid && right<=end){ temp[index++] = arr[left]>arr[right]?arr[right++]:arr[left++]; } while(left<=mid){ temp[index++] = arr[left++]; } while(right<=end){ temp[index++] = arr[right++]; } for (int i=0;i<temp.length;i++){ arr[start+i] = temp[i]; } } public static void main(String[] args) { int []arr = {5,4,3,2,1}; mergeSort(arr); for (int i : arr) { System.out.print(i+" "); } } }

    堆排序

    简介

    堆排序思想:将数组想象成完全二叉树的样子,其实这就是堆。又分为大根堆小根堆。我先让数组中的元素建成堆,有效堆大小初始为数组大小,然后交换0和n-1,有效堆大小-1,然后将堆顶元素下沉,直到该元素的大小比子节点的元素都大,停止下沉,然后交换0和有效堆容量-1的元素,继续上述过程,最终有效堆大小为0,排序结束

    代码实现

    /** * Author:markusZhang * Date:Create in 2020/6/29 13:05 * todo: */ public class HeapSort { public static void heapSort(int []arr){ if (arr == null || arr.length<=0){ return ; } //假定用户给的数据是一个一个给的 //时间复杂度为O(nlogn) 自上而下 // for (int i=0;i<arr.length;i++){ // heapInsert(arr, i); // } //自下而上 时间复杂度为O(n) for (int i=arr.length-1;i>=0;i--){ heapify(arr,i,arr.length); } int size = arr.length; swap(arr,0,--size); while(size>0){ heapify(arr,0,size); swap(arr,0,--size); } } 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 heapify(int []arr,int index,int size){ int left = 2*index+1; while(left<size){//说明有孩子 int largestIndex = left+1<size && arr[left]<arr[left+1]?left+1:left; largestIndex = arr[largestIndex]>arr[index]?largestIndex:index; if (largestIndex == index){ break; } swap(arr,largestIndex,index); index = largestIndex; left = index*2+1; } } private static void swap(int []arr,int i,int j){ int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } public static void main(String[] args) { int []arr = {5,4,3,2,1}; heapSort(arr); for (int i : arr) { System.out.print(i+" "); } } }

    快速排序

    简介

    快速排序思想:我先随机在数组中挑一个元素,让它与最后一个元素做交换,然后在0-n-2的数组上做分区,把小于最后一个元素值的元素放在左边,将等于最后一个元素值的元素放中间,把大于最后一个元素值的元素放在右边,再将小于区域进行分区和大于区域进行分区,最终达到整个数组有序

    代码实现

    /** * Author:markusZhang * Date:Create in 2020/6/30 23:24 * todo: 快速排序 */ public class QuickSort { /** * 1.0版本 时间复杂度为O(n2) */ public static void quickSort_1(int []arr,int L,int R){ if (L >= R){ return ; } int partition = arr[R]; int less = L-1; int more = R+1; int left = L; while(left < more){ if (arr[left] > partition){ swap(arr,left,--more); }else if (arr[left] == partition){ left++; }else{ swap(arr,left++,++less); } } quickSort_1(arr,L,less); quickSort_1(arr,more,R); } /** * 2.0版本:指定的基准值是随机的,时间复杂度最后会收敛到O(nlogn) */ public static void quickSort_v2(int []arr,int L,int R){ if (L < R){ //随机挑选出一个值与最右边的元素交换 swap(arr,L+(int)(Math.random()*(R-L+1)),R); //将数组分成三部分,小于 等于 大于 // 返回值 0:等于区域的第一个值 1:等于区域的最后一个值 int []partition = partition(arr,L,R); // 递归进行小于区域的分区 quickSort_v2(arr,L,partition[0]-1); // 递归进行大于区域的分区 quickSort_v2(arr,partition[1]+1,R); } } //这个方法, 将数组分成三部分,小于 等于 大于。 //返回的两个参数表示,0: private static int[] partition(int []arr,int L,int R){ int less = L-1; int more = R; while(L < more){ if (arr[L] < arr[more]){ swap(arr,L++,++less); }else if (arr[L] > arr[more]){ swap(arr,L,--more); }else{ L++; } } swap(arr,more,R); return new int[]{less+1,more}; } private static void swap(int []arr,int i,int j){ int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } public static void main(String[] args) { int [] arr = {1,4,3,7,5,3}; quickSort_v2(arr,0,arr.length-1); for (int i : arr) { System.out.print(i+" "); } } }

    桶系列–(偷个懒)

    排序总结

    时间复杂度额外空间复杂度稳定性选择排序O( n2 )O(1)×冒泡排序O(n2)O(1)√插入排序O(n2)O(1)√归并排序O(n*log(n))O(n)√堆排序O(n*log(n)O(1)×快速排序O(n*log(n))O(log(n))×

    重要的是归并排序、堆排序和快速排序的选择,在排序当中,就看你想要什么,你想要稳定,就采用归并排序;想要时间快,就用快速排序,这里补充一点,快速排序的常数指标优于其它两个排序;想要追求缩小空间复杂度,就采用堆排序。 目前还没有时间复杂度好、空间复杂度低、稳定性好的排序。 工程上的排序选择就是,在排序数量小于60的时候采用插入排序,大于60采用快速排序 工程上就是考虑两个方面:

    考虑O(nlogn)和O(n2)各自的优势稳定性的考虑
    Processed: 0.011, SQL: 9