各種排序算法-Java-冒泡、選擇、插入、快速、歸併排序

文末有各排序算法的比較

冒泡排序:

1、比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。
2、對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。這步做完後,最後的元素會是最大的數。
3、針對所有的元素重複以上的步驟,除了最後一個。
4、持續每次對越來越少的元素重複上面的步驟,直到沒有任何一對數字需要比較。

原始數組 | 6 | 2 | 4 | 1 | 5 | 9 |

第一趟排序(外循環)
①兩兩比較6 > 2交換(內循環)
交換前狀態| 6 | 2 | 4 | 1 | 5 | 9 |
交換後狀態| 2 | 6 | 4 | 1 | 5 | 9 |
②兩兩比較,6 > 4交換
交換前狀態| 2 | 6 | 4 | 1 | 5 | 9 |
交換後狀態| 2 | 4 | 6 | 1 | 5 | 9 |
③兩兩比較,6 > 1交換
交換前狀態| 2 | 4 | 6 | 1 | 5 | 9 |
交換後狀態| 2 | 4 | 1 | 6 | 5 | 9 |
④兩兩比較,6 > 5交換
交換前狀態| 2 | 4 | 1 | 6 | 5 | 9 |
交換後狀態| 2 | 4 | 1 | 5 | 6 | 9 |
⑤兩兩比較,6 < 9不交換
交換前狀態| 2 | 4 | 1 | 5 | 6 | 9 |
交換後狀態| 2 | 4 | 1 | 5 | 6 | 9 |
第二趟排序(外循環)
交換前狀態| 2 | 4 | 1 | 5 | 6 | 9 |
交換後狀態| 2 | 4 | 1 | 5 | 6 | 9 |
②兩兩比較,4 > 1交換
交換前狀態| 2 | 4 | 1 | 5 | 6 | 9 |
交換後狀態| 2 | 1 | 4 | 5 | 6 | 9 |
③兩兩比較,4 < 5不交換
交換前狀態| 2 | 1 | 4 | 5 | 6 | 9 |
交換後狀態| 2 | 1 | 4 | 5 | 6 | 9 |
④兩兩比較,5 < 6不交換
交換前狀態| 2 | 1 | 4 | 5 | 6 | 9 |
交換後狀態| 2 | 1 | 4 | 5 | 6 | 9 |
第三趟排序(外循環)
①兩兩比較2 > 1交換
交換後狀態| 2 | 1 | 4 | 5 | 6 | 9 |
交換後狀態| 1 | 2 | 4 | 5 | 6 | 9 |
②兩兩比較,2 < 4不交換
交換後狀態| 1 | 2 | 4 | 5 | 6 | 9 |
交換後狀態| 1 | 2 | 4 | 5 | 6 | 9 |
③兩兩比較,4 < 5不交換
交換後狀態| 1 | 2 | 4 | 5 | 6 | 9 |
交換後狀態| 1 | 2 | 4 | 5 | 6 | 9 |
第四趟排序(外循環)
第五趟排序(外循環)
排序完畢,輸出最終結果1 2 4 5 6 9

import java.util.Scanner;

//冒泡排序
public class bubbleSort {

    public static int[] bubbleSort(int[] data){
        int len = data.length;
        int middle=0;
        for(int i = 0;i<len-1;i++)
            for(int j = 0;j<len-1-i;j++){
                if(data[j]>data[j+1]){
                    middle=data[j];
                    data[j]=data[j+1];
                    data[j+1]=middle;
            }
        }   
        return data;
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("請輸入需要排序的數組,用逗號隔開:");
        System.out.print("排序前:");
        String inputString = sc.next();
        String[] stringArray = inputString.split(",");
        int length = stringArray.length;
        int[] data = new int[length];
        int[] data1 = new int[length];
        for(int i = 0;i<length;i++){
            data[i]=Integer.parseInt(stringArray[i]);
        }
        sc.close();

        data1=bubbleSort(data);
        System.out.print("排序後:");
        for(int i = 0;i<length;i++){
            if(i==length-1)
                System.out.print(data1[i]+".");
            else
                System.out.print(data1[i]+",");
        }
    }
}

這裏寫圖片描述

冒泡排序是一種穩定排序

快速排序:

思想:
1、在待排序的元素任取一個元素作爲基準(通常選第一個元素),稱爲基準元素;
2、將待排序的元素進行分區,比基準元素大的元素放在它的右邊,比其小的放在它的左邊;
3、對左右兩個分區重複以上步驟,直到所有元素都是有序的。

這裏寫圖片描述

import java.util.Scanner;

public class QuickSort {

    //選擇數組中的一個數,把數組中數字分成兩部分,比該數小的移到左邊,比該數大的移到右邊
    public static int partition(int[] data,int start,int end){
        int pivot = 0;
        int left = start;
        int right = end;
        if( left <= right ){
            //pivot:基準元素
            pivot = data[start];
            //從左右兩邊交替掃描,直到left=right
            while(left!=right){
                //從右往左掃描,找到第一個比基準元素小的元素
                while( right > left && data[right] >= pivot)
                    right--;
                //找到這種元素data[right]後與data[left]交換
                data[left] = data[right];

                //從左往右掃描,找到第一個比基準元素大的元素
                while( left < right && data[left] <= pivot)
                    left++;
                //找到這種元素data[left]後與data[right]交換
                data[right] = data[left];
            }
        }
        data[right] = pivot;//基準元素歸位
        return right;
    }

