1. 程式人生 > >各種排序演算法比較(java)

各種排序演算法比較(java)

排序演算法是資料結構中十分基礎的內容,本文總結了常用的排序演算法的原理和效能,還給出了相關的圖解,並且採用java語言實現了演算法,最後給了一個面試中實際的例子,以及演算法複雜度的比較

1、選擇排序

最基本的排序演算法,原理看圖就可以理解:
png

// 選擇排序
    public int[] selectsort(int[] arr)
    {
        for(int x=0;x<arr.length-1;x++)  //最後一個數不用在自己和自己進行比較了,n-1輪
        {
            for(int y=x+1;y<arr.length;y++)
            {
                if
(arr[x]>arr[y]) { int temp=arr[x]; arr[x]=arr[y]; arr[y]=temp; } } } return arr; }

2、插入排序

將當前元素和左邊的元素比較,若當前元素小,就交換兩者,也就相當於插入

// 插入排序
    public int[] insertionSort
(int[] arr) { int len = arr.length; for (int i = 1; i < len; i++) { // j表示當前元素的位置,將其和左邊的元素比較,若當前元素小,就交換,也就相當於插入 // 這樣當前元素位於j-1處,j--來更新當前元素,j一直左移不能越界,因此應該大於0 for(int j=i; j>0 && arr[j]<arr[j-1];j--) { int
temp = arr[j]; // 元素交換 arr[j] = arr[j-1]; arr[j-1] = temp; } } return arr; }

3、氣泡排序

相鄰的兩個元素進行比較,如果符合條件就換位,這樣第一輪,最大的數會在最後面,長度在依次遞減

// 氣泡排序
    public int[] bubbleSort(int[] arr) {
        int len = arr.length;
        for (int i = 0; i < len - 1; i++) {
            for (int j = 0; j < len - 1 - i; j++) {
                if (arr[j] > arr[j+1]) {        // 相鄰元素兩兩對比
                    int temp = arr[j+1];        // 元素交換
                    arr[j+1] = arr[j];
                    arr[j] = temp;
                }
            }
        }
        return arr;
    }

4、快速排序



/**
     * 將陣列的某一段元素進行劃分,小的在左邊,大的在右邊
     */
    public static int divide(int[] a, int start, int end){
        //每次都以最右邊的元素作為基準值
        int base = a[end];
        //start一旦等於end,就說明左右兩個指標合併到了同一位置,可以結束此輪迴圈。
        while(start < end){
            while(start < end && a[start] <= base)
                //從左邊開始遍歷,如果比基準值小,就繼續向右走
                start++;
            //上面的while迴圈結束時,就說明當前的a[start]的值比基準值大,應與基準值進行交換
            if(start < end){
                //交換
                int temp = a[start];
                a[start] = a[end];
                a[end] = temp;
                //交換後,此時的那個被調換的值也同時調到了正確的位置(基準值右邊),因此右邊也要同時向前移動一位
                end--;
            }   
            while(start < end && a[end] >= base)
                //從右邊開始遍歷,如果比基準值大,就繼續向左走
                end--;
            //上面的while迴圈結束時,就說明當前的a[end]的值比基準值小,應與基準值進行交換
            if(start < end){
                //交換
                int temp = a[start];
                a[start] = a[end];
                a[end] = temp;
                //交換後,此時的那個被調換的值也同時調到了正確的位置(基準值左邊),因此左邊也要同時向後移動一位
                start++;
            }   

        }
        //這裡返回start或者end皆可,此時的start和end都為基準值所在的位置
        return end;
    }

    /**
     * 排序
     */
    public static void sort(int[] a, int start, int end){
        if(start > end){
            //如果只有一個元素,就不用再排下去了
            return;
        } 
        else{
            //如果不止一個元素,繼續劃分兩邊遞迴排序下去
            int partition = divide(a, start, end);
            sort(a, start, partition-1);
            sort(a, partition+1, end);
        }   
    }

5、歸併排序



治的最後過程舉例


package cn;

import java.util.Arrays;
// 歸併排序
public class MergeSort {
    public static void main(String []args)
    {
        int []arr = {9,8,7,6,5,4,3,2,1};
        sort(arr,0,8);
        System.out.println(Arrays.toString(arr));
    }
    private static void sort(int[] arr,int start,int end)
    {
        if(start<end)
        {
            int mid = (start+end)/2;
            sort(arr,start,mid);//左邊歸併排序,使得左子序列有序
            sort(arr,mid+1,end);//右邊歸併排序,使得右子序列有序
            merge(arr,start,mid,mid+1,end);//將兩個有序子數組合並操作
        }
    }
    private static void merge(int[] arr,int start1,int end1,int start2,int end2)
    {
        // 建立輔助陣列
        int len=end2-start1+1;
        int[] temp=new int[len];

        int i = start1;//左序列指標
        int j = start2;//右序列指標
        int t = 0;//臨時陣列指標
        while (i<=end1 && j<=end2)
        {   // 將小的放入輔助陣列
            if(arr[i]<=arr[j])
            {
                temp[t++] = arr[i++];
            }else 
            {
                temp[t++] = arr[j++];
            }
        }
        //若左序列此時還有有剩餘的,將左邊剩餘元素填充進temp中
        while(i<=end1)
        {
            temp[t++] = arr[i++];
        }
        //若右序列此時還有有剩餘的,將右序列剩餘元素填充進temp中
        while(j<=end2)
        {
            temp[t++] = arr[j++];
        }
        t = 0;
        //將temp中的元素全部拷貝到原陣列中
        while(start1 <= end2){
            arr[start1++] = temp[t++];
        }
    }
}

結果

[1, 2, 3, 4, 5, 6, 7, 8, 9]

6、堆排序

堆排序是利用堆這種資料結構而設計的一種排序演算法,堆排序是一種選擇排序,它的最壞,最好,平均時間複雜度均為O(nlogn),它也是不穩定排序。首先簡單瞭解下堆結構。堆是具有以下性質的完全二叉樹:每個結點的值都大於或等於其左右孩子結點的值,稱為大頂堆;或者每個結點的值都小於或等於其左右孩子結點的值,稱為小頂堆。如下圖:父節點比較大的是大頂堆,父節點比較小的是小頂堆
這裡寫圖片描述
這裡寫圖片描述
堆排序基本思想及步驟
  堆排序的基本思想是:將待排序序列構造成一個大頂堆,此時,整個序列的最大值就是堆頂的根節點。將最大值放到末尾(最大值和末尾元素交換),此時末尾就為最大值。然後將剩餘n-1個元素重新構造成一個堆,這樣會得到n個元素的次小值。如此反覆執行,便能得到一個有序序列了.
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述

再簡單總結下堆排序的基本思路:
  a.將無需序列構建成一個堆,根據升序降序需求選擇大頂堆或小頂堆;
  b.將堆頂元素與末尾元素交換,將最大元素”沉”到陣列末端;
  c.重新調整結構,使其滿足堆定義,然後繼續交換堆頂元素與當前末尾元素,反覆執行調整+交換步驟,直到整個序列有序。

package cn;

import java.util.Arrays;
/*
 * 堆排序demo
 */
public class HeapSort 
{
    public static void main(String []args)
    {
        int []arr = {1,7,2,9,3,8,6,5,4};
        sort(arr);
        System.out.println(Arrays.toString(arr));
    }
    public static void sort(int []arr)
    {
        //1.構建大頂堆
        for(int i=arr.length/2-1;i>=0;i--)
        {
            //從最後一個一個非葉子結點i從下至上,從右至左調整結構
            adjustHeap(arr,i,arr.length);
        }
        //2.調整堆結構+交換堆頂元素與末尾元素
        for(int j=arr.length-1;j>0;j--){
            swap(arr,0,j);//將堆頂元素與末尾元素進行交換
            adjustHeap(arr,0,j);//重新對堆進行調整
        }

    }

    /*
     * 調整大頂堆
     */
    public static void adjustHeap(int []arr,int i,int length)
    {
        //i是父節點
        while(2*i+1<length)
        {
            // k是子節點
            int k=i*2+1;
            //從i結點的左子結點開始,也就是2i+1處開始,使得k指向i的左右子節點中較大的一個
            // 如果不存在右子節點,就不用比較了
            if(k+1<length && arr[k]<arr[k+1])
            {
                //如果左子結點小於右子結點,k指向右子結點
                k++;
            }
            // 比較該較大節點與父節點
            if(arr[k] <arr[i])  break;

            //如果子節點大於父節點,將子節點和父節點交換
            swap(arr,i,k);
            // 更新父節點,調整下面的子樹
             i = k;
        }
    }

    /*
     * 交換元素
     */
    public static void swap(int []arr,int a ,int b)
    {
        int temp=arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }
}

結果:
[1, 2, 3, 4, 5, 6, 7, 8, 9]

7、希爾排序

希爾排序為了加快速度簡單地改進了插入排序。 使陣列中任意間隔為gap的元素都是有序的。下圖中gap=4:
這裡寫圖片描述

package cn;

import java.util.Arrays;
/*
 *希爾排序
 */
public class ShellSort {
    public static void main(String []args){
        int []arr ={1,4,2,7,9,8,3,6};
        sort(arr);
        System.out.println(Arrays.toString(arr));
    }

    public static void sort(int [] arr)
    {
       //確定初始的增量gap,保證其不能越界
       int gap=1;
       while(gap<arr.length/3)
           gap=3*gap+1;
       // 對於相隔gap的元素進行插入排序
       while(gap>=1)
       {
           for(int i=gap;i<arr.length;i++)
           {
               for(int j=i;j>=gap && arr[j]<arr[j-gap]; j-=gap)
                   swap(arr,j,j-gap);
           }
           gap=gap/3;
       }

    }

    /*
     * 交換陣列元素
     */
    public static void swap(int []arr,int a,int b){
        arr[a] = arr[a]+arr[b];
        arr[b] = arr[a]-arr[b];
        arr[a] = arr[a]-arr[b];
    }
}

結果:
[1, 2, 3, 4, 6, 7, 8, 9]

8、排序演算法的實際場景:

對於公司中所有員工的年齡進行排序,員工大概有幾萬人,要求時間效率是o(n),可以使用輔助空間但是不能超過O(n)

package cn;

import java.util.Arrays;

public class SortAges {

    public static void SortAges(int ages[],int length)
    {
        if(ages==null || length<=0)
            return;
        // 存放各個年齡出現的次數,年齡範圍是0-99,初始值全都是0
        int[] timesOfAge=new int[100];
        for(int i=0;i<=99;i++)
        {
            timesOfAge[i]=0;
        }
        // 遍歷陣列,統計次數
        for(int i=0;i<length;i++)
        {
            int age=ages[i];
            if(age<0||age>99)
                throw new RuntimeException();
            timesOfAge[age]++;          
        }
        // 年齡排序一定是0 1 2、、99這種,關鍵在於需要設定幾次,遍歷所有年齡,該年齡出現幾次,就在ages陣列中寫幾次該年齡
        int index=0;
        for(int i=0;i<=99;i++)
        {
            for(int j=0;j<timesOfAge[i];j++)
            {
                ages[index]=i;
                index++;
            }
        }
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        int[] arr={1,3,3,44,5,6,55,55,55};
        SortAges(arr,9);
        System.out.println(Arrays.toString(arr));
    }
}

結果:
[1, 3, 3, 5, 6, 44, 55, 55, 55]

9、各類排序演算法比較