歸併排序就這麼簡單

来源:https://www.cnblogs.com/Java3y/archive/2018/03/23/8631584.html
-Advertisement-
Play Games

歸併排序就這麼簡單 從前面已經講解了冒泡排序、選擇排序、插入排序,快速排序了,本章主要講解的是 歸併排序 ,希望大家看完能夠理解並手寫出歸併排序快速排序的代碼,然後就通過面試了!如果我寫得有錯誤的地方也請大家在評論下指出。 歸併排序的介紹 來源百度百科: 歸併排序(MERGE SORT)是建立在歸併 ...


歸併排序就這麼簡單

從前面已經講解了冒泡排序、選擇排序、插入排序,快速排序了,本章主要講解的是歸併排序,希望大家看完能夠理解並手寫出歸併排序快速排序的代碼,然後就通過面試了!如果我寫得有錯誤的地方也請大家在評論下指出。

歸併排序的介紹

來源百度百科:

歸併排序(MERGE-SORT)是建立在歸併操作上的一種有效的排序演算法,該演算法是採用分治法(Divide and Conquer)的一個非常典型的應用。將已有序的子序列合併,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合併成一個有序表,稱為二路歸併。

過程描述:

歸併過程為:比較a[i]和b[j]的大小,若a[i]≤b[j],則將第一個有序表中的元素a[i]複製到r[k]中,並令i和k分別加上1;否則將第二個有序表中的元素b[j]複製到r[k]中,並令j和k分別加上1,如此迴圈下去,直到其中一個有序表取完,然後再將另一個有序表中剩餘的元素複製到r中從下標k到下標t的單元。歸併排序的演算法我們通常用遞歸實現,先把待排序區間[s,t]以中點二分,接著把左邊子區間排序,再把右邊子區間排序,最後把左區間和右區間用一次歸併操作合併成有序的區間[s,t]。

原理:

歸併操作的工作原理如下:

第一步:申請空間,使其大小為兩個已經排序序列之和,該空間用來存放合併後的序列

第二步:設定兩個指針,最初位置分別為兩個已經排序序列的起始位置

第三步:比較兩個指針所指向的元素,選擇相對小的元素放入到合併空間,並移動指針到下一位置

重覆步驟3直到某一指針超出序列尾

將另一序列剩下的所有元素直接複製到合併序列尾

下麵我就來做個小小的總結:

  • 兩個排好序的數組合併一個有序的數組,稱之為歸併排序
  • 步驟:遍歷兩個數組,比較它們的值。誰比較小,誰先放入大數組中,直到數組遍歷完成

一、演算歸併排序過程

現在我有兩個已經排好順序的數組:int[] arr1 = {2, 7, 8}int[] arr2 = {1, 4, 9},我還有一個大數組來裝載它們int[] arr = new int[6];

1.1

那麼,我將兩個數組的值進行比較,誰的值比較小,誰就放入大數組中

首先,拿出arr1[0]arr2[0]進行比較,顯然是arr2[0]比較小,因此將arr2[0]放入大數組中,同時arr2指針往後一格

所以,現在目前為止arr = {1}

1.2

隨後,拿arr1[0]arr2[1]進行比較,顯然是arr1[0]比較小,將arr1[0]放入大數組中,同時arr1指針往後一格

所以,現在目前為止arr = {1,2}

1.3

隨後,拿arr1[1]arr2[1]進行比較,顯然是arr2[1]比較小,將arr2[1]放入大數組中,同時arr2指針往後一格

所以,現在目前為止arr = {1,2,4}

........

遍歷到最後,我們會將兩個已排好序的數組變成一個已排好序的數組arr = {1,2,4,7,8,9}

二、歸併排序前提分析(分治法)

從上面的演算我們就直到,歸併排序的前提是需要兩個已經排好順序的數組,那往往不會有兩個已經排好順序的數組給我們的呀(一般是雜亂無章的一個數組),那這個演算法是不是很雞肋的呢??

其實並不是的,首先假設題目給出的數組是這樣子的:int[] arr = {2, 7, 8, 1, 4, 9};

當我們要做歸併的時候就以arr[3]也就元素為1的那個地方分開。是然後用一個指針L指向arr[0],一個指針M指向arr[3],用一個指針R指向arr[5](數組最後一位)。有了指針的幫助,我們就可以將這個數組切割成是兩個有序的數組了(操作的方式就可以和上面一樣了)

可是上面說了,一般給出的是雜亂無章的一個數組,現在還是達不到要求。比如給出的是這樣一個數組:int[] arrays = {9, 2, 5, 1, 3, 2, 9, 5, 2, 1, 8};

此時,我們就得用到分治的思想了:

  • 那麼我們也可以這樣想將int[] arr = {2, 7, 8, 1, 4, 9};數組分隔成一份一份的,arr[0]它是一個有序的"數組",arr[1]它也是一個有序的"數組",利用指針(L,M,R)又可以操作兩個數組一樣進行排序。最終合成{2,7}.......再不斷拆分合併,最後又回到了我們的arr = {1,2,4,7,8,9},因此歸併排序是可以排序雜亂無章的數組的

這就是我們的分治法--->將一個大問題分成很多個小問題進行解決,最後重新組合起來

三、歸併代碼實現

實現步驟:

  1. 拆分
  2. 合併

