常用排序算法之——堆排序
堆与堆排序的原理,参考该博客: 白话经典算法系列之七 堆与堆排序
二叉堆是个完全二叉树,可以用一个数组来保存节点,不会浪费空间,能快速定位;本人用一个vector来代替数组,省去自己对内存的分配/重分配和释放等操作。
堆排序就是每次取出小顶堆的堆顶并输出,然后对堆重新调整。
堆排序需要对数组先建堆【时间复杂度为O(N):高度为h的层最多有n/2h+1个结点,每个结点上调的复杂度为O(h),求累加和,取极限值,求出复杂度为O(3N)】,调整的过程中会打破元素的相对顺序,是一种不稳定的排序算法。时间复杂度最好、最坏、平均都为O(N logN)。
本人实现的代码,一个小顶堆,作为笔记:
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
template<class T>
class MyHeap
{
public:
// MyHeap() //默认构造函数对vector初始化
// ~MyHeap()
void init(T nums[], int n); //用一个数组来初始化,并建好堆
int size(); //返回堆中元素个数
void add(T new_item); //添加一个元素
T top(); //返回堆顶(最小值)
void pop(); //删除堆顶,不返回
private:
inline void fixUp(int i); //堆的向上调整
inline void fixDown(int i); //堆的向下调整
vector<T> m_tv; //采用vector数据结构来保存元素
};
template<class T>
void MyHeap<T>::init(T nums[], int n)
{
m_tv.resize(n);
memcpy(&m_tv[0], nums, n * sizeof(T));
if(n < 2)
{
return;
}
for(int i = (n - 2) >> 1; i >= 0; --i) //从第一个非叶节点开始向下调整
{
fixDown(i);
}
}
template<class T>
int MyHeap<T>::size()
{
return m_tv.size();
}
template<class T>
void MyHeap<T>::add(T new_item)
{
m_tv.push_back(new_item);
fixUp(m_tv.size() - 1); //添加到数组尾部,然后向上调整
}
template<class T>
T MyHeap<T>::top()
{
if(m_tv.empty())
{
cout << "head empty" << endl;
return -1;
}
return m_tv[0]; //返回堆顶
}
template<class T>
void MyHeap<T>::pop()
{
if( m_tv.empty() )
{
return;
}
m_tv[0] = m_tv.back(); //将最后一个元素与堆顶交换,然后删除最后一个元素(变相删除第一个元素)
m_tv.pop_back();
fixDown(0); //从堆顶开始向下调整
}
template<class T>
inline void MyHeap<T>::fixUp(int i)
{
//从叶子到根节点的路径上,把叶子调整到大于它的元素之上
for(int j = (i-1) >> 1; (j >= 0) && (i != 0) && (m_tv[j] > m_tv[i]); i = j, j = (i-1) >> 1)
swap(m_tv[i], m_tv[j]);
}
template<class T>
inline void MyHeap<T>::fixDown(int i)
{
const int n = m_tv.size();
int j = 2 * i + 1;
while(j < n)
{
if(j+1 < n && m_tv[j+1] < m_tv[j]) //找出两个儿子中的较小值
{
++j;
}
if(m_tv[i] < m_tv[j]) //如果小于儿子的值,说明已经在合适的位置
{
break;
}
swap(m_tv[i], m_tv[j]); //和小儿子交换,直至找到比他大的儿子或者成为叶节点
i = j;
j = 2 * i + 1;
}
}
int main(int argc, char *argv[])
{
int ia[] = {4, 2, 1, 10, 3, 8};
double da[] = {4.13, 2.11, 1.1, 10.19, 3.12, 8.17};
MyHeap<int> ih; //int元素的堆
MyHeap<double> dh; //double元素的堆
ih.init(ia, sizeof(ia)/sizeof(*ia));
ih.add(5);
const int in = ih.size();
cout << in << endl;
for(int i = 0; i < in; ++i)
{
cout << ih.top() << ' ';
ih.pop();
}
cout << endl;
dh.init(da, sizeof(da)/sizeof(*da));
dh.add(5.14);
dh.add(7.16);
const int dn = dh.size();
cout << dn << endl;
for(int i = 0; i < dn; ++i)
{
cout << dh.top() << ' ';
dh.pop();
}
cout << endl;
return 0;
}