八大算排序的JAVA实现及选择

插入排序

1.直接插入排序

原理:将数组分为无序区和有序区两个区,然后不断将无序区的第一个元素按大小顺序插入到有序区中去,最终将所有无序区元素都移动到有序区完成排序。

要点:设立哨兵,作为临时存储和判断数组边界之用。

实现:

1. /** 

2.  * 直接插入排序 

3.  * @author ming 

4.  * 

5.  */  

6. public class InsertSort {  

7.     /** 

8.      * @param args 

9.      */  

10.     public static void main(String[] args) {  

11.         int[] a = {12,3,41,23,6,9,45,23,315,19,0};  

12.           

13.         InsertSort sort = new InsertSort();  

14.         sort.Sort(a);  

15.           

16.         for (int i = 0; i < a.length; i++) {  

17.             System.out.print(a[i]);  

18.             System.out.print(" ");  

19.         }  

20.     }  

21.       

22.     public int Sort(int[] arr){  

23.         int rst = 0;  

24.         int tmp = 0 ;  

25.         for (int i = 1; i < arr.length; i++) {  

26.               

27.             tmp = arr[i];  

28.               

29.             int j = i-1;  

30.               

31.             while (j>=0 && tmp < arr[j]) {  

32.                 arr[j+1] = arr[j];  

33.                 j--;  

34.             }  

35.             arr[j+1] = tmp;  

36.               

37.         }  

38.               

39.           

40.         return rst;  

41.     }  

42. }  

 2.希尔排序

原理:又称增量缩小排序。先将序列按增量划分为元素个数相同的若干组,使用直接插入排序法进行排序,然后不断缩小增量直至为1,最后使用直接插入排序完成排序。

要点:增量的选择以及排序最终以1为增量进行排序结束。

实现:

1.   public static int[] shellSort(int []R){  

2.            

3.          int gap = R.length/2;  

4.          int temp;  

5.          while(gap>0){  

6.              for(int i=gap;i<R.length;i++){  

7.                  temp = R[i];  

8.                  int j = i - gap;  

9.                  while(j>=0 && temp < R[j]){  

10.                     R[j+gap] = R[j];  

11.                     j = j - gap;  

12.                 }  

13.                 R[j+gap] = temp;  

14.             }  

15.             gap = gap/2;   

16.         }  

17.         return R;  

18.     }  

19.       

20.     public static void display(int[] R){  

21.         System.out.println();  

22.         for(int i=0;i<R.length;i++){  

23.             System.out.print(R[i]+" ");  

24.         }  

25.     }  

26.       

27.     public static void main(String[] args) {  

28.           

29.         final int M = 50;//定义数组大小为50  

30.         int []R = new int[M];  

31.         for(int i=0;i<M;i++){  

32.             R[i] = new Random().nextInt(100);//生成100以内的随机数  

33.         }  

34.         display(R);  

35.         R = shellSort(R);  

36.         display(R);  

37.   

38.     }  

39.   

40. }  

交换排序

1.冒泡排序

原理:将序列划分为无序和有序区,不断通过交换较大元素至无序区尾完成排序。

要点:设计交换判断条件,提前结束以排好序的序列循环。

实现:

1. public class bubbleSort {  

2. public  bubbleSort(){  

3.      int a[]={49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,98,54,56,17,18,23,34,15,35,25,53,51};  

4.     int temp=0;  

5.     for(int i=0;i<a.length-1;i++){  

6.         for(int j=0;j<a.length-1-i;j++){  

7.         if(a[j]>a[j+1]){  

8.             temp=a[j];  

9.             a[j]=a[j+1];  

10.             a[j+1]=temp;  

11.         }  

12.         }  

13.     }  

14.     for(int i=0;i<a.length;i++)  

15.         System.out.println(a[i]);     

16. }  

17. }  

 2.快速排序

原理:不断寻找一个序列的中点,然后对中点左右的序列递归的进行排序,直至全部序列排序完成,使用了分治的思想。

要点:递归、分治

实现:

