一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Java實(shí)現(xiàn)常見排序算法(二)

 算法與編程之美 2020-08-08

問題描述

上次的博客討論了排序算法中的插入排序和交換排序兩個(gè)大類,今天將剩下的常見排序算法全部梳理出來。

選擇排序

簡(jiǎn)單選擇排序

基本思想:每一趟排序從待排序的序列中選擇出最小的元素,順序放入到元素序列中,直到排序完成。該算法是一個(gè)不穩(wěn)定的算法并且效率與初始數(shù)據(jù)順序無關(guān)。

空間復(fù)雜度為O(1)

時(shí)間復(fù)雜度最高,平均,最低都為O(n2)
Java實(shí)現(xiàn):

public static int[] selectInsert(int[] n) {

    int minPos,  temp;

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

        minPos =  i;

        //遍歷找出最小數(shù)的位置

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

            if  (n[j] < n[minPos]) {

                 minPos = j;

            }

        }

        //如果最小數(shù)位置不等于當(dāng)前位置指針,就交換位置,即把數(shù)按照從小到大的順序依次排列

        if  (minPos != i) {

             temp  = n[i];

            n[i]  = n[minPos];

             n[minPos] = temp;

        }

    }

    return n;

}

堆排序

基本原理:堆排序是一種樹形選擇排序算法,其原理是將R[1…n]看成一棵完全二叉樹的順序存儲(chǔ)結(jié)構(gòu)。利用完全二叉樹中雙親節(jié)點(diǎn)和孩子結(jié)點(diǎn)的關(guān)系,在當(dāng)前無序區(qū)中選擇關(guān)鍵字最大(最?。┑脑貥?gòu)建成大根堆(小根堆)。堆排序的主要流程便是,建立大(?。└?,然后輸出元素(頂部和底部元素進(jìn)行交換),再調(diào)整堆,直到元素全部輸出。堆排序是一個(gè)不穩(wěn)定的算法。

堆的定義為:n個(gè)關(guān)鍵字序列R[1…n]稱為堆,堆通??梢员豢醋鲆豢脴涞臄?shù)組對(duì)象。

當(dāng)且僅當(dāng)序列滿足R[i≤R[2i]且R[i]≤R[2i+1]時(shí)稱為該堆為大根堆,其中1≤i≤? n/2?

當(dāng)且僅當(dāng)序列滿足R[i]≥R[2i]且R[i]≥R[2i+1]時(shí)稱為該堆為小根堆,其中1≤i≤?n/2?

比如在大根堆中,最大的元素放在根節(jié)點(diǎn)中,且對(duì)于任一非根節(jié)點(diǎn),它的值小于等于其雙親節(jié)點(diǎn)的值。

對(duì)于堆排序來說關(guān)鍵在于構(gòu)造堆,而建堆是一個(gè)反復(fù)調(diào)整篩選的過程。首先從樹的最后一個(gè)非葉子節(jié)點(diǎn)開始調(diào)整,按照堆的性質(zhì)移動(dòng)元素位置。如下圖便是一個(gè)大頂推的調(diào)整過程。

初始堆建立完成后,就是進(jìn)行排序操作,排序操作的主要步驟是:以大根堆為例,每一次排序?qū)⒍秧斣嘏c堆尾元素進(jìn)行交換,然后再調(diào)用調(diào)整堆的算法使除了堆尾元素以外剩下的堆再次調(diào)整成一個(gè)大根堆,這樣循環(huán)length-1次就可以將元素調(diào)整為從小到大的順序,完成排序。

空間復(fù)雜度為O(1)

時(shí)間復(fù)雜度的最高,平均,最低都為O(nlog2n)

Java實(shí)現(xiàn):

//堆排序

private static int[] heapSort(int[] n) {

    //建立堆,從最后一個(gè)非葉子節(jié)點(diǎn)開始

    for (int i =  (n.length - 2) / 2; i >= 0; i--) {

         adjustHeap(n, i, n.length);

    }

    int temp;

    //完成排序,從最后一個(gè)元素進(jìn)行輸出,每次循環(huán)確定一個(gè)元素的位置

    for (int i =  n.length - 1; i >= 1; i--) {

        temp =  n[0];

        n[0] =  n[i];

        n[i] =  temp;

        // 篩選 R[0] 結(jié)點(diǎn),得到i個(gè)結(jié)點(diǎn)的堆

         adjustHeap(n, 0, i);

    }

    return n;

}

