1. 程式人生 > >排序--4.堆排序(灰常重要滴)

排序--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函式。

當某節點呼叫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