Java算法排序之冒泡/插入/選擇/快速畸冲、二分查找 - 附動圖

1. Java排序:冒泡排序 - 最簡單

(1)比較前后相鄰的二個數(shù)據(jù)嫉髓,如果前面數(shù)據(jù)大于后面的數(shù)據(jù),就將這二個數(shù)據(jù)交換邑闲。
(2)這樣對數(shù)組的第 0 個數(shù)據(jù)到 N-1 個數(shù)據(jù)進行一次遍歷后算行,最大的一個數(shù)據(jù)就“沉”到數(shù)組第N-1個位置。
(3)N=N-1苫耸,如果 N 不為 0 就重復前面二步州邢,否則排序完成。


Java冒泡排序

【邏輯】外層0 ~ <length-1褪子,內(nèi)層0 ~ <length-1-i量淌。相鄰元素,比較大小嫌褪,互換位置
【優(yōu)點】穩(wěn)定
【缺點】慢呀枢,每次只能移動相鄰兩個數(shù)據(jù)

public class TestArraySort{
    public static void main(String[] args) {
        // Test 冒泡
        int[] nums = {1, 8, 3, 6, 2, 9, 7, 4, 5};
        bubbleSort(nums);
        for (int i = 0; i < nums.length; i++) {
            System.out.print(nums[i] + " "); // 1 2 3 4 5 6 7 8 9
        }
    }
    
    /**
     * Java排序:冒泡排序
     * 說明:相鄰元素,比較大小笼痛,互換位置
     * @param array 需要排序的無序整數(shù)類型數(shù)組
     */
    public static void bubbleSort(int[] array) {
        // 1. 參數(shù)合法性判斷
        if (null == array || array.length == 0) {
            return;
        }
        
        // 2. 冒泡排序主邏輯
        for (int i = 0; i < array.length-1; i++) {
            for (int j = 0; j < array.length-1 - i; j++) {
                if (array[j] > array[j+1]) { // 相鄰元素裙秋,升序
                //if (array[j] < array[j+1]) { // 相鄰元素,降序
                    int tmp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = tmp;
                }
            }
        }
    }
}

2. Java排序:插入排序 - 簡單

通過構建有序序列缨伊,對于未排序數(shù)據(jù)摘刑,在已排序序列中從后向前掃描,找到相應的位置并插入刻坊。


Java插入排序

插入排序非常類似于整撲克牌枷恕。在開始摸牌時,左手是空的谭胚,牌面朝下放在桌上徐块。接著隶校,一次從桌上摸起一張牌,并將它插入到左手一把牌中的正確位置上蛹锰。為了找到這張牌的正確位置深胳,要將它與手中已有的牌從右到左地進行比較。無論什么時候铜犬,左手中的牌都是排好序的舞终。
如果輸入數(shù)組已經(jīng)是排好序的話,插入排序出現(xiàn)最佳情況癣猾,其運行時間是輸入規(guī)模的一個線性函數(shù)敛劝。如果輸入數(shù)組是逆序排列的,將出現(xiàn)最壞情況纷宇。平均情況與最壞情況一樣夸盟,其時間代價是(n2)。


Java插入排序

【邏輯】外層1 ~ <length像捶,內(nèi)層i ~ 0上陕。第2個數(shù)開始,與前面的數(shù)逐個比較拓春,插入位置
【優(yōu)點】穩(wěn)定释簿,快
【缺點】比較次數(shù)不一定,比較次數(shù)越少硼莽,插入點后的數(shù)據(jù)移動越多庶溶,特別是當數(shù)據(jù)總量龐大的時候

public class TestArraySort{
    public static void main(String[] args) {
        int[] nums = {1, 8, 3, 6, 2, 9, 7, 4, 5};
        insertSort(nums);
        for (int i = 0; i < nums.length; i++) {
            System.out.print(nums[i] + " "); // 1 2 3 4 5 6 7 8 9
        }
    }
    
    /**
     * Java排序:插入排序
     * 說明:第2個數(shù)開始,與前面的數(shù)逐個比較懂鸵,插入位置
     * @param array 需要排序的無序整數(shù)類型數(shù)組
     */
    public static void insertSort(int[] array) {
        // 1. 參數(shù)合法性判斷
        if (null == array || array.length == 0) {
            return;
        }
        
        // 2. 插入排序主邏輯
        for (int i = 1; i < array.length; i++) { // 從第2個數(shù)temp開始
            for (int j = i; j > 0; j--) { // temp每次與前面的數(shù)比較偏螺,插入進去
                if (array[j] < array[j-1]) { // 升序
                //if (array[j] < array[j-1]) { // 降序
                    int temp = array[j];
                    array[j] = array[j-1];
                    array[j-1] = temp;
                }
            }
        }
    }
}

3. Java排序:選擇排序 - 簡單

