1. 程式人生 > >八大排序演算法Java及效能比較

八大排序演算法Java及效能比較

選擇排序—堆排序(Heap Sort)

堆排序是一種樹形選擇排序,是對直接選擇排序的有效改進。

基本思想:

堆的定義如下:具有n個元素的序列(k1,k2,...,kn),當且僅當滿足


時稱之為堆。由堆的定義可以看出,堆頂元素(即第一個元素)必為最小項(小頂堆)。
若以一維陣列儲存一個堆,則堆對應一棵完全二叉樹,且所有非葉結點的值均不大於(或不小於)其子女的值,根結點(堆頂元素)的值是最小(或最大)的。如:

(a)大頂堆序列:(96, 83,27,38,11,09)

  (b)  小頂堆序列:(12,36,24,85,47,30,53,91)


初始時把要排序的n個數的序列看作是一棵順序儲存的二叉樹(一維陣列儲存二叉樹),調整它們的儲存序,使之成為一個堆,將堆頂元素輸出,得到n 個元素中最小(或最大)的元素,這時堆的根節點的數最小(或者最大)。然後對前面(n-1)個元素重新調整使之成為堆,輸出堆頂元素,得到n 個元素中次小(或次大)的元素。依此類推,直到只有兩個節點的堆,並對它們作交換,最後得到有n個節點的有序序列。稱這個過程為堆排序

因此,實現堆排序需解決兩個問題:
1. 如何將n 個待排序的數建成堆;
2. 輸出堆頂元素後,怎樣調整剩餘n-1 個元素,使其成為一個新堆。


首先討論第二個問題:輸出堆頂元素後,對剩餘n-1元素重新建成堆的調整過程。


調整小頂堆的方法:

1)設有m 個元素的堆,輸出堆頂元素後,剩下m-1 個元素。將堆底元素送入堆頂((最後一個元素與堆頂進行交換),堆被破壞,其原因僅是根結點不滿足堆的性質。

2)將根結點與左、右子樹中較小元素的進行交換。

3)若與左子樹交換:如果左子樹堆被破壞,即左子樹的根結點不滿足堆的性質,則重複方法 (2).

4)若與右子樹交換,如果右子樹堆被破壞,即右子樹的根結點不滿足堆的性質。則重複方法 (2).

5)繼續對不滿足堆性質的子樹進行上述交換操作,直到葉子結點,堆被建成。

稱這個自根結點到葉子結點的調整過程為篩選。如圖:



再討論對n 個元素初始建堆的過程。


建堆方法:對初始序列建堆的過程,就是一個反覆進行篩選的過程。

1)n 個結點的完全二叉樹,則最後一個結點是第個結點的子樹。

2)篩選從第個結點為根的子樹開始,該子樹成為堆。

3)之後向前依次對各結點為根的子樹進行篩選,使之成為堆,直到根結點。

如圖建堆初始過程:無序序列:(49,38,65,97,76,13,27,49)
                              


                              

 演算法的實現:

從演算法描述來看,堆排序需要兩個過程,一是建立堆,二是堆頂與堆的最後一個元素交換位置。所以堆排序有兩個函式組成。一是建堆的滲透函式,二是反覆呼叫滲透函式實現排序的函式。

  1. package com;  
  2. /* 
  3.  * Java實現快速排序演算法 
  4.  * 由大到小排序 
  5.  * author:wyr 
  6.  * 2016-7-14 
  7.  *兩個步驟:1,建堆  2,對頂與堆的最後一個元素交換位置 
  8.  */
  9. publicclass HeapSort {  
  10.     publicstaticvoid main(String[] args) {  
  11.         int a[] = {3,1,5,7,2,4,9,6,10,8};    
  12.         HeapSort  obj=new HeapSort();  
  13.         System.out.println("初始值:");  
  14.         obj.print(a);  
  15.         for(int i=0;i<a.length;i++){  
  16.             obj.createLittleHeap(a,a.length-1-i);//建立堆,建立的是小頂堆。每次迴圈完,二叉樹的根節點都是最小值,所以與此時的未排好部分最後一個值交換位置
  17.             obj.swap(a, 0, a.length - 1 - i);//與最後一個值交換位置,最小值找到了位置
  18.             obj.print(a);  
  19.             System.out.println();  
  20.         }  
  21.         System.out.println("\n排序後:");  
  22.         obj.print(a);  
  23.     }  
  24.     /* 
  25.      * 建立小頂堆:雙親節點小於子節點的值。從葉子節點開始,直到根節點。這樣建立的堆定位最小值 
  26.      */
  27.     privatevoid createLittleHeap(int[] data, int last) {  
  28.          for (int i = (last- 1) / 2; i >= 0; i--) {  //找到最後一個葉子節點的雙親節點
  29.                 // 儲存當前正在判斷的節點  
  30.                 int parent = i;    
  31.                 // 若當前節點的左子節點存在,即子節點存在
  32.                 while (2 * parent + 1 <= last) {    
  33.                     // biggerIndex總是記錄較大節點的值,先賦值為當前判斷節點的左子節點  
  34.                     int bigger = 2 * parent + 1;//bigger指向左子節點  
  35.                     if (bigger < last) { //說明存在右子節點
  36.                         if (data[bigger] > data[bigger+ 1]) { //右子節點>左子節點時
  37.                             bigger=bigger+1;    
  38.                         }    
  39.                     }    
  40.                     if (data[parent] > data[bigger]) {  //若雙親節點值大於子節點中最大的
  41.                         // 若當前節點值比子節點最大值小,則交換2者得值,交換後將biggerIndex值賦值給k  
  42.                         swap(data, parent, bigger);    
  43.                         parent = bigger;    
  44.                     } else {    
  45.                         break;    
  46.                     }    
  47.                 }    
  48.             }    
  49.     }  
  50.     publicvoid print(int a[]){  
  51.         for(int i=0;i<a.length;i++){  
  52.             System.out.print(a[i]+" ");  
  53.         }  
  54.     }  
  55.      publicvoid swap(int[] data, int i, int j) {    
  56.             if (i == j) {    
  57.                 return;    
  58.             }    
  59.             data[i] = data[i] + data[j];    
  60.             data[j] = data[i] - data[j];    
  61.             data[i] = data[i] - data[j];    
  62.         }    
  63. }  


