數據結構與算法之堆與堆排序

  在數據結構中,其實就是一棵完全二叉樹。我們知道內存中也有一塊叫做堆的存儲區域,但是這與數據結構中的堆是完全不同的概念。在數據結構中,堆分為大根堆小根堆,大根堆就是根結點的關鍵字大于等于任一個子節點的關鍵字,而它的左右子樹又分別都是大根堆;小根堆與大根堆恰好相反。在C++的STL中優先隊列priority_queue結構就是實現的堆結構。下來自己動手現實一個堆結構,包括heap_init,heap_insert,heap_top等操作。

1、堆的實現

  因為堆是一棵完全二叉樹,所以我們可以用順序表來實現,而且堆也只能用順序表。我們用vector。

  (1) 堆的初始化

  對堆的初始化基本思想:首先初始數組是一個雜亂無章的序列,但是如果堆中只有一個元素heap[0],那么heap[0]本身是一個堆,然后加入heap[1]調整堆;繼續加入heap[2].....直到完成所有元素的調整。

void sift_up(vector<int> &heap,int index){while((index+1)/2-1 >= 0){if(heap[(index+1)/2-1] < heap[index]){swap(&heap[(index+1)/2-1],&heap[index]);index = (index+1)/2-1;}elsebreak;}
}void heap_init(vector<int> &heap){if(heap.empty())return ;for(int i=1; i<heap.size(); i++){sift_up(heap,i);}
}

  (2) 向堆中插入元素

  把插入的元素放入堆的末尾,然后向上調整堆。

void heap_insert(vector<int> &heap,int element){heap.push_back(element);sift_up(heap,heap.size()-1);
}

  (3) 取出堆頂的元素

  取出一個元素后,用最后一個元素填補第一個元素的位置,然后向下依次調整堆。

void sift_down(vector<int> &heap,int index){while(index*2+2 < heap.size()){if(heap[index*2+1]>=heap[index*2+2] && heap[index]<heap[index*2+1]){swap(&heap[index],&heap[index*2+1]);index = index*2+1;}else if(heap[index*2+1]<heap[index*2+2] && heap[index]<heap[index*2+2]){swap(&heap[index],&heap[index*2+2]);index = index*2+2;}elsebreak;}
}
bool heap_top(vector<int> &heap,int *res){if(heap.empty())return false;*res = heap[0];heap[0] = heap[heap.size()-1];heap.erase(heap.end()-1);sift_down(heap,0);return true;
}

2、堆排序

  首先初始化堆,然后依次取出堆頂的值。這里為大根堆,所以是從大到小排序。

void heap_sort(vector<int> &vec){heap_init(vec);int len = vec.size();while(len--){int num;heap_top(vec,&num);printf("%d ",num);}
}

  堆排序的時間復雜度為O(nlog2n),從上面排序的步驟可以看出它是不穩定的排序。但是它與選擇排序,歸并排序一樣時間復雜度不隨序列的分布變化而變化。而對于插入排序和冒泡排序來說,當輸入序列有序或者基本有序時,它們的復雜度會遞減為O(n),而快速排序則會退化成O(n2)。

  所以在具體應用中,要根據輸入序列來選擇哪種排序方法,具體問題具體分析。由于堆排序特殊的排序結構和優良的性能,所以在很多時候下都可以采用堆排序。

3、堆排序的應用

  在一個n個數的序列中取其中最大的k個數(Top k問題)。

    這是一個很常見的排序算法題。

  方法一:直接對這這n個數進行排序,然后取k個數。時間復雜度最少為O(nlog2n)。

  方法二:借鑒快排的思路,并不需要完整地實現快排,只需要實現快排的一部分即可得到最大的k個數。復雜度為O(nlog2k)。

  方法三:可以采用哈希排序,先把n中開始的k個數放入hash表中,然后依次從剩下的的n-k個數中取出一個,與hash表中的k個數比較,每次淘汰最小的那個數。時間復雜度為O((n-k)*k)。

  方法四:取出n中開始的k個數,建立一個小根堆,然后從剩下的n-k個數中,每次取出一個數插入小根堆中,然后刪除堆頂的那個元素(堆中的最小值)。時間復雜度為O(*(n-k)*lg2k)。

  不可否認,采用堆來求最大的k個數性能是最好的,但是好處還不止這么一點點!!我們試想一下,如果輸入的序列很大,也就是n值很大,以致于無法全部存放在內存中,那么這時候,方法一和方法二就不管用了,當然方法一采用歸并排序可以達到目的,但是這時候需要多少次IO??。如果選擇方法四,最多只需要(n-k)次IO,當然方法三也是如此,只是每次需要比較k次。

  完整代碼詳見:https://github.com/whc2uestc/DataStructure-Algorithm/tree/master/heap

  版權所有,歡迎轉載,轉載請注明出處。