........



    public static void main(String[] args) {
        int[] arrays = {9, 2, 5, 1, 3, 2, 9, 5, 2, 1, 8};
        mergeSort(arrays, 0, arrays.length - 1);

        System.out.println("公眾號:Java3y" + arrays);


    }

    /**
     * 歸併排序
     *
     * @param arrays
     * @param L      指向數組第一個元素
     * @param R      指向數組最後一個元素
     */
    public static void mergeSort(int[] arrays, int L, int R) {

        //如果只有一個元素,那就不用排序了
        if (L == R) {
            return;
        } else {

            //取中間的數,進行拆分
            int M = (L + R) / 2;

            //左邊的數不斷進行拆分
            mergeSort(arrays, L, M);

            //右邊的數不斷進行拆分
            mergeSort(arrays, M + 1, R);

            //合併
            merge(arrays, L, M + 1, R);

        }
    }


    /**
     * 合併數組
     *
     * @param arrays
     * @param L      指向數組第一個元素
     * @param M      指向數組分隔的元素
     * @param R      指向數組最後的元素
     */
    public static void merge(int[] arrays, int L, int M, int R) {

        //左邊的數組的大小
        int[] leftArray = new int[M - L];

        //右邊的數組大小
        int[] rightArray = new int[R - M + 1];

        //往這兩個數組填充數據
        for (int i = L; i < M; i++) {
            leftArray[i - L] = arrays[i];
        }
        for (int i = M; i <= R; i++) {
            rightArray[i - M] = arrays[i];
        }


        int i = 0, j = 0;
        // arrays數組的第一個元素
        int  k = L;


        //比較這兩個數組的值,哪個小,就往數組上放
        while (i < leftArray.length && j < rightArray.length) {

            //誰比較小,誰將元素放入大數組中,移動指針,繼續比較下一個
            if (leftArray[i] < rightArray[j]) {
                arrays[k] = leftArray[i];

                i++;
                k++;
            } else {
                arrays[k] = rightArray[j];
                j++;
                k++;
            }
        }

        //如果左邊的數組還沒比較完,右邊的數都已經完了,那麼將左邊的數抄到大數組中(剩下的都是大數字)
        while (i < leftArray.length) {
            arrays[k] = leftArray[i];

            i++;
            k++;
        }
        //如果右邊的數組還沒比較完,左邊的數都已經完了,那麼將右邊的數抄到大數組中(剩下的都是大數字)
        while (j < rightArray.length) {
            arrays[k] = rightArray[j];

            k++;
            j++;
        }
    }

我debug了一下第一次的時候,就可以更容易理解了:

  • 將大數組的前兩個進行拆分,然後用數組裝載起來

  • 比較小數組的元素哪個小,哪個小就先放入大數組中

上面的兩個步驟不斷迴圈,最後得出有序的數組:

四、歸併排序的優化

來源:http://www.cnblogs.com/noKing/p/7940531.html

我這裡整理一下要點,有興趣的同學可到上面的鏈接上閱讀:

  • 當遞歸到規模足夠小時,利用插入排序
  • 歸併前判斷一下是否還有必要歸併
  • 只在排序前開闢一次空間

如果文章有錯的地方歡迎指正,大家互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同學,可以關註微信公眾號:Java3y


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、id 比較的數值,輸出結果為True 或者 False is比較的是記憶體地址 id 查看記憶體地址 記憶體地址相當與門牌號a = 1000 b = 1000 print(a == b) # == 比較的是數值 #is 比較的是記憶體地址。 # print(a is b) #查看記憶體地址id() # p ...
  • xilinx使用高電平複位 altera使用低電平複位 原因:Xilinx 寄存器的SR控制端是高電平有效的。如果RTL代碼採用了低電平有效的複位模式,綜合器將在複位信號驅動寄存器SR控制端之前的插入一個反相器(interver)。你必須使用一個查找表(look up table)來實現反向器,以利 ...
  • 首先我們瞭解一個名詞ORM,全稱是(Object Relational Mapping),即對象關係映射。ORM的實現思想就是將關係型資料庫中表的數據映射成對象,以對象的形式展現,這樣開發人員就可以把對資料庫的操作轉化為對這些對象的操作。Hibernate正是實現了這種思想,達到了方便開發人員以面向 ...
  • 前面小Alan跟大家聊了在Linux伺服器上jdk運行環境的安裝以及redis非關係型資料庫的安裝,今天繼續跟大家聊聊Tomcat的安裝,以及將我們的項目發佈上去併成功的訪問。 第一步:將tomcat的安裝包上傳到伺服器上,tomcat包的下載不用我教了吧,那你乾脆收拾包袱回家種田得了,雖然說回家種 ...
  • 完整的電腦系統包括:應用程式 + 操作系統 + 電腦硬體 一、電腦硬體: 1、五大組成:控制器、運算器、存儲器、輸入設備、輸出設備 控制器:電腦整體的指揮系統 運算器:負責邏輯運算和數學運算 存儲器(I/O):記憶體、外部存儲 輸入設備(I):鍵盤、滑鼠… 輸出設備(0):顯示器、印表機… 2 ...
  • 先上個例題: 描述 使用STL中的優先隊列,將n個點按照橫坐標從小到大順序排序,如果橫坐標相同,按照縱坐標從小到大排序。 輸入 第一行為正整數n,接下來有n行,每行一個點,包含橫坐標和縱坐標,均為整數。 第一行為正整數n,接下來有n行,每行一個點,包含橫坐標和縱坐標,均為整數。 輸出 每組輸出排序後 ...
  • 搞笑系統採用PHP+MySQL實現, 支持電腦版,手機版線上觀看搞笑圖片 有會員制觀看功能 電腦端img: 手機端img: 這是一款不錯的搞笑網站系統源碼 專業的團隊、高效的執行效率 有需要的朋友聯繫我們微信:kjwenlc q:3328752804 ...
  • ping & telnet 實現類: import org.springframework.data.web.JsonPath; import java.io.IOException; import java.net.*; public class PTUtil { /*** * ping操作 * ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...