基於C#的堆排序

堆是一種完全二叉樹,也叫二叉堆。
分別分爲兩種類型: 最大堆 以及 最小堆;

最大堆(大頂堆), 所有父節點都大於子節點
最小堆(小頂堆), 所有父子點都小於子節點

右爲 大頂堆,
左爲 小頂堆,

根節點叫堆頂 , 根節點一定是 整個堆中 最小/最大的。
在這裏插入圖片描述

堆排序利用這個 特點進行排序。
每次 它調整後, 最大的節點或最小的節點 總是排到第一位去,
那麼 可以讓最大 節點 存儲到它 最大的節點編號上, 這樣 最後一位就是保存了 所有節點中最大的節點了,依次的, 把第二大的浮去上,再放到 第二大的節點編號上,直到 最後 放到 2號 上。

在這裏插入圖片描述

構建大定堆的 思路:就是讓所有的 非葉子節點(父節點) 與它的兩個子節點
依次比較 ,保存最大。
從最後一個非葉子節點開始 依次比較保存 最大。

上圖 最後一個非葉子 節點 編號 是4 它的值是 60, 它會和 編號8,9 進行比較 ,如果需要交換,需要 再去從交換過的 索引開始 對它 進行調整

然後再從 編號3 開始,它的值是80, 它會 和 編號 6,7進行 比較。
,如果需要交換,需要 再去從交換過的 索引開始 對它 進行調整

然後再從 編號2 開始 它的值是70,它會和編號4,5進行比較。
,如果需要交換,需要 再去從交換過的 索引開始 對它 進行調整

最後 從編號1開始,它的值是90,它會和編號2 和3 進行 比較。

完全二叉樹中,它的左子節點 編號 是父節點編號的兩倍。
即 leftIndex=2fatherIndex;
它的右節點是 左節點加上1,
即 rightIndex=2
fatherIndex+1
逆推 可以得
fatherIndex=leftIndex/2;
fatherIndex=(rightIndex-1)/2;

最後一個非葉子節點編號,就是最後一個節點的 父節點,
完全二叉樹中 最後一個 節點 一定是 右子節點。
所以 非葉子節點編號公式 爲
(length-1)/2

知道這個 就可以進行調整了。

//從 調整num編號的元素, 僅僅是調整一個 
 void HeapAdjust(int numToAdjust,int[] nums,int maxLimit)
 {
	    int i=numToAdjust;
		int tempMaxNum=i; //保存 最大
		while(true)
		{
			int left= i*2;
			int right= i*2+1;
	
			//節點 存在  且是它的值是最大的 
			if(left<maxLimit&& nums[left-1]>nums[tempMaxIndex-1])
			{
			 	tempMaxNum=left;
			}
			if(rightt<maxLimit&&nums[right-1]>nums[tempMax-1])
			{
			 	tempMaxNum=right;
			}
			//需要交換
			if(tempMaxNum!=i)
			{
				int temp=nums[temMaxNum-1];
				nums[temMaxNum-1]=nums[i];
				nums[i]=temp;
			 	i=tempMaxNum;//再從交換過的節點 進行調整
			}else//不需要調整退出
			{
				break; 
			}
		}
 }
void BuildHeap(int[] nums)
{
	//從最後一個非葉子節點開始
	for(int i=nums.Lenght/2;i>0;i--)
	{
		HeapAdjust(i,nums,nums.Length);
	}
}

void HeapSort(int[] nums)
{
	BuildHeap(nums);//構建 大定堆  
	for(int i=nums.Length-1,i>1;i--)
	{
		int temp=nums[i];
		nums[i]= nums[0];
		nums[0]=temp;
		//首尾交換  再進行調整堆 最後一個節點不需要 交換了  也就不用+1了  
		//因爲 編號 比索引多1
		 HeapAdjust(1,nums,i); 
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章