    public static void quickSort(int[] data,int start,int end){
        int location = 0;
        if(start < end){
            location = partition(data,start,end);
            quickSort(data,start,location-1);
            quickSort(data,location+1,end);
        }
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("請輸入需要排序的數組,用逗號隔開:");
        System.out.print("排序前:");
        String inputString = sc.next();
        String[] stringArray = inputString.split(",");
        int length = stringArray.length;
        int[] data = new int[length];
        for(int i = 0;i<length;i++){
            data[i]=Integer.parseInt(stringArray[i]);
        }
        sc.close();

        quickSort(data,0,length-1);
        System.out.print("排序後:");
        for(int i = 0;i<length;i++){
            if(i==length-1)
                System.out.print(data[i]+".");
            else
                System.out.print(data[i]+",");
        }
    }
}

這裏寫圖片描述

1、當分區選取的基準元素爲待排序元素中的最大或最小值時,爲最壞的情況,移動次數達到最大值C= 1+2+…+(n-1) = n*(n-1)/2 = O(n^2),最差時間複雜度爲O(n^2)
2、當分區選取的基準元素爲待排序元素中的”中值”,爲最好的情況,最好時間複雜度爲O(nlog2n)
3、空間複雜度爲O(log2n)
4、當待排序元素類似[6,1,3,7,3]且基準元素爲6時,經過分區,形成[1,3,3,6,7],兩個3的相對位置發生了改變,所以快速排序是一種不穩定排序

選擇排序

算法思想:
1、在未排序序列中找到最小(大)元素,存放到排序序列的起始位置
2、再從剩餘未排序元素中繼續尋找最小(大)元素,放到已排序序列的末尾
3、以此類推,直到所有元素均排序完畢。

現有無序數組[6 2 4 1 5 9]
第一趟找到最小數1,放到最前邊(與首位數字交換)
交換前:| 6 | 2 | 4 | 1 | 5 | 9 |
交換後:| 1 | 2 | 4 | 6 | 5 | 9 |
第二趟找到餘下數字[2 4 6 5 9]裏的最小數2,與當前數組的首位數字進行交換,實際沒有交換,本來就在首位
交換前:| 1 | 2 | 4 | 6 | 5 | 9 |
交換後:| 1 | 2 | 4 | 6 | 5 | 9 |
第三趟繼續找到剩餘[4 6 5 9]數字裏的最小數4,實際沒有交換,4待首位置無須交換
第四趟從剩餘的[6 5 9]裏找到最小數5,與首位數字6交換位置
交換前:| 1 | 2 | 4 | 6 | 5 | 9 |
交換後:| 1 | 2 | 4 | 5 | 6 | 9 |
第五趟從剩餘的[6 9]裏找到最小數6,發現它待在正確的位置,沒有交換
排序完畢輸出正確結果[1 2 4 5 6 9]

第一趟找到最小數1的細節:
當前數組是| 6 | 2 | 4 | 1 | 5 | 9 |
先把6取出來,讓它扮演最小數
當前最小數6與其它數一一進行比較,發現更小數就交換角色
當前最小數6與2比較,發現更小數,交換角色,此時最小數是2,接下來2與剩餘數字比較
當前最小數2與4比較,不動
當前最小數2與1比較,發現更小數,交換角色,此時最小數是1,接下來1與剩餘數字比較
當前最小數1與5比較,不動
當前最小數1與9比較,不動,到達末尾
當前最小數1與當前首位數字進行位置交換,如下所示
交換前:| 6 | 2 | 4 | 1 | 5 | 9 |
交換後:| 1 | 2 | 4 | 6 | 5 | 9 |
完成一趟排序,其餘步驟類似

import java.util.Scanner;

public class selectionSort {

    public static void selection_sort(int[] arr) {
        int min,temp;

        //i:未排序序列的首位
        for(int i = 0 ; i <arr.length-1;i++){
            //找出最小數,與首位交換
            min = i;
            for(int j = i+1 ;j<arr.length;j++){
                if(arr[min]>arr[j])
                    min = j ;
                //把最小值跟未排序序列的首位交換
                temp = arr[min];
                arr[min] = arr[i];
                arr[i] = temp;
            }
        }
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("請輸入需要排序的數組,用逗號隔開:");
        System.out.print("排序前:");
        String inputString = sc.next();
        String[] stringArray = inputString.split(",");
        int length = stringArray.length;
        int[] data = new int[length];
        for(int i = 0;i<length;i++){
            data[i]=Integer.parseInt(stringArray[i]);
        }
        sc.close();

        selection_sort(data);
        System.out.print("排序後:");
        for(int i = 0;i<length;i++){
            if(i==length-1)
                System.out.print(data[i]+".");
            else
                System.out.print(data[i]+",");
        }
    }
}