1.  public class quickSort {  

2.    

3.    inta[]={49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,98,54,56,17,18,23,34,15,35,25,53,51};  

4.    

5.  public quickSort(){  

6.    

7.      quick(a);  

8.    

9.      for(int i=0;i<a.length;i++)  

10.   

11.        System.out.println(a[i]);  

12.   

13. }  

14.   

15. publicint getMiddle(int[] list, int low, int high) {     

16.   

17.             int tmp = list[low];    //数组的第一个作为中轴     

18.   

19.             while (low < high) {     

20.   

21.                 while (low < high && list[high] >= tmp) {     

22.   

23.                     high--;     

24.   

25.                 }     

26.   

27.                 list[low] = list[high];   //比中轴小的记录移到低端     

28.   

29.                 while (low < high && list[low] <= tmp) {     

30.   

31.                     low++;     

32.   

33.                 }     

34.   

35.                 list[high] = list[low];   //比中轴大的记录移到高端     

36.   

37.             }     

38.   

39.            list[low] = tmp;              //中轴记录到尾     

40.   

41.             return low;                   //返回中轴的位置     

42.   

43.         }    

44.   

45. publicvoid _quickSort(int[] list, int low, int high) {     

46.   

47.             if (low < high) {     

48.   

49.                int middle = getMiddle(list, low, high);  //将list数组进行一分为二     

50.   

51.                 _quickSort(list, low, middle - 1);        //对低字表进行递归排序     

52.   

53.                _quickSort(list, middle + 1, high);       //对高字表进行递归排序     

54.   

55.             }     

56.   

57.         }   

58.   

59. publicvoid quick(int[] a2) {     

60.   

61.             if (a2.length > 0) {    //查看数组是否为空     

62.   

63.                 _quickSort(a2, 0, a2.length - 1);     

64.   

65.         }     

66.   

67.        }   

68.   

69. }

 

选择排序

1.直接选择排序

原理:将序列划分为无序和有序区,寻找无序区中的最小值和无序区的首元素交换,有序区扩大一个,循环最终完成全部排序。

要点:

实现:

package com.test;

 

/**

 * Theselection sorting demo in Java.

 *<a href="http://my.oschina.net/arthor" class="referer"target="_blank">@author</a> Belin Wu

 *@version 1.0 2012-07-29

 */

public class SelectionSort {

       

        /**

         * Sort the int array by selection sorting.

         * @param values the int array for sorting.

         */

        publicstatic void selectionSort(int[] values) {

               inttemp = 0; // 数组元素交换时的临时变量

              

               //进行数组排序

               for(int i = 0; i < values.length - 1; i++) {

                       //认为数组第i个元素是第i趟中的最小值,记录该索引。

                       intminValueIndex = i;

                      

                       for(int j = i + 1; j < values.length; j++) {

                               if(values[minValueIndex] > values[j]) {

                                      minValueIndex= j; // 之前的假设不成立,重新记录数组中最小值的索引值。

                               }

                       }

                      

                       //当minValueIndex值发生了变化才进行数组元素的交换

                       if(minValueIndex != i) {

                               temp= values[i];

                               values[i]= values[minValueIndex];

                               values[minValueIndex]= temp;

                       }

               }

        }

       

        /**

         * Test the selection sorting.

         * @param args the console arguments as astring array.

         */

        publicstatic void main(String[] args) {

               //初始化数组

               int[]values = {1, -1, 3, 3, 2, 9, -10, 7, 6, 5};

 

               //调用方法

               selectionSort(values);

              

               //打印数组

               for(int i = 0; i < values.length; i++) {

                       System.out.println("values["+ i + "] = " + values[i]);

               }

              

               /*输出结果

               values[0]= -10

               values[1]= -1

               values[2]= 1

               values[3]= 2

               values[4]= 3

               values[5]= 3

               values[6]= 5

               values[7]= 6

               values[8]= 7

               values[9]= 9

               */

        }

}

 

2.堆排序

原理:利用大根堆或小根堆思想,首先建立堆,然后将堆首与堆尾交换,堆尾之后为有序区。

要点:建堆、交换、调整堆

实现:

