几种常见的排序方法整理
几种常见的排序方法整理
一、直接插入排序
插入排序是一种简单直观的排序算法。通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在从后向前扫描的过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。
算法:
将需要排序的数列看成一个数组,i初始化指向数组1号下标,j初始化指向数组0号下标,和i对应数值进行比较,比较一次往后退一步,如果j对应数值大于i对应数值,数值进行交换,直到i前面的数字都比它小,i往后走。
时间复杂度:(1)最坏情况是O(n^2)
(2) 最好情况是有序情况:O(n)
空间复杂度:O(1)
稳定性:稳定
代码:
1 public static void insertSort(int[] array){ 2 int tmp = 0; 3 int j ; 4 for(int i=1; i<array.length; i++){ 5 tmp = array[i]; 6 for( j=i-1; j>=0; j--){ 7 if(array[j] > tmp){ 8 array[j+1] = array[j]; //调换位置 9 }else{ 10 // array[j+1] = tmp; //不用换,放回原位 11 break; 12 } 13 } 14 array[j+1] = tmp; //不用换,放回原位 15 } 16 }
二、希尔排序
希尔排序也是插入排序的一种,它是采用分组的思想,对每组进行插入排序。
代码:
1 public static void shellSort(int[] array){ 2 int[] drr = {5,3,1}; 3 for(int i = 0; i<drr.length; i++){ 4 shell(array,drr[i]); 5 } 6 } 7 public static void shell(int[] array,int gap){ 8 int tmp = 0; 9 for(int i = gap; i<array.length; i++){ 10 tmp = array[i]; 11 int j; 12 for(j=i-gap; j>=0; j-=gap){ 13 if(array[j]>tmp){ 14 array[j+gap] = array[j]; 15 }else { 16 break; 17 } 18 } 19 array[j+gap]=tmp; 20 } 21 22 }
三、选择排序
算法思想:
先从数组第一个数字开始,把这个数字和这个数字之后的所有数字进行比较,如果比这个数字小就交换,然后把数组第二个数字和它之后的所有数字进行比较,比他小就交换,以此类推,直到数组最后一个数字。
代码:
1 public static void selectSort(int[] array){ 2 for(int i=0; i<array.length; i++){ 3 for(int j=i+1; j<array.length; j++){ 4 if(array[j]<array[i]){ 5 int tmp = array[i]; 6 array[i] = array[j]; 7 array[j] = tmp; 8 } 9 } 10 11 } 12 13 }
时间复杂度:O(n^2)
空间复杂度:O(1)
稳定性:不稳定
四、堆排序
首先将数组建立成一个大根堆,从数组最后一个数字开始,和数组0号下标数字进行交换,然后采用向下调整法。接着将倒数第二个数字和数组0号下标数字进行交换,然后采用向下调整法,以此类推,直到0号下标数字。
代码:
1 public static void heapSort(int[] array){ 2 creatHeap(array); 3 int end = array.length-1; 4 while(end>0){ 5 int tmp = array[end]; 6 array[end] = array[0]; 7 array[0] = tmp; 8 adjustDown(array,0,end); 9 end--; 10 } 11 } 12 //建立大根堆 13 public static void creatHeap(int[] array){ 14 for(int i = (array.length-1-1)/2; i>=0; i--){ 15 adjustDown(array,i,array.length); 16 } 17 } 18 //向下调整法 19 public static void adjustDown(int[] array,int root,int len){ 20 int patrnt = root; 21 int child = root*2+1; 22 //最起码有左孩子 23 while(child<len){ 24 //有右孩子且左孩子小于右孩子,进行交换 25 if(child+1<len && array[child]<array[child+1]){ 26 int tmp = array[child]; 27 array[child] = array[child+1]; 28 array[child+1] = tmp; 29 } 30 //如果左孩子大于父亲结点,要进行交换 31 if (array[child] > array[patrnt]) { 32 int tmp = array[child]; 33 array[child] = array[patrnt]; 34 array[patrnt] = tmp; 35 patrnt = child; 36 child = patrnt*2+1; 37 }else{ 38 break; 39 } 40 } 41 }
时间复杂度:O(nlogn)
空间复杂度:O(1)
稳定性:不稳定
五、冒泡排序
冒泡排序是每一趟都从第一个数字开始,将数组每一个数字和它后一个数字进行比较,比它小就交换。如此往复,直到序列有序。
代码:
1 public static void bubleSort(int[] array){ 2 //i表示趟数 3 for(int i=0; i<array.length-1; i++){ 4 for(int j=0; j<array.length-1-i; j++){ 5 if(array[j]>array[j+1]){ 6 int tmp = array[j]; 7 array[j] = array[j+1]; 8 array[j+1] = tmp; 9 } 10 } 11 } 12 }
时间复杂度:O(n^2)
空间复杂度:O(1)
稳定性:不稳定
六、快速排序
快速排序,又称划分交换排序。通过一趟排序将要排序的数据分割成两部分,然后再按此方法对两部分数据分别进行快速排序,以此达到整个数据变成有序序列
步骤为:
(1) 从数列找出一个元素,称为“基准”。
(2) 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区操作。
(3)把基准元素左边的数值序列用递归的方法进行快速排序,右边序列也如此。直到整个序列有序。
代码:
1 public static void quickSort(int[] array){ 2 3 quick(array,0,array.length-1); 4 } 5 public static void quick(int[] array,int left,int right){ 6 if(left>=right){ 7 return; 8 } 9 int par = partition(array,left,right); 10 //递归排序左边和右边 11 quick(array,left,par-1); 12 quick(array,par+1,right); 13 14 } 15 //找基准 16 public static int partition(int[] array,int left,int right){ 17 int tmp = array[left]; 18 while(left<right){ 19 20 while(left<right && array[right]>=tmp){ 21 right--; 22 } 23 array[left]=array[right]; 24 while(left<right && array[left]<=tmp) { 25 left++; 26 } 27 array[right] = array[left]; 28 } 29 array[left] = tmp; 30 return left; 31 }
时间复杂度:O(nlogn)
最坏情况:1 2 3 4 5 6 7 8 9 / 9 8 7 6 5 4 3 2 1 :O(n^2)
空间复杂度:O(logn)~O(n)
稳定性:不稳定
七、归并排序
归并排序是采用分治法,思想就是先将数组分解为一个一个的数(将数组从中间一分为二,然后递归分解左边和右边),再合并数组。
合并的基本思路是比较两个数组的最前面的数,谁小就先取谁,取了后相应的指向就往后移一位。然后比较,直至一个数组为空,最后把另一个数组的剩余部分复制过来即可。
代码:
1 public static void mergeSort(int[] array){ 2 3 mergeSortIn(array,0,array.length-1); 4 } 5 //分解 6 public static void mergeSortIn(int[] array,int low,int high){ 7 if(low>=high){ 8 return; 9 } 10 //分解(从数组中间一分为二,直至分解为一个一个的数) 11 int mid = (low+high)>>>1; //右移相当于除2 12 mergeSortIn(array,low,mid); 13 mergeSortIn(array,mid+1,high); 14 //归并(将一个一个的数按序归并) 15 merge(array,low,mid,high); 16 } 17 //归并 18 public static void merge(int[] array,int low,int mid,int high){ 19 int s1 = low; 20 int s2 = mid+1; 21 int len = high-low+1; //新数组的长度 22 int[] ret = new int[len]; //新建一个数组用来存放归并排序后的数 23 int i = 0; //表示ret数组的下标 24 25 while (s1<=mid && s2<=high){ 26 if(array[s1] <= array[s2]){ 27 ret[i++] = array[s1++]; 28 }else { 29 ret[i++] = array[s2++]; 30 } 31 } 32 while (s1<=mid){ 33 ret[i++] = array[s1++]; 34 } 35 while (s2<=high){ 36 ret[i++] = array[s2++]; 37 } 38 for(int j= 0; j<ret.length; j++){ 39 array[j+low] = ret[j]; 40 } 41 }