【演算法導論】堆排序實現
我建立了一個Heap的資料結構,而不是像STL那樣使用函式解決堆排序,當然STL的比較優雅一點,我只是提供第二個思路
#ifndef HEAP_SORT_H #define HEAP_SORT_H #include <vector> #include <cstddef> #include <iterator> #ifdef _DEBUG #include <iostream> #endif // _DEBUG template <typename T> struct less { bool operator() (const T& lhs, const T& rhs) { return lhs < rhs; } }; ////////////////////////////////////////////////////////////////////////// // 最大堆,用於實現堆排序 // 演算法思路: // 利用堆這種資料結構的特性,實現排序 // 在這裡的思路是Heap含有一個vec,並沒有事實能夠證明繼承比包含好用 ////////////////////////////////////////////////////////////////////////// template <typename T, typename Container = std::vector<T>, typename Compare = less<T> > class MaxHeap { public: typedef size_t pos_type; typedef size_t size_type; typedef ptrdiff_t diff_type; public: template <typename Iterator> MaxHeap(Iterator first, Iterator last) : vec(first, last), comp(Compare()) { this->build_max_heap(); #ifdef _AL_DEBUG // Show the original squence for (; first != last; ++first) { std::cout << *first << " "; } std::cout << std::endl; // Show the squence after build_max_heap() for (std::vector<T>::iterator iter = vec.begin(); iter != vec.end(); ++iter) { std::cout << *iter << " "; } std::cout << std::endl; #endif // _AL_DEBUG } virtual ~MaxHeap() { } inline size_type size() const { return (size_type) this->vec.size(); } inline size_type capacity() const { return (size_type) this->vec.capacity(); } inline const T& top() const { return this->first(); } inline bool pop() { if (size() == 0) return false; this->swap(1, size()); // delete begin in vec this->vec.pop_back(); // do max heapify this->max_heapify(_START_POS); // test the size of vec return true; } inline void push(const T& new_val) { this->vec.push_back(new_val); this->update_heapify(this->size()); } protected: Container vec; Compare comp; protected: inline pos_type parent(pos_type i) const { return i >> 1; } inline pos_type right(pos_type i) const { return (i << 1) + 1; } inline pos_type left(pos_type i) const { return i << 1; } inline bool has_left(pos_type i) const { if (left(i) > size() || left(i) < _START_POS) return false; else return true; } inline bool has_right(pos_type i) const { if (right(i) > size() || right(i) < _START_POS) return false; else return true; } inline bool has_parent(pos_type i) const { if (parent(i) < _START_POS) return false; else return true; } inline const T& value(pos_type i) const { return vec[--i]; } inline const T& first() const { return vec[0]; } inline void swap(pos_type lhs, pos_type rhs) { --lhs, --rhs; Container::iterator left = this->vec.begin() + lhs; Container::iterator right = this->vec.begin() + rhs; T tmp = *left; *left = *right; *right = tmp; } // 建堆操作,時間複雜度:O(n) void build_max_heap() { pos_type last_pos = vec.size(); #ifdef _AL_DEBUG std::cout << "Size: " << last_pos << std::endl; #endif // _AL_DEBUG if (has_parent(last_pos)) { for (pos_type p = parent(last_pos); p != 0; --p) { max_heapify(p); } } } // 保持堆性質操作,時間複雜度:O(lgn) void max_heapify(pos_type pos) { pos_type max_pos = pos; pos_type left_pos = left(pos); pos_type right_pos = right(pos); #ifdef _AL_DEBUG std::cout << "max_heapify " << pos << " " << left_pos << " " << right_pos << " "; std::cout << "max_heapify " << value(pos) << " "; #endif // _AL_DEBUG // Do exchange among this 3 nodes // and record the max one to max_pos // or the value of max_pos will not // be changed if (has_left(pos) && comp(value(max_pos), value(left_pos))) { max_pos = left_pos; #ifdef _AL_DEBUG std::cout << value(left_pos) << " "; #endif // _AL_DEBUG } if (has_right(pos) && comp(value(max_pos), value(right_pos))) { max_pos = right_pos; #ifdef _AL_DEBUG std::cout << value(right_pos); #endif // _AL_DEBUG } #ifdef _AL_DEBUG std::cout << std::endl; #endif // _AL_DEBUG if (max_pos != pos) { swap(max_pos, pos); max_heapify(max_pos); } } void update_heapify(pos_type p) { pos_type cur = p; pos_type parent_pos = parent(cur); while (has_parent(cur)) { #ifdef _AL_DEBUG // Show the squence after build_max_heap() for (std::vector<T>::iterator iter = vec.begin(); iter != vec.end(); ++iter) { std::cout << *iter << " "; } std::cout << std::endl; #endif // _AL_DEBUG if (comp(value(parent_pos), value(cur))) { swap(parent_pos, cur); cur = parent_pos; parent_pos = parent(cur); }else break; } } static const size_type _START_POS = 1; }; template <typename Iterator> void heap_sort(Iterator first, Iterator last) { _heap_sort_aux(first, last, std::_Val_type(first)); } ////////////////////////////////////////////////////////////////////////// // 因為藉助vector實現的,而不是自己利用allocator實現的,所以沒辦法控制 // heap-sort過程中將最大值放在末尾的步驟,所以只能將最大值賦給當前的指標 // 指向的位置 ////////////////////////////////////////////////////////////////////////// template <typename Iterator, typename Val> void _heap_sort_aux(Iterator first, Iterator last, Val*) { MaxHeap<Val> heap(first, last); for (; first != last && heap.size() != 0; ++first) { *first = heap.top(); heap.pop(); } } #endif
相關推薦
【演算法導論】堆排序實現
我建立了一個Heap的資料結構,而不是像STL那樣使用函式解決堆排序,當然STL的比較優雅一點,我只是提供第二個思路 #ifndef HEAP_SORT_H #define HEAP_SORT_H #include <vector> #include <
【演算法導論】歸併排序
#include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <cstring> #include <string&g
【演算法導論】插入排序法
插入排序法的時間複雜度為n的平方,對於較小的輸入規模來說,插入排序法比合並排序法更快些。在最佳情況下,即輸入陣列已經排序好,則時間複雜度可表示為n,是一個線性函式;在最差情況下,即輸入陣列是逆序排列時
【演算法導論】計數排序
計數排序假設n個輸入元素中的每一個都是介於0到k之間的整數,此處k為某個整數。 計數排序的基本思想就是對每一個輸入元素x,確定出小於x的元素個數。有了這一資訊,就可以把x直接放到它在最終輸出陣列中的位置上。例如,如果有17個元素小於x,則x就屬於第18個輸出位置。當有幾個元
堆排序(最小堆)--【演算法導論】
堆排序的思想在堆排序(最大堆)已做說明,故不再贅述; 總之,思想就是首先進行建堆,由於這是最小堆,故而必須保證父節點都小於孩子節點,若不滿足條件,則進行調節; 最後進行堆排序,不斷將最小的提取出來,並對剩下的進行調節,使之滿足最小堆; 故而將最大堆中的判斷父節點與孩子大小部
【演算法導論】6.堆排序
堆排序時間複雜度為O(nlgn), 空間複雜度為O(1). 應用:最大堆用於堆排序,最小堆用於構造優先佇列。 6.1堆 二叉堆是一個數組,可被看作一個近似的完全二叉樹。除了最底層外,該樹是完全滿的。 所以可以計算得到父結點、左孩子和右孩子的下標。 Parent(i) &nbs
【演算法導論】c++實現計數排序
計數排序的基本思想為:對每一個輸入的元素x,確定出小於x的元素的個數。有了這一資訊,那麼就可以把x直接放到相應的位置上。 特點: 1 需要臨時的儲存空間,如果排序資料範圍特別大時,空間開銷很大。 2 適合於排序0 - 100以內的資料。 3 排序的時間複雜度為O(n)。 #
【排序演算法7】堆排序
此排序演算法完全是看著MoreWindows大神的部落格一邊看一邊體會一邊跟著敲出來的,在這裡還是非常感謝他。 部落格地址https://blog.csdn.net/MoreWindows/article/details/6709644 上述地址對堆排序講的很細緻,這裡就不講了。但是不知
【演算法導論】10.1-5單陣列實現雙端佇列
演算法導論第三版P131 題目: 10.1-5 棧插入和刪除元素只能在同一端進行,佇列的插入操作和刪除操作分別在兩端進行,與它們不同的,有一種雙端佇列(deque),其插入和刪除操作都可以在兩端進行。寫出4個時間均為O(1)的過程,分別實現在雙端佇列插入和刪除元素的操作,該
【演算法導論】8.線性時間排序(計數排序,基數排序,桶排序)
三種線性時間複雜度的排序演算法:計數排序,基數排序,桶排序。 8.1排序演算法的下界 給定兩個元素ai和aj,如果使用比較排序,可以有ai<aj,ai<=aj,ai=aj,ai>aj,ai>=aj五種操作來確定其相對次序。本節假設所有的比較採用ai<=aj形
【演算法導論】7.快速排序
快速排序的平均時間複雜度為O(nlgn),最壞時間複雜度為O(n^2),最壞時間複雜度出現在待排序列完全有序的狀態,此時在使用分治法進行劃分時,兩個子序列的規模相差很大,就出現了最壞時間複雜度。快速排序由於其O(nlgn)前隱含的常數係數非常小,所以相比其它排序演算法更快。 7.1快速排序的
二叉排序樹(Binary Sort Tree,二叉查詢樹,二叉搜尋樹)--【演算法導論】
今天的收穫就是二叉搜尋樹,“好記性不如爛筆頭”,寫下來加深一下印象; 1、首先是瞭解了二叉搜尋樹(Binary Sort Tree)又稱二叉查詢樹,亦稱二叉排序樹。 若它的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值; 若它的右子樹不空,則右子樹上所有結點的值均
【演算法導論】二叉排序樹
具體程式實現如下: /**************************************\ 函式功能:在二叉排序樹中刪除節點 輸入: 二叉排序樹的根節點、要刪除的節點的內容 輸出: 二叉排序樹的根節點 \*************************************
【演算法導論】2-2 二路歸併排序(分治)merge-sort 和逆序對的問題
二路歸併排序程式碼如下。 #include <iostream> using namespace std; //二路排序演算法,書p17 正確性證明見p18-19 void merge(int *b,int p,int q,int r)
【資料結構】堆的實現
文章目錄 Heap.h Heap.c Test.c Heap.h #ifndef __HEAP_H__ #define __HEAP_H__ #include<assert.h> #include
【演算法導論】3.1~3.2
2018年10月31日 19:42:50 mahaoyuan2015 閱讀數:4 個人分類: 讀書筆記
【演算法導論】7
快速排序 程式碼: #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> int partition(int a[], int p, int r) {
【演算法導論】動態規劃切鋼條
問題:鋼條切割 給定長度為n英寸的鋼條,和一個價格表P{1....n},求切割鋼條的方案,使得收益R最大。如果鋼條價格足夠大,可以完全不用切割。 來源:演算法導論,第15章 方法:1、遞迴窮舉;2、動態規劃 思路: 遞迴窮舉:鋼條分為兩部分左邊為不切割部分範圍長度j
【演算法導論】求二叉樹的葉子數和深度
/**********************************************\ 函式功能:計算葉子節點個數 輸入: 二叉樹的根節點 輸出: 葉子節點個數 \**********************************************/ int countleaf(
【演算法導論】動態規劃之“鋼管切割”問題
動態規劃,其實跟分治法有些相似,基本思想都是將複雜的問題分成數個簡單的子問題,然後再去解決。它們的區別在於,分治法關注的子問題不相互“重疊”,而動態規劃關注的子問題,多是相互“重疊”的。比如在快速排序中,我們將資料分成兩部分,這兩部分再分別快速排序的遞迴思想