堆排序:主要是二叉堆,是一个数组,可以近似看作是一棵完全二叉树。最坏情况运行时间为 n * log (n);
主要性质:
1.对于任意一个下标index,书上写的是左子女的下标为 2 * index,右子女为 2 * index + 1;但是在实际编程中,下标是从0开始的,所以下标的变化应该为:
左子女为2 * index + 1, 右子女为 2 * index + 2;
2.最大(小)堆:对于任意一个非叶节点,它的值都大于(小于)等于它的子女节点。
下面是自己写的代码,只针对int型,并且针对最大堆,如果要对其他类型进行堆排序,那么就要重载操作符。
heap.h
#ifndef HEAP_H
#define HEAP_H
#include <iostream>
#include <vector>
class MyHeap
{
public:
MyHeap(std::vector<int>&); //用vector来建立并保存数组,
int getMax(); //返回当前的最大值(根节点,数组的第一个元素)
void heapSort(); //堆排序
void printVector(); //打印当前数组
void buildMaxHeap(int size); //用当前保存在heap对象里面的数组构造最大堆
~MyHeap();
private:
void maxHeaplify(std::vector<int>&,int index); //维护最大堆的函数
std::vector<int> array;
void swap(int&, int&); //交换两个index
std::vector<int>::size_type size; //记录未排好序的数组的长度。
};
#endif
3.上面实现堆排序的几个重要的函数:
1)maxHeaplify(),这个函数接受一个数组和一个下标,用这个下标计算它的左右子女,进而和左右子女比较,如果根节点不是
最大的话,那就不满足最大堆的性质,那么就要把根节点和子女中的最大值坐交换,并且记录下被交换子女的index,
然后再递归地调用这个函数,直到节点满足最大堆的性质为止。
2)heapSort() buildMaxHeap() 这两个函数都会调用上面的函数,但是值得注意的是:buildMaxHeap()这个函数的起始条件是
从第一个非叶节点的节点开始调用maxHeaplify(),而第一个非叶节点的下标(按照书上来说是:数组大小 / 2 并向下取整),
但是在实际编程中的非叶节点的下标为:(数组大小 / 2 - 1)。
下面是cpp文件:
#include "heap.h"
/*为什么在堆排序的时候下面这个函数只用从根节点开始:
因为排序之前我们已经让堆具有了最大堆的性质,所以交换节点之后根节点会违反最大堆的性质,而其他节点
会保持相应的最大堆的性质,没有必要再从第一个非叶节点开始调用函数。
为什么不会把最大值再次调整到堆顶:
因为我们已经把未排序的数组的大小“改变了”-通过一个成员变量,所以最大值交换之后就会固定了,不会再被交换。
*/
void MyHeap::buildMaxHeap(int size)
{
for (int i = size/2 - 1; i >= 0; --i)
{
this->maxHeaplify(this->array,i);
}
}
int MyHeap::getMax()
{
return array[0];
}
void MyHeap::heapSort() // Heap Sort;
{
std::vector<int>::size_type start = this->size - 1;
--this->size;
while(start > 0)
{
std::cout << this->size << std::endl;
this->swap(array[0],array[start]);
this->buildMaxHeap(2);
--this->size;
--start;
}
}
void MyHeap::printVector()
{
std::vector<int>::size_type size = array.size();
for(std::vector<int>::size_type i = 0; i != size; ++i)
{
std::cout << array[i] << " ";
}
std::cout << std::endl;
}
MyHeap::MyHeap(std::vector<int>& row) : array(row),size(row.size()) //construct a heap as a Max-Heap;
{
this->buildMaxHeap(array.size());
}
void MyHeap::maxHeaplify(std::vector<int>& target,int index)
{
int left = index * 2 + 1;
int right = index * 2 + 2;
int maxIndex = index;
if(left < this->size && target[index] < target[left]) //compare left child with this node,if left is bigger,then write down the max index;
{
maxIndex = left;
}
else
{
maxIndex = index;
}
if(right < this->size && target[maxIndex] < target[right]) //compare right child with max index,if right is bigger,then write down the max index;
{
maxIndex = right;
}
if(maxIndex != index) //if 'root' is max, end this function
{
this->swap(target[maxIndex],target[index]);
this->maxHeaplify(target,maxIndex);
}
}
void MyHeap::swap(int& first, int& second)
{
int current = first;
first = second;
second = current;
}
MyHeap::~MyHeap()
{
std::cout << "Destroy Heap" << std::endl;
}
最后是主函数:简单试验:
#include "heap.h"
int main()
{
int a[16] = {4,1,3,2,16,9,10,14,8,7,56,4,3,5,6,100};
std::vector<int> v(a,a+16);
MyHeap test(v);
test.printVector();
test.heapSort();
test.printVector();
return 0;
}
g++ -o heap.h heap.cpp main.cpp
经过实验,正常得到排序的结果