放牛娃談堆排序---(爲了說明白,我重新學習瞭如何說“人話”)

原創不易,如果你覺得對你有用,哪怕一點點也好,請留下一個贊再走,謝謝啦啦啦!!

一、前期知識儲備

  1. 堆排序是對於完全二叉樹而言

完全二叉樹的那些事:

  1. 定義:對於一個樹高爲h的二叉樹,如果其第0層至第h-1層的節點都滿。如果最下面一層節點不滿,則所有的節點在左邊的連續排列,空位都在右邊。這樣的二叉樹就是一棵完全二叉樹(不理解沒關係,是我的錯,不許噴我
  2. 性質:如果n個節點的完全二叉樹的節點按照層次並按從左到右的順序從0開始編號,對於每個節點都有:
    • 序號爲0的節點是根對於i>0,
    • 其父節點的編號爲(i-1)/2。
    • 若2·i+1<n,其左子節點的序號爲2·i+1,否則沒有左子節點
    • 若2·i+2<n,其右子節點的序號爲2·i+2,否則沒有右子節點。

是不是很枯燥?是不是看不下去?小夥子,彆着急,磨刀不誤砍柴工。,我給你上個圖,你就懂上面所說的一切了。
在這裏插入圖片描述
2. 那堆又是什麼呢?

  • 堆的定義:
  • 每個非葉子結點的值都大於或等於其左孩子和右孩子結點的值,稱之爲大根堆
  • 每個結點的值都小於或等於其左孩子和右孩子結點的值,稱之爲小根堆
  • 大根堆常用於升序操作
  • 小根堆常用於降序操作

千言萬語不勝一圖,看圖哈
在這裏插入圖片描述

二、堆如何跟排序掛上鉤的?

理由很簡單,因爲堆這種數據結構可以用於排序(雖然感覺是廢話,哈哈哈哈,不管了,先說人話)不信你往下看。

  • 根據大頂堆的特性,我們可以知道大根堆根節點就是所有節點的最大值
  • 所以我們可以將最大值的根節點取下(人話:替換)與最後一個節點的值進行互換,然後將剩餘的節點繼續構造成大根堆

三、堆排序思想

非常重要呀呀呀,不懂也沒關係,下面有圖有真相

  1. 首先將待排序的數組構造成一個大根堆,此時,整個數組的最大值就是堆結構的頂端(根節點)

  2. 將頂端的數與末尾的數交換,此時,末尾的數爲最大值,剩餘待排序數組個數爲n-1

  3. 將剩餘的n-1個數再構造成大根堆,再將頂端數與n-1位置的數交換,如此反覆執行,便能得到有序數組

四、如何進行堆排序(附親手畫的圖)

上面說的是不是還是很懵逼???,沒關係,既然是說人話,那我就上個圖來解釋:

說明:以下畫的樹必須滿足完全二叉樹,因爲這是堆這個數據結構的前提

  1. 給定一個數組,如何知道非哪些元素是非葉子節點個數呢?
  • 根據一條公式即可知道了,total = arry.length-1(下標從0開始)
  • 看下圖哈
    在這裏插入圖片描述
  1. 構建大頂堆順序
  • 依次處理非葉子節點
  • 順序是從上往下、從右往左

在這裏插入圖片描述

  1. 堆排序

在這裏插入圖片描述
簡要說一下人話:

  1. 給定一個待排序的數組,我們要將它變成大頂堆數組,這裏之所以要給出完全二叉樹來,是因爲這樣便於理解哈
  2. 我們是直接操作數組使其變成大頂堆,而不是樹,但是原理是一樣的,因爲我們操作數組的時候就是用到上面說的完全二叉樹的性質(下標索引找孩子節點
  3. 這裏用樹來演示,就是爲了便於理解,真正操作是對數組直接操作。

再放兩個圖:
仔細品,不懂可以留言交流呀!圖醜也歡迎留言噴哈哈哈
在這裏插入圖片描述
調整好大頂堆後,根(arry[0])節點值跟倒二節點(arry[5])值又互換,看圖
在這裏插入圖片描述

五、擼代碼(詳細註釋,不怕你看不懂)

紙上得來終且淺,得知此時要躬行,看了再多還是得擼代碼
如果你看到這裏了,要個贊不過分吧,哈哈哈哈

代碼:

package suanFa;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

/**
 * 堆排序的學習:
 *  時間複雜度:O(nlogn),遠比冒泡,簡單選擇,直接插入的O(n^2)好很多,但是它是個不穩定的算法
 * @公衆號 放牛娃學編程
 *
 */

public class HeapSort {
	public static void main(String[] args) {
//		int[] arry = {20};
//		//測試一波
//		Heapsort(arry);
//		System.out.println("數組已經排序完了:"+Arrays.toString(arry));
		//性能測試一波,8千萬數據排序
		int[] arry = new int[80000000];
		for(int i = 0; i < 80000000; i++)
		{
			arry[i] = (int) (Math.random()*80000000);
		}
		Date start = new Date();
		Heapsort(arry);
		Date end = new Date();
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String startTime = simpleDateFormat.format(start);
		String endTime = simpleDateFormat.format(end);
		System.out.println("排序前的時間:"+startTime);
		System.out.println("排序後的時間:"+endTime);
		
		
	}
	
	//構建大頂堆
	public static void Heapsort(int[] arry)
	{
		//構建一棵大頂堆,策略:依次處理非葉子節點,從右往左,從上往下
		for(int i = arry.length / 2 - 1; i >= 0; i--)
		{
			HeapAdjust(arry, i, arry.length);
		}
		//開始排序(取大頂堆的根節點,即使最大值,跟數組最後一個調換位置,然後將剩餘的數重新調整爲大頂堆)
		for(int j = arry.length - 1; j > 0 ; j--)
		{
			//交換位置
			swap(arry,0, j);
			//將剩餘的節點(這裏是數組)調整爲大頂堆
			HeapAdjust(arry, 0, j);
		}
		
	}
	
	private static void swap(int[] arry, int i, int j) {
		// TODO Auto-generated method stub
		int temp = arry[i];
		arry[i] = arry[j];
		arry[j] = temp;
	}

	//調整堆
	/**
	 * 
	 * @param arry 需要調整的數組
	 * @param index 非葉子節點下標索引
	 * @param length 需要調整的數組長度
	 */
	public static void HeapAdjust(int[] arry, int index, int length)
	{
		//1.0 用一個臨時變量將該節點值暫時保存起來
		int temp = arry[index];
		int k;
		//下標爲什麼要這樣變化,根據完全二叉樹的父節點與子節點的關係得出來的(編號從0開始編號)
		for(k=2*index + 1; k < length; k = 2*k+1)
		{
			if(k+1 < length && arry[k] < arry[k+1])
			{
				//指向右子節點(較大的下標)
				++k;
			}
			/**如果父節點已經是大於等於孩子節點(那直接退出循環,爲什麼可以這樣呢?
			   因爲我們採取的策略是:處理非葉子節點時,從右往左,從上往下。假設非葉子節點編號爲:4,3,2,1)
			**/
			if(temp >= arry[k])
			{
				break;
			}
			//替換
			arry[index] = arry[k];
			index = k;
		}
		//插入
		arry[index] = temp;
	}
}
六、 八千萬數據測試堆排序性能

上圖程序中,我用8千萬的數據進行堆排序,我的電腦用時:
在這裏插入圖片描述

  1. 可能我的電腦配置比較差勁,但是比冒泡、簡單排序好太多了,不信你自己玩玩,我這破電腦就不試了哈
  2. 歡迎留言看看你的運行時間是多少,看是不是吊打我電腦呢,哈哈哈哈哈
  3. 看在我熬夜肝圖的份上就點個贊吧,圖不好也可以噴哈哈哈

都已經看到這了,再不給贊,那就說不過去了吧

七、分享交流

最後有興趣一起交流的,可以關注我的公衆號:這裏你能夠學到很實用的技巧,不是常用的我不說,公衆號回覆提取碼即可獲取以下學習資料啦啦啦啦,喜歡就拿去吧!!

(鏈接時常會失效,若出現此類情況,可以加我微信:17722328325(加時請備註:學習資料))

  1. Java web從入門到精通電子書

  2. Python機器學習電子書

  3. Python400集(北京尚學堂)

  4. JavaScript項目案例、經典面試題

  5. Java300集(入門、精通)

  6. Java後端培訓機構錄集(同事培訓內部提供)

  7. java重要知識pdf文檔(價值連城呀呀,不收藏你會後悔的)

額外一堆電子書:
在這裏插入圖片描述
在這裏插入圖片描述



        喜歡就關注吧,點個贊吧

在這裏插入圖片描述
這是分享生活、電影、資料、書籍的一個公衆號,有需要的也可以看看喲!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章