這裏寫圖片描述

選擇排序是不穩定排序

插入排序

1、從第一個元素開始,該元素可以認爲已經被排序
2、取出下一個元素,在已經排序的元素序列中從後向前掃描
3、如果該元素(已排序)大於新元素,將該元素移到下一位置
4、重複步驟3,直到找到已排序的元素小於或者等於新元素的位置
5、將新元素插入到該位置後重復步驟2~5

輸入數組: [5, 6, 3, 1, 8, 7, 2, 4]
這裏寫圖片描述

import java.util.Scanner;

public class insertionSort {

    public static void InsertionSort(int[] data){
        int length = data.length;
        for(int i = 0; i < length-1 ; i++ )
            for(int j = i+1 ; j > 0 ; j-- )
                if(data[j-1]>data[j]){
                    int temp = data[j];
                    data[j] = data[j-1];
                    data[j-1] = temp;
                }
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("請輸入需要排序的數組,用逗號隔開:");
        System.out.print("排序前:");
        String inputString = sc.next();
        String[] stringArray = inputString.split(",");
        int length = stringArray.length;
        int[] data = new int[length];
        for(int i = 0;i<length;i++){
            data[i]=Integer.parseInt(stringArray[i]);
        }
        sc.close();

        InsertionSort(data);

        System.out.print("排序後:");
        for(int i = 0;i<length;i++){
            if(i==length-1)
                System.out.print(data[i]+".");
            else
                System.out.print(data[i]+",");
        }
    }
}

這裏寫圖片描述

插入排序是穩定排序

歸併排序

1、申請空間,使其大小爲兩個已經排序序列之和,該空間用來存放合併後的序列
2、設定兩個指針,最初位置分別爲兩個已經排序序列的起始位置
3、比較兩個指針所指向的元素,選擇相對小的元素放入到合併空間,並移動指針到下一位置
4、重複步驟3直到某一指針達到序列尾
5、將另一序列剩下的所有元素直接複製到合併序列尾

這裏寫圖片描述

import java.util.Scanner;

public class MergeSort {

    //歸併排序
    public static void mergeSort(int[] data){
        int[] temp =new int[data.length];
        sort(data,temp,0,data.length-1);
    }

    /** 
     * 遞歸分治 
     * @param data1 待排數組
     * @param data2 臨時數組,大小和data1相同
     * @param left 左指針
     * @param right 右指針 
     */
    public static void sort(int[] data1, int[] data2,int left, int right) {
        if(left < right){
            // 找出中間索引 
            int mid = (left+right)/2;
            sort(data1,data2,left,mid);// 對左邊數組進行遞歸  
            sort(data1,data2,mid+1,right);// 對右邊數組進行遞歸  
            merge(data1,data2,left,mid,right);//合併
        }
    }

    //合併兩個有序的數組
    public static void merge(int data[],int temp[], int left, int mid, int right) {
        //[left,mid] [mid+1,right]
        int i = left ;
        int j = mid + 1 ;
        int k = 0 ;
        //// 從兩個數組中取出最小的放入臨時temp數組
        while(i <= mid && j <= right){
            if(data[i]<=data[j])
                temp[k++] = data[i++];
            else
                temp[k++] = data[j++];
        }
        // 剩餘部分依次放入temp數組(實際上兩個while只會執行其中一個)
        //當某個數組裏只剩1個元素時,直接複製
        while(i<=mid)
            temp[k++] = data[i++];
        while(j<=right)
            temp[k++] = data[j++];

        //將臨時數組中的內容拷貝回原數組中
        for(i=0;i<k;i++){
            data[left+i] = temp[i];
        }
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("請輸入需要排序的數組,用逗號隔開:");
        System.out.print("排序前:");
        String inputString = sc.next();
        String[] stringArray = inputString.split(",");
        int length = stringArray.length;
        int[] data = new int[length];
        for(int i = 0;i<length;i++){
            data[i]=Integer.parseInt(stringArray[i]);
        }
        sc.close();

        mergeSort(data);

        System.out.print("排序後:");
        for(int i = 0;i<length;i++){
            if(i==length-1)
                System.out.print(data[i]+".");
            else
                System.out.print(data[i]+",");
        }
    }
}

這裏寫圖片描述

歸併排序是穩定排序

排序算法比較

這裏寫圖片描述

冒泡排序:
優點:穩定
缺點:慢,每次只能移動相鄰兩個數據

選擇排序:
優點:移動數據的次數已知
缺點:不穩定,且比較次數多

插入排序:
優點:穩定,快
缺點:比較的次數不一定,比較次數越少,插入點後的數據移動越多,特別是當數據總量龐大的時候,但用鏈表可以解決這個問題。

快速排序:
優點:極快,數據移動少
缺點:不穩定

歸併排序:
優點:穩定,時間複雜度低
缺點:空間複雜度略高,需要O(n)輔助空間

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章