堆的介紹
實例問題:
如果需要在一堆數(shù)據(jù)里面今艺,不斷提取,其中最大或最小的數(shù)據(jù)实牡;
請問怎么實現(xiàn)创坞?
實例分析:
可以使堆排序,實現(xiàn)上述功能:
堆是一個完全二叉樹纲堵;
對于堆來說婉支,有大頂堆和小頂堆的區(qū)別蝌以;
大頂堆:根結(jié)點對應的數(shù)據(jù)值跟畅,跟其他結(jié)點對應的數(shù)據(jù)值比較,根結(jié)點對應的數(shù)據(jù)值虱痕,最大部翘,如下圖所示:
小頂堆:根結(jié)點對應的數(shù)據(jù)值,跟其他結(jié)點對應的數(shù)據(jù)值比較夹囚,根結(jié)點對應的數(shù)據(jù)值荸哟,最小,如下圖所示:
雜論無章的完全二叉樹掏父,構(gòu)造成大頂堆之后爵政,如果要變成小頂堆钾挟,實現(xiàn)思路如下:
先將大頂堆的根結(jié)點徽千,移到最下面双抽;
然后將n-1個值,重新排序成大頂堆慎菲,移到最下面露该;
。书幕。台汇。。牵素。。
移植n-1次赠幕,還剩一個值在最上面,作為根結(jié)點逆屡;
這就是小頂堆了碳胳。
代碼實現(xiàn)-大頂堆
首先挨约,新建工程,如下圖所示:
參考配置工程參數(shù),如下圖所示:
在主函數(shù)中,隨機定義一個數(shù)組篮撑,存儲幾組數(shù)據(jù)赢笨,如下圖所示:
定義大頂堆的排序方法,其中傳遞數(shù)組參數(shù)桐筏,如下圖所示:
因為九昧,編號最大的結(jié)點,肯定是葉子結(jié)點毕匀;
所以根據(jù)公式:左子結(jié)點是2i,右子結(jié)點是2i+1
最大編號的結(jié)點躁垛,對應的父結(jié)點為:n/2=i,取商即可胶滋,忽略余數(shù);
根據(jù)該父結(jié)點悲敷,同理,對應父結(jié)點的父結(jié)點為:n/2=a理张,取商即可拷况,忽略余數(shù)奏寨;
一直到,編號為1為止病瞳,如下圖所示:
然后套菜,完成一次大頂堆的排序;
首先,設(shè)置max最大值耕拷,默認為i骚烧;
根據(jù)公式凭戴,左子結(jié)點的編號涉枫,就是2i乐纸;右子結(jié)點的編號汽绢,就是2i+1疆拘;
如圖所示:
判斷,如果左子結(jié)點的編號值匾灶,小于最大編號值棱烂;如果左子結(jié)點,對應的數(shù)據(jù)值秃踩,大于默認的最大數(shù)據(jù)值憔杨;
將左子結(jié)點的編號值抛蚤,賦值給缀壤,最大數(shù)據(jù)的編號值苍糠;
如下圖所示:
同理,判斷,如果右子結(jié)點的編號值蚓炬,小于最大編號值松逊;如果右子結(jié)點,對應的數(shù)據(jù)值肯夏,大于默認的最大數(shù)據(jù)值经宏;
將右子結(jié)點的編號值,賦值給熄捍,最大數(shù)據(jù)的編號值烛恤;
如下圖所示:
判斷,max是否仍等于i余耽;
max的默認值是i缚柏,經(jīng)過比較后,如果max不等于i了碟贾,說明子結(jié)點對應的值币喧,比默認的數(shù)據(jù)值大;
交換兩者的數(shù)據(jù)袱耽,如下圖所示:
完成一次杀餐,單獨的大頂堆排序。
對于堆排序來說朱巨,它們之間史翘,是有嵌套關(guān)系的,如下圖所示:
如上圖所示冀续,4和8琼讽、9可以構(gòu)成一個頂堆,2和4洪唐、5也可以構(gòu)成一個頂堆钻蹬;
所以,它們之間凭需,是存在嵌套關(guān)系的问欠。
將代碼修改成while循環(huán)肝匆,針對嵌套進行操作;
部分代碼顺献,需要從while()中提取出來旗国,需要另外定義一個tempd值,如下圖所示:
將判斷大小的關(guān)鍵代碼滚澜,搬移到while()死循環(huán)中粗仓,針對頂堆的嵌套,進行操作设捐;
完成一次max的選擇后,再重新對tempd賦值塘淑,再進入while()循環(huán)萝招,如下圖所示:
針對tempd操作,如果max=tempd存捺,說明是子頂堆中的最大值槐沼;
這時,跳出判斷大小的while()函數(shù)即可捌治,如下圖所示:
完成一次for循環(huán)后岗钩,就可以完成一次大頂堆的嵌套排序;
將該duiSort()函數(shù)肖油,設(shè)置為兼吓,公有靜態(tài)函數(shù),如下圖所示:
在主函數(shù)中森枪,調(diào)用該方法视搏,完成大頂堆的排序,如下圖所示:
遍歷輸出县袱,大頂堆排序后的data數(shù)組浑娜,如下圖所示:
保存修改,按F5式散,運行程序筋遭,如下圖所示:
大頂堆的代碼實現(xiàn),測試成功暴拄。