轉載于:https://www.cnblogs.com/whc-uestc/p/4719355.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/459004.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/459004.shtml
英文地址,請注明出處:http://en.pswp.cn/news/459004.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

非法操作 login.php,閱文游戲中心 h5游戲接入wiki

閱文游戲中心《h5游戲 CP接口規范》接口要求規范游戲方接口說明&#xff1a;游戲方需按照規范提供&#xff0c;閱文進行調用閱文接口說明&#xff1a;閱文提供&#xff0c;游戲方調用參數 time 為Unix 時間戳(January 1 1970 00:00:00 GMT 起的秒數) &#xff0c;單位為秒編碼統…

串口通信與編程:串口基礎知識

*************************************************** 更多精彩&#xff0c;歡迎進入&#xff1a;http://shop115376623.taobao.com *************************************************** 串口是串行接口&#xff08;serial port&#xff09;的簡稱&#xff0c;也稱為串行通信…

jmeter上傳文件搞了一天,才搞定,沒高人幫忙效率就是低,趕緊記下來,以備后用...

jmeter上傳文件搞了一天&#xff0c;才搞定&#xff0c;沒高人幫忙效率就是低&#xff0c;趕緊記下來&#xff0c;以備后用 先用谷歌瀏覽器抓包&#xff0c;抓到的包類似這樣&#xff1a; 在jmeter里添加一個http請求&#xff0c;配置好參數&#xff0c;方法&#xff0c;端口&a…

自定義dialog

