堆通常是乙個可以被看做一棵樹的陣列物件。堆總是滿足下列性質:
堆總是一棵完全二叉樹。
堆中某個節點的值總是不大於或不小於其父節點的值;
將根節點最大的堆叫做最大堆或大根堆,根節點最小的堆叫做最小堆或小根堆。常見的堆有二叉堆、斐波那契堆 等。
這裡主要介紹二叉堆
上面是邏輯上結構, 下面則是實際的儲存結構,我將陣列和樹的都從1開始編號。
以下標pos為5,即值為4的點為例
pos的父親節點為 pos>>1 = 2, 值為3, 左兒子節點為 pos<<1 = 10 值為 10, 右兒子節點為 pos<<1|1 = 11 值為 9
這圖就是乙個小根堆,大根堆也就容易理解了
題目鏈結
題目很簡單,用優先佇列就能過。優先佇列本質還是用堆實現的。
那我們還是用堆來實現。
根據題目要求,我們使用小根堆顯然比較合適些;
//操作1 x,就將x放入陣列的末尾
/*dui陣列用於儲存堆元素
x 是要插入的元素
因為是向上更新的,所以函式名為 up
*/voidup(
int x)}/*
這樣,就能保證每次插入新的元素之後,dui[1] 是堆中的最小值
*/
操作 2
就直接輸出 dui[
1] 就好了
//操作3 移除最小的元素
/*如果只是單純的移除掉根節點,肯定是不行的
所以,我們就把 dui 陣列的最後乙個元素覆蓋掉 根節點 ,同時還要對堆進行維護, 使之依然是 小根堆
*/void
down()
else
break;}
}
本來想上圖的,不過自己畫的真的醜,自己隨便模擬下就可以了
這樣這個題目就能很輕鬆了水過去了
堆排序就簡單了啊,就是上面兩個函式的結合啊。
上面的 操作1 就相當於 輸入元素。
操作3 就不是覆蓋了,是將 根節點 和 最後乙個節 點交換了。
#include
const
int maxn =
100005
;using namespace std;
typedef
long
long ll;
int dui[maxn]
, len;
// len 堆的實際長度
voidup(
int pos)
}void
down
(int pos)
else
break;}
}int
main()
for(
int i=
1; i
)for
(int i=
1; i<=n; i++
)printf
("%d "
, dui[i]);
return0;
}
上面是利用小根堆, 將陣列按降序排列
公升序怎麼辦??
陣列倒著輸出就好了啊
還有大根堆啊
排序 4 堆排序
將待排序的序列構成乙個大頂堆。此時,序列的最大值就是堆頂的根結點。將它移走 就是,將其與堆陣列的末尾元素交換,此時末尾的元素就是最大值 然後將剩餘的n 1個序列重新構成乙個堆,如此反覆。其中關鍵問題 1 如何將無序序列構成乙個堆 2 輸出堆頂元素後,如何調整公升序元素為乙個堆 4.堆排序 堆調整 v...
排序二 堆排序
子結點的鍵值或索引總是小於 或者大於 它的父節點。堆通過一維陣列實現。在起始陣列為 0 的情形中 父節點i的左子節點在位置 2 i 1 父節點i的右子節點在位置 2 i 2 子節點i的父節點在位置 floor i 1 2 堆中的最大值總是位於根節點。堆中定義以下幾種操作 1 最大堆調整 max he...
排序七 堆排序
時間複雜度 最好 o n o n 平均o n o nlogn 最差o n o nlogn 空間複雜度 o n o 1 穩定性 不穩定 堆 順序儲存的完全二叉樹,其每個結點均小於等於或大於等於其子節點。小根堆 每個結點元素的值都小於等於其子節點元素的值的堆。s i s 2 i 1 s i s 2 i ...