1.  public class HeapSort {  

2.      public static int heap_size;  

3.      //双亲编号  

4.      public static int parent(int i){  

5.          return i/2;  

6.      }  

7.      //左孩子编号  

8.      public static int leftChild(int i){  

9.          return 2*i;  

10.     }  

11.     //右孩子编号  

12.     public static int rightChild(int i){  

13.         return 2*i + 1;  

14.     }  

15.     /** 

16.      * 保持最大堆的性质 

17.      * @param a,堆中的数组元素 

18.      * @param i,对以该元素为根元素的堆进行调整,假设前提:左右子树都是最大堆 

19.      *  

20.      * 由于左右孩子都是最大堆,首先比较根元素与左右孩子,找出最大值,假如不是根元素,则调整两个元素的值; 

21.      * 由于左孩子(右孩子)的值与根元素交换,有可能打破左子树(右子树)的最大堆性质,因此继续调用,直至叶子元素。 

22.      */  

23.     public static void max_heapify(int[] a, int i){  

24.         int left = leftChild(i);  

25.         int right = rightChild(i);  

26.         int largest = 0;  

27.         if(left < heap_size && a[i]<a[left]){  

28.             largest = left;  

29.         }else{  

30.             largest = i;  

31.         }  

32.         if(right < heap_size && a[right] > a[largest]){  

33.             largest = right;  

34.         }  

35.         if(largest == i){  

36.             return ;  

37.         }else{  

38.             int temp = a[i];  

39.             a[i] = a[largest];  

40.             a[largest] = temp;  

41.             max_heapify(a, largest);  

42.         }  

43.     }  

44.     /** 

45.      * 建立最大堆。在数据中,a.length/2+1一直到最后的元素都是叶子元素,也就是平凡最大堆,因此从其前一个元素开始,一直到 

46.      * 第一个元素,重复调用max_heapify函数,使其保持最大堆的性质 

47.      * @param a 

48.      */  

49.     public static void build_max_heap(int[] a){  

50.         for(int i = a.length/2; i>=1; i--){  

51.             max_heapify(a, i);  

52.         }  

53.     }  

54.     /** 

55.      * 堆排序:首先使用建立最大堆的算法建立好最大堆,然后将堆顶元素(最大值)与最后一个值交换,同时使得 

56.      *              堆的长度减小,调用保持最大堆性质的算法调整,使得堆顶元素成为最大值,此时最后一个元素已被排除在外、 

57.      */  

58.     public static void heapSort(int[] a){  

59.         build_max_heap(a);  

60.         for(int i = a.length - 1; i>=2; i--){  

61.             int temp = a[1];  

62.             a[1] = a[i];  

63.             a[i] = temp;  

64.             heap_size--;  

65.             max_heapify(a, 1);  

66.         }  

67.     }  

68.     public static void main(String[] args) {  

69.         int a[] = {0413216910,1487};  

70.         heap_size = a.length;  

71.         heapSort(a);  

72.         for(int i = 0; i< a.length; i++){  

73.             System.out.print(a[i] + "  ");  

74.         }  

75.     }  

76. }  

归并排序

原理:将原序列划分为有序的两个序列,然后利用归并算法进行合并,合并之后即为有序序列。

要点:归并、分治

实现:

