1. 程式人生 > >【資料結構】Java實現各類經典排序演算法——插入排序、希爾排序

【資料結構】Java實現各類經典排序演算法——插入排序、希爾排序

一、插入排序

    顧名思義,插入排序從左往右掃描陣列,每趟排序把一個元素“插入”到已排序部分陣列的合適位置中。既然是“插入”,則不必兩兩交換元素來進行排序,從邏輯上把當前元素放到合適位置,並把該位置右側部分元素往右移動一格就可以了。這樣做和氣泡排序的交換相鄰元素比,好處在於“交換”的動作被“賦值”取代,因此效率要高一些。這種操作在堆排序中也可以見到。以下是程式碼實現:

    public void insertSort(int[] nums) {
        // 插入排序
        for(int i = 1; i < nums.length; i++) {
            int tmp = nums[i];
            int j = i;
            for( ; j > 0 && tmp < nums[j-1]; j--) {
                nums[j] = nums[j-1];
            }
            nums[j] = tmp;
        }
    }

    有人說插入排序和氣泡排序很像,但其實兩者的排序原理(如上一段所述)和提前跳出迴圈的原理都完全不同,充其量就是兩者的各種“指標”很像而已。兩者時間複雜度均為:最好O(n)、最壞O(n2)、平均O(n2),最好的情況均出現在原陣列“基本有序”的情況下:此時氣泡排序會執行很少次數的內部迴圈,然後在陣列完成排序後,提前跳出外部迴圈;而插入排序則是經常提前跳出內部迴圈,完成所有外部迴圈。

    空間複雜度:O(1);穩定性:穩定。與氣泡排序分析及分析結果均一致。

二、希爾排序

    容易證明,通過交換相鄰元素來進行排序的演算法,平均排序時間均為二次。這個定理不僅對氣泡排序有效,對插入排序、選擇排序等隱含地執行相鄰元素交換來完成排序的演算法也有效。

    為了突破二次魔咒,希爾排序在插入排序的基礎上做出了一點改進,加入了非相鄰元素的交換。先上程式碼:

    public void shellSort(int[] nums) {
        // 希爾排序
        int[] shellArray = new int[] {1, 3, 7};
        for(int d = shellArray.length - 1; d >= 0; d--) {
            for(int i = d; i < nums.length; i++) {
                int tmp = nums[i];
                int j = i;
                for( ; j > d - 1 && tmp < nums[j-d]; j-=d) {
                    nums[j] = nums[j-d];
                }
                nums[j] = tmp;
            }
        }
    }

    從整體上講,希爾排序就是以增量序列(大小為n)中的數值為間隔,間隔由大到小執行了n次插入排序而已。直覺上可以猜到,這個“增量序列”的設計和選擇,可以很大程度上影響本演算法的效率。(以上程式碼中序列為[1, 3, 7])

    演算法發明者希爾提出本演算法的時候,並沒證明出本演算法的“亞二次”平均時間界,給出的增量序列(1,2,4,8...)效果也比較差,此時演算法還是二次的時間複雜度。在後人精心設計的增量序列下,演算法的平均時間複雜度可以接近O(n7/6),最壞情況下O(n4/3)。此時,希爾排序就成為了一種能經常與各類O(nlogn)階排序演算法PK而廣泛運用於各類場合的優秀演算法了。

    除分析複雜且受增量序列大幅影響的時間複雜度外,希爾排序的空間複雜度顯然也是O(1)。但插入排序是穩定的,而希爾排序是不穩定的!因為剛開始間隔比較大,比如陣列[5, 1, 1],在間隔為2的初始情況下,右邊大小為1的元素會被交換到最左邊去。而這種情況在間隔一直是1的插入排序中是不存在的。

相關推薦

資料結構Java實現各類經典排序演算法——插入排序排序

一、插入排序    顧名思義,插入排序從左往右掃描陣列,每趟排序把一個元素“插入”到已排序部分陣列的合適位置中。既然是“插入”,則不必兩兩交換元素來進行排序,從邏輯上把當前元素放到合適位置,並把該位置右側部分元素往右移動一格就可以了。這樣做和氣泡排序的交換相鄰元素比,好處在於

資料結構Java實現圖的DFS和BFS

圖的深度優先遍歷(DFS)和廣度優先遍歷(BFS),DFS利用遞迴來實現比較易懂,DFS非遞迴就是將需要的遞迴的元素利用一個棧Stack來實現,以達到遞迴時候的順序,而BFS則是利用一個佇列Queue來實現。 package DataStructure;

資料結構實現一個位圖

點陣圖法就是bitmap的縮寫。關於bitmap,就是用每一位來存放某種狀態,適用於大規模資料,但資料狀態又不是很多的情況。 通常是用來判斷某個資料存不存在的。 點陣圖的優缺點: 優點: (1),是速

資料結構實現迷宮尋路問題

思路: 解決迷宮求解的問題,從入口出發,順某一方向向前探索,若能走通,則繼續往前走;否則沿原路退回,換一個方向再繼續探索,直至所有可能的通路都探索到為止。為了保證在任何位置上都能沿原路退回,所以需要用一個後進先出的結構來儲存從入口到當前位置的路徑。因此,在求迷宮通路的演算法

資料結構實現表示式求值