//調(diào)整堆

public static void adjustHeap(int[] n, int k, int  length) {

    //設(shè)置堆頂?shù)闹?/span>

    int temp =  n[k];

     //從左孩子開始判斷

    for (int i =  k * 2 + 1; i <= length - 1; i = 2 * i + 1) {

        //如果左孩子小于右孩子

        if (i + 1  < length && n[i] < n[i + 1]) {

             //取右孩子

             i++;

        }

        //如果堆頂?shù)闹荡笥谧笥液⒆又械妮^大者,無需調(diào)整

        if (temp  >= n[i]) {

             break;

        } else {

            //否則的話,將左右孩子中的較大者換到雙親節(jié)點(diǎn)

            n[k]  = n[i];

            //然后將k值更新,方便繼續(xù)向下調(diào)整

            k =  i;

        }

    }

    //將原堆頂位置當(dāng)入最后調(diào)整出來的地方

    n[k] = temp;

}

歸并排序和基數(shù)排序

歸并排序

基本思想:“歸并”的意思是指將兩個(gè)或者兩個(gè)以上的有序表合并成一個(gè)新的有序表。假設(shè)一個(gè)待排序的序列長(zhǎng)度為n,首先我們可以將其視為n個(gè)有序表,即每個(gè)表中元素個(gè)數(shù)為1,然后我們將n個(gè)有序表進(jìn)行兩兩歸并,得到? \lceil?n/2? \rceil?個(gè)長(zhǎng)度為2或者1的有序表然后再再次基礎(chǔ)上進(jìn)行兩兩歸并直到得到一個(gè)長(zhǎng)度為n的有序表為止。這種方法就稱為2路歸并排序。歸并排序是一個(gè)穩(wěn)定的排序算法。PS.歸并排序的發(fā)明者是約翰·馮·諾伊曼,其速度僅次于快速排序(平均狀況下)

例如我們有一個(gè)初始值為[22,11,32,2,12,83,10]的序列,才有2路歸并排序

第一趟歸并后:[11,22],[2,32],[12,83],[10]

第二趟歸并后:[2,11,22,32],[10,12,83]

第三趟歸并后:[2,10,11,12,22,32,83]

空間復(fù)雜度為O(n)

時(shí)間復(fù)雜度的最高,平均,最低都為O(nlog2n)

Java實(shí)現(xiàn):

//歸并排序

public static int[] mergeSort(int[] n, int low, int  high) {

    int mid =  (low + high) / 2;

    if (low <  high) {

         mergeSort(n, low, mid);

         mergeSort(n, mid + 1, high);

        merge(n,  low, mid, high);

    }

    return n;

}

//調(diào)整

public static void merge(int[] n, int low, int mid, int  high) {

    int[]  tempArr;

    int i = low,  j = mid + 1, k = 0;

    tempArr =  Arrays.copyOf(n, high - low + 1);

    // 把較小的數(shù)先移到新數(shù)組中

    while (i  <= mid && j <= high) {

        if (n[i]  < n[j]) {

            tempArr[k++] = n[i++];

        } else {

             tempArr[k++] = n[j++];

        }

    }

    // 把左邊剩余的數(shù)移入數(shù)組

    while (i  <= mid) {

         tempArr[k++] = n[i++];

    }

    // 把右邊邊剩余的數(shù)移入數(shù)組

    while (j  <= high) {

         tempArr[k++] = n[j++];

    }

    // 把新數(shù)組中的數(shù)覆蓋nums數(shù)組

     System.arraycopy(tempArr, 0, n, low, tempArr.length);

}

基數(shù)排序(桶子排序)

基本思想:基數(shù)排序是一種不基于比較的排序,而采用多關(guān)鍵字排序思想,即基于關(guān)鍵字各位的大小進(jìn)行排序,主要使用“分配”和“收集”兩種基本操作對(duì)單邏輯關(guān)鍵字進(jìn)行排序?;鶖?shù)排序又分為最高位優(yōu)先(MSD)排序和最低位優(yōu)先(LSD)排序。他的主要思想是將待排序的整數(shù)按位數(shù)切割成不同的數(shù)字,然后對(duì)每一位的數(shù)進(jìn)行單獨(dú)的比較,具體做法是:將所有待比較數(shù)值統(tǒng)一為同樣的數(shù)位長(zhǎng)度,如有不同位數(shù)則在前面進(jìn)行補(bǔ)零操作,然后從最低位開始,依次進(jìn)行一次排序,這樣從最低位排序一直到最高位排序完成以后, 數(shù)列就變成一個(gè)有序序列。