1.  public class MergeSortTest {  

2.    

3.      public static void main(String[] args) {  

4.          int[] data = new int[] { 536219487 };  

5.          print(data);  

6.          mergeSort(data);  

7.          System.out.println("排序后的数组:");  

8.          print(data);  

9.      }  

10.   

11.     public static void mergeSort(int[] data) {  

12.         sort(data, 0, data.length - 1);  

13.     }  

14.   

15.     public static void sort(int[] data, int left, int right) {  

16.         if (left >= right)  

17.             return;  

18.         // 找出中间索引  

19.         int center = (left + right) / 2;  

20.         // 对左边数组进行递归  

21.         sort(data, left, center);  

22.         // 对右边数组进行递归  

23.         sort(data, center + 1, right);  

24.         // 合并  

25.         merge(data, left, center, right);  

26.         print(data);  

27.     }  

28.   

29.     /** 

30.      * 将两个数组进行归并,归并前面2个数组已有序,归并后依然有序 

31.      *  

32.      * @param data 

33.      *            数组对象 

34.      * @param left 

35.      *            左数组的第一个元素的索引 

36.      * @param center 

37.      *            左数组的最后一个元素的索引,center+1是右数组第一个元素的索引 

38.      * @param right 

39.      *            右数组最后一个元素的索引 

40.      */  

41.     public static void merge(int[] data, int left, int center, int right) {  

42.         // 临时数组  

43.         int[] tmpArr = new int[data.length];  

44.         // 右数组第一个元素索引  

45.         int mid = center + 1;  

46.         // third 记录临时数组的索引  

47.         int third = left;  

48.         // 缓存左数组第一个元素的索引  

49.         int tmp = left;  

50.         while (left <= center && mid <= right) {  

51.             // 从两个数组中取出最小的放入临时数组  

52.             if (data[left] <= data[mid]) {  

53.                 tmpArr[third++] = data[left++];  

54.             } else {  

55.                 tmpArr[third++] = data[mid++];  

56.             }  

57.         }  

58.         // 剩余部分依次放入临时数组(实际上两个while只会执行其中一个)  

59.         while (mid <= right) {  

60.             tmpArr[third++] = data[mid++];  

61.         }  

62.         while (left <= center) {  

63.             tmpArr[third++] = data[left++];  

64.         }  

65.         // 将临时数组中的内容拷贝回原数组中  

66.         // (原left-right范围的内容被复制回原数组)  

67.         while (tmp <= right) {  

68.             data[tmp] = tmpArr[tmp++];  

69.         }  

70.     }  

71.   

72.     public static void print(int[] data) {  

73.         for (int i = 0; i < data.length; i++) {  

74.             System.out.print(data[i] + "\t");  

75.         }  

76.         System.out.println();  

77.     }  

78.   

79. }

 

基数排序

原理:将数字按位数划分出n个关键字,每次针对一个关键字进行排序,然后针对排序后的序列进行下一个关键字的排序,循环至所有关键字都使用过则排序完成。

要点:对关键字的选取,元素分配收集。

实现:

1.  ackage com.algorithm.sort;  

2.    

3.  import java.util.Arrays;  

4.    

5.  public class RadixSort {  

6.    

7.      //基于计数排序的基数排序算法  

8.      private static void radixSort(int[] array,int radix, int distance) {  

9.          //array为待排序数组  

10.         //radix,代表基数  

11.         //代表排序元素的位数  

12.           

13.         int length = array.length;  

14.         int[] temp = new int[length];//用于暂存元素  

15.         int[] count = new int[radix];//用于计数排序  

16.         int divide = 1;  

17.           

18.         for (int i = 0; i < distance; i++) {  

19.               

20.             System.arraycopy(array, 0,temp, 0, length);  

21.             Arrays.fill(count, 0);  

22.               

23.             for (int j = 0; j < length; j++) {  

24.                 int tempKey = (temp[j]/divide)%radix;  

25.                 count[tempKey]++;  

26.             }  

27.               

28.             for (int j = 1; j < radix; j++) {  

29.                 count [j] = count[j] + count[j-1];  

30.             }  

31.               

32.             //个人觉的运用计数排序实现计数排序的重点在下面这个方法              

33.             for (int j = length - 1; j >= 0; j--) {  

34.                 int tempKey = (temp[j]/divide)%radix;  

35.                 count[tempKey]--;  

36.                 array[count[tempKey]] = temp[j];  

37.             }  

38.               

39.             divide = divide * radix;                  

40.               

41.         }  

42.                   

43.     }  

44.       

45.       

46.     /** 

47.      * @param args 

48.      */  

49.     public static void main(String[] args) {  

50.       

51.         int[] array = {3,2,3,2,5,333,45566,2345678,78,990,12,432,56};  

52.         radixSort(array,10,7);  

53.         for (int i = 0; i < array.length; i++) {  

54.             System.out.print("  " + array[i]);  

55.         }  

56.           

57.   

58.     }  

59.   

60. }  

 

 

 