用棧實現表示式求值,涉及到中、字尾表示式轉換的問題。 Expression.h /***************** * Calc_Expression() * 功能: 利用棧實現整數表示式求值 * 輸入: 表示式字串 * 輸出: 求值結果 * 作者: wu

資料結構c++ 實現連結串列的建立,查詢,列印,刪除,插入

//程式很簡單,但是要捋順邏輯關係,留著備用 #include #include"stdafx.h" using namespace std; struct node { int data; node* next; }; node * created_hea

資料結構實現迷宮演算法

#include<stdio.h> #include<stdlib.h> #include<string.h> #include<iostream> using namespace std; #define STACK_INIT

資料結構JavaScript實現單鏈表單鏈表反轉

連結串列 連結也是一種儲存資料的工具,不同於陣列,連結串列中的元素並不是連續儲存的。因此不能通過下標去訪問。 連結串列分為單(向)連結串列,雙向連結串列,迴圈連結串列等。.今天來實現一下單鏈表。 單鏈表中的每個元素包括兩個兩個域,一個是儲存元素本身的域,另一

資料結構二叉樹一些基本演算法

二叉樹中搜索某個元素的演算法。 /** * 查詢二叉樹中元素 * @param root * @param data * @return */ Boolean FinadIn

資料結構-線性表-順序表-1324: 演算法2-2:有序線性表的有序合併

1324: 演算法2-2:有序線性表的有序合併 題目描述 已知線性表 LA 和 LB 中的資料元素按值非遞減有序排列,現要求將 LA 和 LB 歸併為一個新的線性表 LC, 且 LC 中的資料元素仍然按值非遞減有序排列。例如,設LA=(3,5,8,11)

java排序演算法(四)------排序

希爾排序 希爾排序也是一種插入排序,它是簡單插入排序經過改進之後的一個更高效的版本,也稱為縮小增量排序,同時該演算法是衝破O(n2)的第一批演算法之一。 程式碼實現: /** *希爾排序的誕生是由於插入排序在處理大規模陣列的時候會遇到需要移動太多元素的問

資料結構堆疊佇列的原理及java實現

一、堆是一個執行時資料區,通過new等指令建立,不需要程式程式碼顯式釋放 <1>優點: 可動態分配記憶體大小,生存週期不必事先告訴編譯器,Java垃圾回收自動回收不需要的資料; <2>缺點: 執行時需動態分配記憶體,資料存取速度較

資料結構連結串列的原理及java實現

一:單向連結串列基本介紹 連結串列是一種資料結構,和陣列同級。比如,Java中我們使用的ArrayList,其實現原理是陣列。而LinkedList的實現原理就是連結串列了。連結串列在進行迴圈遍歷時效率不高,但是插入和刪除時優勢明顯。下面對單向連結串列做一個介

資料結構圖(最短路徑Dijkstra演算法)的JAVA程式碼實現

最短路徑的概念最短路徑的問題是比較典型的應用問題。在圖中,確定了起始點和終點之後,一般情況下都可以有很多條路徑來連線兩者。而邊或弧的權值最小的那一條路徑就稱為兩點之間的最短路徑,路徑上的第一個頂點為源點,最後一個頂點為終點。圖的最短路徑的演算法有很多,本文主要介紹狄克斯特拉(

資料結構各類排序演算法實現

 給出n個學生的考試成績表,每條資訊由姓名和成績組成, 試運用各種排序思想設計演算法並比較其效能,要求實現: a.按分數高低次序,打印出每個學生在考試中獲得的名次,分數相同的為同一名次; b.按名次列出每個學生的姓名與分數。 #include<stdio.h>

資料結構圖(深度優先遍歷廣度優先遍歷)的JAVA程式碼實現

圖的遍歷是指從圖中的任一頂點出發,對圖中的所有頂點訪問一次並且只訪問一次。圖的遍歷是圖的一種基本操作,圖中的許多其他操作也都是建立在遍歷的基礎之上。在圖中,沒有特殊的頂點被指定為起始頂點,圖的遍歷可以從任何頂點開始。圖的遍歷主要有深度優先搜尋和廣度優先搜尋兩種方式。深度優先搜

資料結構圖形的多種表示方法及其java實現之相鄰表法

        上一篇博文講到用相鄰矩陣法表示圖形,該方法的優點是直觀,訪問方便,缺點是,當圖形的規模龐大,節點數目很多時,有許多節點之間並無連線,這樣就浪費了大量的儲存空間。而相鄰表法則解決了這一問題。         相鄰表法只記錄圖形中存在的連線,也即只記錄相鄰矩陣中

資料結構之二叉樹的java實現

二叉樹的定義: 二叉樹是樹形結構的一個重要型別。許多實際問題抽象出來的資料結構往往是二叉樹的形式,即使是一般的樹也能簡單地轉換為二叉樹,而且二叉樹的儲存結構及其演算法都較為簡單,因此二叉樹顯得特別重要。     二叉樹(BinaryTree)是n(n≥0)個結點的有限集,它

資料結構堆疊(順序棧鏈棧)的JAVA程式碼實現

堆疊(stack)是一種特殊的線性表,是一種只允許在表的一端進行插入或刪除操作的線性表。表中允許進行插入和刪除操作的一端稱為棧頂,最下面的那一端稱為棧底。棧頂是動態的,它由一個稱為棧頂指標的位置指示器指示。當棧中沒有資料元素時,為空棧。堆疊的插入操作稱為進棧或入棧,堆疊的刪除

資料結構二叉樹(順序儲存鏈式儲存)的JAVA程式碼實現

二叉樹是一種非線性的資料結構。它是由n個有限元素的集合,該集合或者為空、或者由一個稱為根(root)的元素及兩顆不相交的、被分別稱為左子樹、右子樹的二叉樹組成。當集合為空時,稱該二叉樹為空二叉樹。在二叉樹中,一個元素也可以稱做一個結點。二叉樹是有序的,即若將其左右兩個子樹顛倒