2019獨角獸企業重金招聘Python工程師標準>>> R.layout.layout_insert_dialog自定義布局 View mViewLayoutInflater.from(MainActivity.this).inflate(R.layout.layout_insert_dialog, null); AlertDialog.Builder dialognew AlertDialog.Builder (MainActivity.this…

js unescape 對應php的函數,php實現Javascript的escape和unescape函數

由于需要用到php調用js文件&#xff0c;在網上找了相關的資料&#xff0c;并改寫了相關的方法。php實現 Javascript的escape函數方法&#xff1a;function escape($str) {preg_match_all("/[/xc2-/xdf][/x80-/xbf]|[/xe0-/xef][/x80-/xbf]{2}|[/xf0-/xff][/x80-/xbf]{3}|[…

字符數組,字符串、數字轉化

<p style"margin-top: 5px; margin-bottom: 5px; padding-top: 0px; padding-bottom: 0px; line-height: 26px; word-wrap: break-word; color: rgb(102, 102, 102); font-family: 宋體, Arial; font-size: 16px;">//****************************************…

PE文件RV轉FOA及FOA轉RVA

/************************************************************************/ /* 功能:虛擬內存相對地址和文件偏移的轉換 參數&#xff1a;stRVA&#xff1a; 虛擬內存相對偏移地址 lpFileBuf: 文件起始地址 返回&#xff1a;轉換后的文件偏移地址 */ /*****************…

SurfaceView類透明背景設置

將SurfaceView背景設置為透明&#xff0c;主要添加以下幾句話就可以了&#xff1a; 在SurfaceView創建后設置一下下面的參數&#xff1a; setZOrderOnTop(true); getHolder().setFormat(PixelFormat.TRANSLUCENT); 還有在draw方法中繪制背景顏色的時候以下面的方式進行繪制就可…

oracle的env函數用法,env命令_Linux env 命令用法詳解:顯示系統中已存在的環境變量...

env命令用于顯示系統中已存在的環境變量&#xff0c;以及在定義的環境中執行指令。該命令只使用"-"作為參數選項時&#xff0c;隱藏了選項"-i"的功能。若沒有設置任何選項和參數時&#xff0c;則直接顯示當前的環境變量。如果使用env命令在新環境中執行指令…

網絡通信的工作原理

*************************************************** 更多精彩&#xff0c;歡迎進入&#xff1a;http://shop115376623.taobao.com *************************************************** 1、什么是計算機網絡&#xff1f; 計算機網絡是由兩臺或兩臺以上的計算機通過網絡設備…

Bossie Awards 2015: The best open source applicati

2019獨角獸企業重金招聘Python工程師標準>>> Read about more open source winners InfoWorlds Best of Open Source Awards for 2014 celebrate more than 100 open source projects, from the bottom of the stack to the top. Follow these links to more open s…

oracle中pga指什么,oracle學習SGA跟PGA理解

SGA&#xff1a;SystemGlobal Area是OracleInstance的基本組成部分&#xff0c;在實例啟動時分配;系統全局域SGA主要由三部分構成&#xff1a;數據庫緩沖區、日志緩沖區、共享池&#xff0c;還可能包含&#xff1a;大池&#xff0c;JAVA池&#xff0c;流池。注意點&#xff1a;…

oracle重做日志教程,Oracle教程:重做日志文件基本維護

重做日志文件最重要的用途就是用來恢復數據(其實你也可以用來logminer)&#xff0c;它記錄著system global area(sga)當中的database bu重做日志文件最重要的用途就是用來恢復數據(其實你也可以用來logminer)&#xff0c;它記錄著system global area(sga)當中的database buffer…

以太網,局域網,萬維網

*************************************************** 更多精彩&#xff0c;歡迎進入&#xff1a;http://shop115376623.taobao.com *************************************************** 以太網是一種通信協議標準 萬維網WWW 是 Internet 的多媒體信息查詢工具 以太網: 以…

java的自動類型轉換和強制類型轉換

在程序運行時&#xff0c;經常需要將一種數值類型進行轉換成另一種類型。下面給出了一個合法的轉換。數值之間的合法轉換上圖中有6個實心箭頭&#xff0c;表示無信息丟失的轉換&#xff0c;有三個虛箭頭&#xff0c;表示可能有精度丟失的轉換。例如123456789是一個大整數&#…

Class 泛型

Java Class 泛型的例子說明&#xff1a; http://blog.chinaunix.net/uid-1911213-id-3085866.html http://blog.163.com/sir_876/blog/static/1170522320121216273111/轉載于:https://www.cnblogs.com/yedu/p/4514016.html

java動態代理的實現

動態代理作為代理模式的一種擴展形式&#xff0c;廣泛應用于框架&#xff08;尤其是基于AOP的框架&#xff09;的設計與開發&#xff0c;本文將通過實例來講解Java動態代理的實現過程。友情提示&#xff1a;本文略有難度&#xff0c;讀者需具備代理模式相關基礎知識&#xff0c…

常見的網絡類型

*************************************************** 更多精彩&#xff0c;歡迎進入&#xff1a;http://shop115376623.taobao.com *************************************************** 我們經常聽到Internet網、星形網等名詞&#xff0c;它們表示什么&#xff1f;是怎樣分…

oracle放在內存里,oracle如中何把小表釘住在內存中

buffer_pool_defualtbuffer_pool_keepbuffer_pool_recycle如果要把表釘死在內存中&#xff0c;也就是把表釘在keep區。相關的命令為&#xff1a;alter table ..... storage(buffer_pool keep);這句命令把表示表如果緩存的話是緩存在keep區。可以通過語句&#xff1a;select tab…

C++基礎之this指針的詳解

*************************************************** 更多精彩&#xff0c;歡迎進入&#xff1a;http://shop115376623.taobao.com *************************************************** 關于C中的this指針&#xff0c;建議大家看看這篇文章&#xff0c;《C中的this指針》&a…