1快速排序(QuickSort

快速排序是一个就地排序,分而治之,大规模递归的算法。从本质上来说,它是归并排序的就地版本。快速排序可以由下面四步组成。

1 如果不多于1个数据,直接返回。
2 一般选择序列最左边的值作为支点数据。
3 将序列分成2部分,一部分都大于支点数据,另外一部分都小于支点数据。
4 对两边利用递归排序数列。

快速排序比大部分排序算法都要快。尽管我们可以在某些特殊的情况下写出比快速排序快的算法,但是就通常情况而言,没有比它更快的了。快速排序是递归的,对于内存非常有限的机器来说,它不是一个好的选择。 

2 归并排序(MergeSort

归并排序先分解要排序的序列,从1分成22分成4,依次分解,当分解到只有1个一组的时候,就可以排序这些分组,然后依次合并回原来的序列中,这样就可以排序所有数据。合并排序比堆排序稍微快一点,但是需要比堆排序多一倍的内存空间,因为它需要一个额外的数组。

3 堆排序(HeapSort

堆排序适合于数据量非常大的场合(百万数据)。

堆排序不需要大量的递归或者多维的暂存数组。这对于数据量非常巨大的序列是合适的。比如超过数百万条记录,因为快速排序,归并排序都使用递归来设计算法,在数据量非常大的时候,可能会发生堆栈溢出错误。

堆排序会将所有的数据建成一个堆,最大的数据在堆顶,然后将堆顶数据和序列的最后一个数据交换。接下来再次重建堆,交换数据,依次下去,就可以排序所有的数据。

4 Shell排序(ShellSort

Shell
排序通过将数据分成不同的组,先对每一组进行排序,然后再对所有的元素进行一次插入排序,以减少数据交换和移动的次数。平均效率是O(nlogn)。其中分组的合理性会对算法产生重要的影响。现在多用D.E.Knuth的分组方法。

Shell
排序比冒泡排序快5倍,比插入排序大致快2倍。Shell排序比起QuickSortMergeSortHeapSort慢很多。但是它相对比较简单,它适合于数据量在5000以下并且速度并不是特别重要的场合。它对于数据量较小的数列重复排序是非常好的。

插入排序(InsertSort

插入排序通过把序列中的值插入一个已经排序好的序列中,直到该序列的结束。插入排序是对冒泡排序的改进。它比冒泡排序快2倍。一般不用在数据大于1000的场合下使用插入排序,或者重复排序超过200数据项的序列。

冒泡排序(BubbleSort

冒泡排序是最慢的排序算法。在实际运用中它是效率最低的算法。它通过一趟又一趟地比较数组中的每一个元素,使较大的数据下沉,较小的数据上升。它是O(n^2)的算法。

7 交换排序(ExchangeSort)和选择排序(SelectSort

这两种排序方法都是交换方法的排序算法,效率都是 O(n2)。在实际应用中处于和冒泡排序基本相同的地位。它们只是排序算法发展的初级阶段,在实际中使用较少。

8 基数排序(RadixSort

基数排序和通常的排序算法并不走同样的路线。它是一种比较新颖的算法,但是它只能用于整数的排序,如果我们要把同样的办法运用到浮点数上,我们必须了解浮点数的存储格式,并通过特殊的方式将浮点数映射到整数上,然后再映射回去,这是非常麻烦的事情,因此,它的使用同样也不多。而且,最重要的是,这样算法也需要较多的存储空间。

总结

下面是一个总的表格,大致总结了我们常见的所有的排序算法的特点。

排序法

 平均时间

最差情形

稳定度

额外空间

备注

冒泡

 O(n2)

  O(n2)

 稳定

O(1)

n小时较好

交换

  O(n2)

  O(n2)

不稳定

O(1)

n小时较好

选择

 O(n2)

 O(n2)

不稳定

O(1)

n小时较好

插入

 O(n2)

 O(n2)

稳定

O(1)

大部分已排序时较好

基数

O(logRB)

O(logRB)

稳定

O(n)

B是真数(0-9)

R是基数(个十百)

Shell

O(nlogn)

O(ns) 1<s<2

不稳定

O(1)

s是所选分组

快速

O(nlogn)

O(n2)

不稳定

O(nlogn)

n大时较好

归并

O(nlogn)

O(nlogn)

稳定

O(1)

n大时较好

O(nlogn)

O(nlogn)

不稳定

O(1)

n大时较好

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值