選擇排序(Selection sort)是一種簡單直觀的排序算法。
它的工作原理是:第一次從待排序的數(shù)據(jù)元素中選出最写夜狻(或最大)的一個元素套像,存放在序列的起始位置,然后再從剩余的未排序元素中尋找到最信寡ā(大)元素凉夯,然后放到已排序的序列的末尾货葬。以此類推采幌,直到全部待排序的數(shù)據(jù)元素的個數(shù)為零。
選擇排序是不穩(wěn)定的排序方法震桶。
原因是用數(shù)組實現(xiàn)的選擇排序是不穩(wěn)定的休傍,用鏈表實現(xiàn)的選擇排序是穩(wěn)定的,因為數(shù)組內(nèi)會破壞相同元素的位置蹲姐,所以選擇排序是不穩(wěn)定的磨取。
在《算法》第四版217頁上作者已經(jīng)說了人柿,有很多辦法可以將任意排序算法變成穩(wěn)定的,但是忙厌,往往需要額外的時間或者空間凫岖。

Java選擇排序

【邏輯】外層0 ~ <length-1,i為固定值逢净,內(nèi)層i+1 ~ <length哥放。固定值與其他值依次比較,互換位置
【優(yōu)點】數(shù)據(jù)移動次數(shù)已知為(n-1)次
【缺點】比較次數(shù)多

public class TestArraySort {
    public static void main(String[] args) {
        int[] nums = {1, 8, 3, 6, 2, 9, 7, 4, 5};
        selectSort(nums);
        for (int i = 0; i < nums.length; i++) {
            System.out.print(nums[i] + " "); // 1 2 3 4 5 6 7 8 9
        }
    }
    
    /**
     * Java排序:選擇排序
     * 說明:固定值與其他值依次比較爹土,互換位置
     * @param array 需要排序的無序整數(shù)類型數(shù)組
     */
    public static void selectSort(int[] array) {
        // 1. 參數(shù)合法性判斷
        if (null == array || array.length == 0) {
            return;
        }
        
        // 2. 選擇排序主邏輯
        for (int i = 0; i < array.length-1; i++) {
            for (int j = i + 1; j < array.length; j++) {
                if (array[i] > array[j]) { // 升序:選擇1個數(shù)array[i]與i+1后面的數(shù)依次比較
                //if (array[i] < array[j]) { // 降序
                    int tmp = array[i];
                    array[i] = array[j];
                    array[j] = tmp;
                }
            }
        }
    }
}

4. Java排序:快速排序 - 遞歸(難)

快速排序的原理:選擇一個關鍵值作為基準值甥雕。比基準值小的都在左邊序列(一般是無序的),比基準值大的都在右邊(一般是無序的)胀茵。一般選擇序列的第一個元素社露。
一次循環(huán):從后往前比較,用基準值和最后一個值比較琼娘,如果比基準值小的交換位置峭弟,如果沒有繼續(xù)比較下一個,直到找到第一個比基準值小的值才交換脱拼。找到這個值之后孟害,又從前往后開始比較,如果有比基準值大的挪拟,交換位置挨务,如果沒有繼續(xù)比較下一個,直到找到第一個比基準值大的值才交換玉组。直到從前往后的比較索引 > 從后往前比較的索引谎柄,結束第一次循環(huán),此時惯雳,對于基準值來說朝巫,左右兩邊就是有序的了。

Java快速排序

【邏輯】選擇第一個數(shù)位基準值石景,開始首尾比較劈猿,首[0]基準值開始的i++找 ≤ 首值的進行交換,尾[length-1]基準值開始的j--找 ≥ 尾值的進行交換潮孽,找到中間后揪荣,兩半邊各自遞歸
【優(yōu)點】極快,數(shù)據(jù)移動少
【缺點】不穩(wěn)定(原因同選擇排序)

public class TestArraySort {
    public static void main(String[] args) {
        int[] nums = {1, 8, 3, 6, 2, 9, 7, 4, 5};
        quickSort(nums, 0, nums.length-1);
        for (int i = 0; i < nums.length; i++) {
            System.out.print(nums[i] + " "); // 1 2 3 4 5 6 7 8 9
        }
    }
    
    /**
     * Java排序:快速排序
     * 說明:選一個數(shù)作為基數(shù)(一般為array[0])往史,大于基數(shù)的放到右邊仗颈,小于這個基數(shù)的放到左邊
     * @param array 需要排序的無序整數(shù)類型數(shù)組
     * @param low 最小基準位置,eg:0
     * @param high 最大基準位置椎例,eg:length-1
     */
    public static void quickSort(int[] array, int low, int high) {
        // 1. 參數(shù)合法性判斷
        if (null == array || array.length == 0) {
            return;
        }
        
        if (low > high) {
            return;
        }
        
        // 2. 快速排序主邏輯
        int i, j, temp, t;
        i = low;
        j = high;
        temp = array[low]; // temp就是基準位

        while (i < j) {
            while (temp <= array[j] && i < j) { // 升序:先看右邊挨决,依次往左遞減
            //while (temp >= array[j] && i < j) { // 降序:先看右邊请祖,依次往左遞遞增
                j--;
            }
            while (temp >= array[i] && i < j) { // 升序:再看左邊,依次往右遞增
            //while (temp <= array[i] && i < j) { // 降序:再看左邊脖祈,依次往右遞減少
                i++;
            }
            if (i < j) { // 如果滿足條件則交換
                t = array[j];
                array[j] = array[i];
                array[i] = t;
            }

        }
        // 最后將基準為與i和j相等位置的數(shù)字交換
        array[low] = array[i];
        array[i] = temp;
        
        quickSort(array, low, j - 1); // 遞歸調用左半邊數(shù)組
        quickSort(array, j + 1, high); // 遞歸調用右半邊數(shù)組
    }
}

