排序--4.堆排序(灰常重要滴)
1.原地排序,不穩定的,時間複雜度為O(logn) logn為堆的高度;在任何時候陣列中只有常數個元素儲存在輸入陣列之外’
呼叫遞迴方法實現的堆排序空間複雜度為O(logn),而非遞迴的才是O(1)
2.值得注意的是:
當陣列下標從1開始,即(1<=i<n+1)時,節點 i 的左孩子為 2i,右孩子為 2i+1(右孩子不一定有),i 的父親為 i/2,最後一個父親節點為 n/2
當陣列下標從0開始,即(0<=i<n)時,節點 i 的左孩子為 2i+1,右孩子為 2i+2(右孩子不一定有),i 的父親節點為 (i-1)/2,最後一個父親節點為 (n-1)/2
3.堆排序原理:最大堆節點 i 的值比它的左右字數的值都大 即:父親節點的值>孩子節點值(最小堆相反)
4.演算法步驟:heap_size 最大堆的大小,不是陣列元素個數的大小length;
(1)維持最大堆: maxHeapify(int [] a,int i):是對節點i開始維持:首先i處的值要是左右孩子和其本身三個節點值中最大的那個,如果其本身最大則節點i保持最大堆性質,不用動;否則值最大的孩子和節點i交換位置,然後對節點i的新位置(原來孩子處)開始維持最大堆性質(遞迴)。
該步驟的時間複雜度為O(logn) n為節點數 或者O(h)h為堆高度
(2)建立最大堆:buildMaxHeap(int[] a): 自底向上用maxHeapify對每一個父親節點(最後面的父親節點是n-1/2 前面有講到)建立最大堆,即對n-1/2 到0開始呼叫maxHeapify函式。
該步驟的時間輔助度是對每個父節點呼叫維持最大堆性質函式,所以時間複雜度為O(nlogn)
(3)堆排序演算法heapSort(int[] a):首先建立最大堆buildMaxHeap(a); 其次從尾節點開始到第二個節點(i從length-1降低到1)交換根節點和尾節點,這裡heap_size開始減小;
然後每次對根節點呼叫維持最大堆函式maxHeapify(a,0).
該演算法的時間複雜度是O(nlogn)
5.實現過程:(1)
//4.堆排序 //維持最大堆性質:i表示待維持的節點 public static void maxHeapify(int[] array,int heapSize,int i){ int left=2*i+1; int right=2*i+2;//左右孩子位置,注意 右孩子不一定存在 int largest=i; if(left<heapSize&&array[left]>array[i]){ largest=left; } if(right<heapSize&&array[right]>array[largest]){ largest=right; } if(largest!=i){//節點i處值不是三者中最大的,則交換i和largest兩處的節點, int temp=array[i]; array[i]=array[largest]; array[largest]=temp; maxHeapify(array,heapSize,largest);//交換後對孩子處(節點i的新位置)進行維持最大堆性質 } } public static void maxHeapify2(int[] array,int heapSize,int i){//非遞迴的維持最大堆性質函式 while(true){//迴圈代替遞迴 int left=2*i+1; int right=2*i+2; int largest=i; if(left<heapSize&&array[left]>array[i]){ largest=left; } if(right<heapSize&&array[right]>array[largest]){ largest=right; } if(largest!=i){ int temp=array[i]; array[i]=array[largest]; array[largest]=temp; i=largest;//非遞迴的方式 }else{ break; } } } //建立最大堆:自底向上對每個父節點開始呼叫維持性質函式,注意是自底向上 public static void buildMaxHeap(int[] array){ if(array==null||array.length<=1)return; int heapSize=array.length; int half=(array.length-1)/2; for(int i=half;i>=0;i--){//自底向上 注意最後一個父節點的位置是n-1/2 maxHeapify(array,heapSize,i); } } //堆排序函式:先建立最大堆,然後交換尾節點和根節點,在對根節點維持最大堆性質 public static void heapSort(int[] array){ if(array==null||array.length<=1) return; buildMaxHeap(array);//建立最大堆 for(int i=array.length-1;i>0;i--){//此處i最小值為1,此時只有根節點和I節點 還可以交換 int temp=array[i]; array[i]=array[0]; array[0]=temp; //System.out.print(temp+"\t"); maxHeapify(array,i,0);//此處heap_size=i } }
(2)建立最大堆函式採用非遞迴方式:
6.(1)每次把尾節點取出,不做尾節點和根節點交換,直接maxHeapify可以嗎?
解答:不可以,舉個反例當右子樹的值都比左子樹大時,50,14,48,8,7,46,40,3,2
相關推薦
排序--4.堆排序(灰常重要滴)
1.原地排序,不穩定的,時間複雜度為O(logn) logn為堆的高度;在任何時候陣列中只有常數個元素儲存在輸入陣列之外’ 呼叫遞迴方法實現的堆排序空間複雜度為O(logn),而非遞迴的才是O(1) 2.值得注意的是: 當陣列下標從1開始,即(1<=i<n+1)
(灰常重要)jsp九大內建物件整理總結和EL表示式內建物件
轉自:https://blog.csdn.net/haha_sir/article/details/80350374https://www.cnblogs.com/sharpel/p/5870114.html一、什麼是內建物件1、我的理解是: jsp內建物件,不需要new來建
面試常考:排序演算法2(希爾排序,歸併排序,堆排序)
希爾排序 O(N^d),最壞O(N^2),不穩定 void ShellSort(int A[],int N) { /*O(N^d),最壞O(N^2),不穩定*/ int Si,D,P,i; int tmp; int Sedgewick[]={929,505,209,109,41,
排序演算法(直接插入、氣泡排序、選擇排序、快速排序、希爾排序、堆排序、歸併排序)
main函式 int main() { int data[] = {1,2,6,3,4,7,7,9,8,5}; //bubble_sort(data,10); //select_sort(data,10); Insert_Sort(data,10); fo
排序演算法4---堆排序
堆排序 基本思想: 大堆對應升序序列,小堆對應降序佇列,我們從最後一個非葉子結點建堆,步驟如下: ⑴ 將堆頂元素與當前最大堆的最後一個節點交換 ⑵ 最大堆節點-1,即調整剩下的n-1個節點 ⑶ 從堆頂繼續向下調整,試之滿足最大堆,迴圈⑴和⑵ ,直至剩下一個節點。 時間複雜度: Nlo
排序下篇(快速排序、並歸排序、堆排序、桶排序/基數排序)
5.快速排序 (1)原理: 在要排序的一組數中,通過一趟排序將待排記錄分隔成獨立的兩部分,其中一部分記錄的關鍵字均比另一部分的關鍵字小,則可分別對這兩部分記錄繼續進行排序,以達到整個序列有序。 (2)圖解:這第一次迴圈5 小黑框是已確定位置,大黑框中使用遞迴 (3)程
排序演算法之堆排序(關鍵詞:資料結構/演算法/排序演算法/堆排序)
假定:有 1 個亂序的數列 nums ,其中有 n 個數。 要求:排好序之後是 從小到大 的順序。 堆排序演算法 原理 先將原始的堆,調整為最大堆: 從倒數第 1 個有子結點的結點(下標為 index = n//2 - 1)開始,將以結點 index 為根結點的子堆
資料結構與演算法--排序(冒泡、選擇、歸併、快速排序、堆排序)
/** * 氣泡排序 * @param arr */ function bubbleSort(arr) { let len = arr.length; for (let i =0; i < arr.len; i++) { for (l
排序的模板【氣泡排序、選擇排序、直接插入排序、歸併排序、堆排序】(還有排序後面繼續補)
目錄 氣泡排序: 選擇排序: 歸併排序: 堆排序: 氣泡排序: 第一種寫法: for(int i=0;i<n-1;i++) { for(int j=0;j<n-1-i;j++) { if(a[j]>a[j-1]) swap(a[
資料結構知識整理 - 排序演算法(本篇包括折半插入排序、快速排序以及堆排序)
主要內容 前提 初步認識排序 待排序記錄表的結構定義 折半插入排序(Binary Insertion Sort) 快速排序(Quick Sort) 堆排序(Heap Sort) 前提 排序是計算機程式設計中的一種重要操作,
C語言中常用排序演算法(氣泡排序、選擇排序、插入排序、希爾排序、快速排序、堆排序)實現比較
以下程式在win10 X64位作業系統,使用VS2017執行驗證可行 排序是非常重要且很常用的一種操作,有氣泡排序、選擇排序、插入排序、希爾排序、快速排序、堆排序等多種方法。 例項1 冒泡法排序 1.前言: 陣列中有N個整數,用冒泡法將它們從小到大(或從大到小)排序。冒泡法
排序演算法(四)、選擇排序 —— 簡單選擇排序 和 堆排序
1、簡單選擇排序簡單選擇排序思想是:從頭到尾(從後往前也行)遍歷序列,先固定第一個位置的資料,將該位置後面的資料,依次和這個位置的資料進行比較,如果比固定位置的資料大,就交換。這樣,進行一趟排序以後,第一個位置就是最小的數了。然後重複進行,第 2 次遍歷並且比較後,第二個位置
1098 Insertion or Heap Sort (25 分)(插入排序,堆排序)
According to Wikipedia: Insertion sort iterates, consuming one input element each repetition, and growing a sorted output list. Each iteration, inse
幾種常用的排序演算法(快速排序,希爾排序,堆排序,選擇排序,氣泡排序)
1、歸併排序 基本原理:歸併排序也稱合併排序,其演算法思想是將待排序序列分為兩部分,依次對分得的兩個部分再次使用歸併排序,之後再對其進行合併。操作步驟如下。(1)將所要進行的排序序列分為左右兩個部分,如果要進行排序的序列的起始元素下標為first,最後一個元素的
七大內部排序演算法總結(插入排序、希爾排序、氣泡排序、簡單選擇排序、快速排序、歸併排序、堆排序)
寫在前面: 排序是計算機程式設計中的一種重要操作,它的功能是將一個數據元素的任意序列,重新排列成一個按關鍵字有序的序列。因此排序掌握各種排序演算法非常重要。對下面介紹的各個排序,我們假定所有排序的關鍵字都是整數、對傳入函式的引數預設是已經檢查好了的。只
常見比較排序演算法的實現(歸併排序、快速排序、堆排序、選擇排序、插入排序、希爾排序)
這篇部落格主要實現一些常見的排序演算法。例如: //氣泡排序 //選擇排序 //簡單插入排序 //折半插入排序 //希爾排序 //歸併排序 //雙向的快速排序(以及快速排序的非遞迴版本) //單向的快速排序 //堆排序 對於各個演算法的實現
排序演算法(1):簡單選擇排序和堆排序
1.簡單選擇排序 (1)本質:每一趟從給定待排序序列A[ 1......n ] ,選擇出第i小元素,並和A[i]交換。 程式碼: /************************************************* 演算法:簡單選擇排序(升序) 時間
九種經典排序演算法詳解(氣泡排序,插入排序,選擇排序,快速排序,歸併排序,堆排序,計數排序,桶排序,基數排序)
綜述 最近複習了各種排序演算法,記錄了一下學習總結和心得,希望對大家能有所幫助。本文介紹了氣泡排序、插入排序、選擇排序、快速排序、歸併排序、堆排序、計數排序、桶排序、基數排序9種經典的排序演算法。針對每種排序演算法分析了演算法的主要思路,每個演算法都附上了虛擬
排序演算法——堆排序(大頂堆、小頂堆)
堆排序的思想這裡就先不講了,以後有時間再補上,下面是分別採用大頂堆和小頂堆實現的堆排序。 注意:下面例子中排序的數字是{1,2,5,3,6,4,9,7,8}。 大頂堆方式 #include &
Java資料結構:排序演算法(氣泡排序,選擇排序,插入排序,希爾排序,快速排序,堆排序和合並排序)
public class 氣泡排序 { public static void main(String[] args) { int a[] = { 1, 9, 6, 8, 5, 65, 65, 84, 1, 2, 5, 23, 7, 889 }; for (int i