堆排序需要雙層迴圈,第一層控制迴圈多少次,第二層得到每次的最小值(小頂堆)

  1. package arrayTest;  
  2. import java.util.ArrayList;  
  3. publicclass Solution32 {  
  4. /* 輸入n個整數,找出其中最小的K個數。 
  5.  * 例如輸入4,5,1,6,2,7,3,8這8個數字, 
  6.  * 則最小的4個數字是1,2,3,4,。 
  7.  * */
  8.     public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {  
  9.             ArrayList<Integer> result = new ArrayList<Integer>();  
  10.             if(k > input.length) return result;  
  11.             for(int i = 0; i < k ; i ++){//只排前k次 
  12.                 heapSort(input,i,input.length);//進行第i次排序
  13. 相關推薦

    八大排序演算法Java效能比較

    選擇排序—堆排序(Heap Sort) 堆排序是一種樹形選擇排序,是對直接選擇排序的有效改進。 基本思想: 堆的定義如下:具有n個元素的序列(k1,k2,...,kn),當且僅當滿足 時稱之為堆。由堆的定義可以看出,堆頂元素(即第一個元素)必為最小項(小頂堆)。 若以一維陣列

    常見排序演算法總結效能比較

    一.常見排序演算法有哪些 二. 插入排序 1.直接插入排序 基本思想:插入排序是每次將一個待排序的記錄,按照大小,插入到前面已經排好的有序區中適當的位置,直到將所有記錄插入完位置。大概思想是將待

    [原始碼和文件分享]基於C++的八大排序演算法的實現與比較

    1 概述 排序有內部排序和外部排序,內部排序是資料記錄在記憶體中進行排序,而外部排序是因排序的資料很大,一次不能容納全部的排序記錄,在排序過程中需要訪問外存。我們這裡說說八大排序就是內部排序。 當 n 較大,則應採用時間複雜度為 O(nlog2n) 的排序方法:快速排序、堆排序或歸併排

    五十道程式設計小題目 --- 28 八大排序演算法 java 之 06快速排序

    6. 交換排序—快速排序(Quick Sort) 快速排序演算法介紹       快速排序和歸併排序都使用分治法來設計演算法,區別在於歸併排序把陣列分為兩個基本等長的子陣列,分別排好序之後還要進行歸併(Merge)操作,而快速排序拆分子陣列的時候顯得更有藝術,取一

    五十道程式設計小題目 --- 28 八大排序演算法 java 之 02希爾排序

     2. 插入排序—希爾排序(Shell`s Sort) 希爾排序是1959 年由D.L.Shell 提出來的,相對直接排序有較大的改進。希爾排序又叫縮小增量排序 基本思想: 先將整個待排序的記錄序列分割成為若干子序列分別進行直接插入排序,待整個序列中的記錄“基本有序

    五十道程式設計小題目 --- 28 八大排序演算法 java 之 07歸併排序

    7. 歸併排序(Merge Sort) 基本思想: 歸併(Merge)排序法是將兩個(或兩個以上)有序表合併成一個新的有序表,即把待排序序列分為若干個子序列,每個子序列是有序的。然後再把有序子序列合併為整體有序序列。 歸併排序示例:   合併方法: 設r[

    五十道程式設計小題目 --- 28 八大排序演算法 java 之 01直接插入排序

    1.插入排序—直接插入排序(Straight Insertion Sort) 基本思想: 將一個記錄插入到已排序好的有序表中,從而得到一個新,記錄數增1的有序表。即:先將序列的第1個記錄看成是一個有序的子序列,然後從第2個記錄逐個進行插入,直至整個序列有序為止。 要

    八大排序演算法Java

    概述 排序有內部排序和外部排序,內部排序是資料記錄在記憶體中進行排序,而外部排序是因排序的資料很大,一次不能容納全部的排序記錄,在排序過程中需要訪問外存。 我們這裡說說八大排序就是內部排序。     當n較大,則應採用時間複雜度為O(

    八大排序演算法JAVA實現(時間複雜度O(n-logn)篇)

    本文講述時間複雜度為n*logn的排序演算法:歸併排序、快速排序、堆排序以及希爾排序的原理、Java實現以及變形應用。 一、歸併排序  原理:把兩個有序數列合併為一個有序數列。需遞迴實現。  Java實現: 1 public int[] mergeSort(in

    八大排序演算法JAVA實現(時間複雜度O(n-n)篇)

    本文主要描述3個時間複雜度為n2的排序演算法:氣泡排序、選擇排序、插入排序。 1.氣泡排序:由陣列頭部開始,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。每次交換完成後,當前陣列最大值就會被放在最後。 1 public int[] bubbleSort

    五十道程式設計小題目 --- 28 八大排序演算法 java 00

    【程式28】 題目:對10個數進行排序 1.程式分析:八大排序演算法 擴充套件:八大排序演算法 排序有內部排序和外部排序,內部排序是資料記錄在記憶體中進行排序,而外部排序是因排序的資料很大,一次不能容納全部的排序記錄,在排序過程中需要訪問外存。     當n較大,

    八大排序演算法時間空間複雜度分析,java

    //放在一起感覺又臭又長,所以每排序我單獨放出來了,歡迎大家平均交流指出不足import java.lang.reflect.Array;import java.util.*;public class EightKindOfSort {/*選擇排序    (不穩定演算法) *

    炸金花絕對大小計算、比較排序演算法(Java),包含花色參與和不參與大小比較

    昨日忽生興趣,想起同事正在玩的一個炸金花遊戲,見他們討論略有激烈,想來蠻有趣,於是自己也寫來玩玩。 因有要一次產生很多副牌的需求(可能上1000),要對所有的玩家進行一個排序,因此考慮一個能得到每幅牌的絕對大小的統一演算法。 牌大小計算演算法

    各種內排序演算法的實現效能比較(實驗四)

    1.編寫演算法,分別實現順序表的簡單選擇排序、直接插入排序、氣泡排序、快速排序、兩路合併排序以及堆排序。 2.編寫演算法,利用隨機函式,在檔案中隨機生成n個關鍵字。 3.編寫程式,分別簡單驗證簡單隨

    Java 之 檔案讀寫效能比較總結

    Java 之 檔案讀寫及效能比較總結 2014年05月12日 17:56:49 閱讀數:21765  幹Java這麼久,一直在做WEB相關的專案,一些基礎類差不多都已經忘記。經常想得撿起,但總是因為一些原因,不能如願。 其實不是沒有時間,只是有些時候疲於總結,今得空,下定決心

    C語言實現八大排序演算法詳解及其效能之間的

    概述 排序是資料結構中的重要一節,也是演算法的重要組成部分。主要分為內部排序以及外部排序,今天我們講內部排序,也就是八大排序。 插入排序 直接插入排序 演算法思想 演算

    Java 八大排序演算法總結

    概述 排序有內部排序和外部排序,內部排序是資料記錄在記憶體中進行排序,而外部排序是因排序的資料很大,一次不能容納全部的排序記錄,在排序過程中需要訪問外存。我們這裡說說八大排序就是內部排序。 插入排序 思想:每步將一個待排序的記錄,按其順序碼大小插入到前面已經排序的子序列

    簡單選擇排序演算法原理java實現(超詳細)

    選擇排序是一種非常簡單的排序演算法,就是在序列中依次選擇最大(或者最小)的數,並將其放到待排序的數列的起始位置。 簡單選擇排序的原理 簡單選擇排序的原理非常簡單,即在待排序的數列中尋找最大(或者最小)的一個數,與第 1 個元素進行交換,接著在剩餘的待排序的數列中繼續找最大(最小)的一個數,與第 2 個元素交

    java 八大排序演算法

    文章目錄交換排序氣泡排序快速排序選擇排序插入排序歸併排序基數排序 常用的排序演算法主要包括: 插入排序   直接插入排序   希爾排序 交換排序   氣泡排序   快速排序 選擇排序   簡單選擇排序   堆排序 歸併排序 基數排序 交換排序 氣泡排序 氣泡

    Java版資料結構之八大排序演算法

    排序演算法簡介 交換排序:氣泡排序、快速排序 插入排序:直接插入排序、希爾排序 選擇排序:簡單選擇排序、堆排序 歸併排序 基數排序 對比 程式碼實現 氣泡排序 //氣泡排序 public static void sort(int[] arr){