舉個(gè)栗子:

待排序的數(shù)據(jù)為[222,123,580,996,965,854,775],使用最低位優(yōu)先排序

第一趟將最低位進(jìn)行排序:

[580,222,123,854,965,775,996]

第二趟將中間位進(jìn)行排序:

[222,123,854,965,775,580,996]

第三趟將最高位進(jìn)行排序:

[123,222,580,775,854,965,996]

空間復(fù)雜度:一趟排序需要的輔助空間為O?(r個(gè)隊(duì)列或桶)用于存放d待排序的數(shù)

時(shí)間復(fù)雜度:O(d(n+r)),d趟的分配和收集,一趟分配為O(n),一趟收集為O?。

Java實(shí)現(xiàn)(代碼參考百度百科)

//d表示最大的數(shù)有多少位

public static int[] radixSort(int[] number, int d) {

    //控制鍵值排序依據(jù)在哪一位

    int k = 0,n =  1,m = 1;

    //數(shù)組的第一維表示可能的余數(shù)0-9

    int[][] temp  = new int[10][number.length];

    //數(shù)組orderp[i]用來表示該位是i的數(shù)的個(gè)數(shù)

    int[] order =  new int[10];

    while (m  <= d) {

        for (int  value : number) {

            int  lsd = ((value / n) % 10);

             temp[lsd][order[lsd]] = value;

            order[lsd]++;

        }

        for (int  i = 0; i < 10; i++) {

            if  (order[i] != 0)

                 for (int j = 0; j < order[i]; j++) {

                     number[k] = temp[i][j];

                     k++;

                }

            order[i]  = 0;

        }

        n *= 10;

        k = 0;

        m++;

    }

    return  number;

}

總結(jié)

就此常見的幾個(gè)排序算法就總結(jié)得差不多了,下一次的博客準(zhǔn)備寫一下JDK8中默認(rèn)的排序算法是如何實(shí)現(xiàn)的以及介紹的這幾種排序算法的實(shí)際使用案例和場(chǎng)景。

END

主  編   |   張禎悅

責(zé)  編   |   楊   旭

 where2go 團(tuán)隊(duì)


微信號(hào):算法與編程之美          

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    人人爽夜夜爽夜夜爽精品视频| 白白操白白在线免费观看| 91在线爽的少妇嗷嗷叫| 伊人网免费在线观看高清版| 日韩一区二区三区免费av| 香蕉久久夜色精品国产尤物| 久久婷婷综合色拍亚洲| 国产又粗又猛又长又大| 欧美激情一区=区三区| 欧美国产日本高清在线| 日本黄色录像韩国黄色录像| 伊人久久青草地婷婷综合| 国产传媒中文字幕东京热| 中文字幕日韩欧美理伦片| 后入美臀少妇一区二区| 亚洲欧美日韩中文字幕二欧美 | 日韩在线视频精品视频| av在线免费播放一区二区| 日韩欧美在线看一卡一卡| 国产视频在线一区二区| 日本 一区二区 在线| 一区二区福利在线视频| 亚洲熟妇熟女久久精品 | 亚洲中文字幕熟女丝袜久久| av在线免费观看在线免费观看| 欧美在线视频一区观看| 亚洲香艳网久久五月婷婷| 欧美精品一区二区水蜜桃| 欧美日韩综合综合久久久| 噜噜中文字幕一区二区| 日韩特级黄片免费观看| 日韩在线视频精品视频| 亚洲中文字幕在线观看黑人| 日韩熟妇人妻一区二区三区| 亚洲精品成人午夜久久| 国产传媒欧美日韩成人精品| 粉嫩内射av一区二区| 亚洲另类欧美综合日韩精品| 国产超薄黑色肉色丝袜| 欧美三级大黄片免费看| 大尺度激情福利视频在线观看|