1. 程式人生 > >【演算法導論】堆排序實現

【演算法導論】堆排序實現

我建立了一個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(

演算法導論動態規劃之“鋼管切割”問題

        動態規劃,其實跟分治法有些相似,基本思想都是將複雜的問題分成數個簡單的子問題,然後再去解決。它們的區別在於,分治法關注的子問題不相互“重疊”,而動態規劃關注的子問題,多是相互“重疊”的。比如在快速排序中,我們將資料分成兩部分,這兩部分再分別快速排序的遞迴思想