堆排序的基本思想:如果把待排序的数据元素集合构成一个完全二叉树结构,则每次选择出一个最大(或最小)的数据元素只需比较完全二叉树的数值为高度的次数,即log2n次,时间复杂度就是O(nlog2n)
堆的两个性质:
(1)最大堆的根节点是堆中值最大的数据元素,最小堆的根节点是堆中值最小的数据元素,称堆的根节点元素为堆顶元素。
(2)对于最大堆,从根节点到每个叶节点的路径上,数据元素组成的序列都是递减有序的;对于最小堆,从根节点到每个叶结点的路径上,数据元素组成的序列都是递增有序的。
实例
假设要排序一个数组
一:将数组看成完全二叉树,将其最大堆化(也可以最小堆)
二:堆排序算法基本思想
(1)把堆顶a[0]元素(最大元素)与最后一个元素交换
(2)最大堆元素个数少一
(3)若此时根节点不满足最大根定义,则调整根节点使他满足最大堆的定义
个人领悟
实现过程中最最重要的思路就是要把数组当成是一个二叉树来处理
自己代码
实现如下(个人代码实现还有一些漏洞,比如说,我是用-1表示的结点无效,但是堆排序的思想都实现了)
#include <iostream>
using namespace std;
void heapTrans(int a[], int size, int length)//传变成最大根堆
{
int tmp;
for (int i = size; i >= 0; --i)
{//3 2 1 0
int left = -1;
int right = -1;
if (2 * i + 1 < length)
{
left = a[2 * i + 1];
}
if (2 * i + 2 < length)
{
right = a[2 * i + 2];
}
if (right == -1 && left == -1)
{
continue;
}
else if (right == -1 && left != -1)
{
if (a[i] < left)
{
tmp = a[i];
a[i] = a[2 * i + 1];
a[2 * i + 1] = tmp;
}
continue;
}
else if(right != -1 && left == -1)
{
tmp = a[i];
a[i] = a[2 * i + 2];
a[2 * i + 2] = tmp;
continue;
}
if (left > right)
{
if (a[i] < left)
{
tmp = a[i];
a[i] = a[2 * i + 1];
a[2 * i + 1] = tmp;
}
}
else
{
if (a[i] < right)
{
tmp = a[i];
a[i] = a[2 * i + 2];
a[2 * i + 2] = tmp;
}
}
}
}
void heapSort(int a[],int size, int length)//堆排序
{
int tmp;
tmp = a[0];
a[0] = a[length - 1];
a[length - 1] = tmp;
length--;
if (length == 0)
{
return;
}
heapTrans(a, (length - 1) / 2, length);
heapSort(a, (length - 1) / 2, length);
}
int main()
{
int size = 8;
int a[8] = { 10,50,32,5,76,9,40,88 };
for (int i = 0; i < 8; ++i)
{
cout << a[i] << " ";
}
cout << endl;
heapTrans(a, 3, 8);
for (int i = 0; i < 8; ++i)
{
cout << a[i] << " ";
}
cout << endl;
heapSort(a, 3, 8);
for (int i = 0; i < 8; ++i)
{
cout << a[i] << " ";
}
cout << endl;
return 0;
}
书上代码
#include <iostream>
using namespace std;
void CreatHeap(int a[], int n, int h)
{
int i;
int j;
int flag;
int temp;
i = h;
j = 2 * i + 1;//i为要创建的二叉树根结点下标
temp = a[i];//j为i的左孩子结点的下标
flag = 0;
//沿左右孩子中值较大者重复向下筛选
while (j < n&&flag != 1)
{
if (j < n - 1 && a[j] < a[j + 1])
{
j++;
}
if (temp > a[j])
{
flag = 1;//标记结束
}
else
{
a[i] = a[j];
i = j;
j = 2 * i + 1;
}
}
a[i] = temp;
}
void InitCreatHeap(int a[], int n)
{
int i;
for (i = (n - 1) / 2; i >= 0; i--)
{
CreatHeap(a, n, i);
}
}
void HeapSort(int a[], int n)
{
int i;
int temp;
InitCreatHeap(a, n);
for (i = n - 1; i > 0; --i)
{
temp = a[0];
a[0] = a[i];
a[i] = temp;
CreatHeap(a, i, 0);
}
}
int main()
{
int size = 8;
int a[8] = { 10,50,32,5,76,9,40,88 };
HeapSort(a, 8);
for (int i = 0; i < 8; ++i)
{
cout << a[i] << " ";
}
cout << endl;
return 0;
}
代码分析:
书上将实现了三个函数:
(1)化最大根堆
(2)初始化最大根堆
(3)进行堆排序
我的代码:
(1)化最大根堆
(2)排序
很明显的发现书上代码更加简洁,更加容易理解,比较的原因是要去学习书上规范代码的编写思路,让自己能以一个更加清晰的角度去看待问题。