几种常见的排序方法整理

几种常见的排序方法整理

一、直接插入排序

插入排序是一种简单直观的排序算法。通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在从后向前扫描的过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

算法:
将需要排序的数列看成一个数组,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 }

 

posted @ 2016-01-08 22:58  chenxiangxiang  阅读(945)  评论(0编辑  收藏  举报