5. Java算法:二分查找 - 升降序邏輯處理

又叫折半查找肆捕,要求待查找的序列有序。
默認升序邏輯說明:每次取中間位置的值與待查關鍵字比較盖高,如果中間位置的值比待查關鍵字大福压,則在前半部分循環(huán)這個查找的過程,如果中間位置的值比待查關鍵字小或舞,則在后半部分循環(huán)這個查找的過程荆姆。直到查找到了為止,否則序列中沒有待查的關鍵字映凳。

  • 示例代碼:(嚴謹?shù)呐袛嗟ㄍ病⒂行?升,降序的處理
public class TestBinarySearch {
    public static void main(String[] args) {
        int result = 0;
        
        // Test 升序
        int[] nums1 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        result = binarySearch(nums1, 3);
        System.out.println(result); // 2

        // Test 降序
        int[] nums2 = {9, 8, 7, 6, 5, 4, 3, 2, 1};
        result = binarySearch(nums2, 3);
        System.out.println(result); // 6

        // Test 無序
        int[] nums3 = {1, 8, 3, 6, 2, 9, 7, 4, 5};
        result = binarySearch(nums3, 3);
        System.out.println(result); // -1
    }
    
    /**
     * Java算法:二分查找/折半查找
     * 說明:默認有序,但需判斷知道其為升序還是降序
     * @param array 被查找的數(shù)組诈豌,要求默認有序
     * @param a 需要查找的數(shù)
     * @return int 下標位置
     */
    public static int binarySearch(int[] array, int a) {
        // 1. 參數(shù)合法性判斷
        if (null == array || array.length == 0) {
            return -1;
        }
        
        // 2. 判斷是否有序仆救,以及升序 or 降序
        boolean up = false;
        for (int i = 0; i < array.length - 1; i++) {
            if (array[i] < array[i+1]) {
                if (i+1 == array.length-1) { // 遍歷到最大下標才算
                    up = true; // 降序
                }
            } else if (array[i] > array[i + 1]) {
                if (i+1 == array.length - 1) { // 遍歷到最大下標才算
                    up = false; // 升序
                }
            } else {
                return -1;
            }
        }
        
        // 3. 二分查找主邏輯循環(huán)
        int minIndex = 0;
        int maxIndex = array.length - 1;
        int midIndex;
        while (minIndex <= maxIndex) { // maxIndex/minIndex動態(tài)變化,折半遍歷
            midIndex = (minIndex + maxIndex) / 2;
            if (array[midIndex] > a) {
                if (up) {
                    maxIndex = midIndex-1; // 升序左移
                } else {
                    minIndex = midIndex+1; // 降序右移
                }
            } else if (array[midIndex] < a) {
                if(up) {
                    minIndex = midIndex+1; // 升序右移
                } else {
                    maxIndex = midIndex-1; // 降序左移
                }
            } else { // array[midIndex] == a
                return midIndex;
            }
        }
        
        return -1;
    }
}
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末矫渔,一起剝皮案震驚了整個濱河市彤蔽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌庙洼,老刑警劉巖顿痪,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異油够,居然都是意外死亡蚁袭,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門石咬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來揩悄,“玉大人,你說我怎么就攤上這事鬼悠∩拘裕” “怎么了?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵焕窝,是天一觀的道長蹬挺。 經(jīng)常有香客問我,道長袜啃,這世上最難降的妖魔是什么汗侵? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮群发,結果婚禮上晰韵,老公的妹妹穿的比我還像新娘。我一直安慰自己熟妓,他們只是感情好雪猪,可當我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著起愈,像睡著了一般只恨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上抬虽,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天,我揣著相機與錄音,去河邊找鬼瓤球。 笑死突梦,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的笛辟。 我是一名探鬼主播功氨,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼手幢!你這毒婦竟也來了捷凄?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤围来,失蹤者是張志新(化名)和其女友劉穎跺涤,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體监透,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡钦铁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了才漆。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片牛曹。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖醇滥,靈堂內(nèi)的尸體忽然破棺而出黎比,到底是詐尸還是另有隱情,我是刑警寧澤鸳玩,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布阅虫,位于F島的核電站,受9級特大地震影響不跟,放射性物質發(fā)生泄漏颓帝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望购城。 院中可真熱鬧吕座,春花似錦、人聲如沸瘪板。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽侮攀。三九已至锣枝,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間兰英,已是汗流浹背撇叁。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留畦贸,地道東北人陨闹。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像家制,于是被迫代替她去往敵國和親正林。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容