#include "stdafx.h"
#include<windows.h>
#include <math.h>
void swap(int* a, int* b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
/*
* 得到左子节点的下标
*/
int leftChildIndex(int i) {
return (i + 1) * 2 - 1;
}
/*
* 得到右子节点的下标
*/
int rightChildIndex(int i) {
return (i + 1) * 2;
}
void maxHeapIndex(int a[], int root, int maxSize) {
//得到左子节点的下标
int l = leftChildIndex(root);
//得到右子节点的下标
int r = rightChildIndex(root);
//先默认最大节点的下标值为当前根节点
int largest = root;
//如果左节点存在且左节点的值大于根节点,则标记最大值为左节点
if (l <= maxSize && a[l] > a[root]) {
largest = l;
}
//如果左节点存在且右节点的值大于根节点,则标记最大值为右节点
if (r <= maxSize && a[r] > a[largest]) {
largest = r;
}
//经过标记判断,如果发现最大值确实不是根节点,则进行交换值,且进行递归调用看看交换之后的根节点是否满足大根堆性质
if (root != largest) {
swap(a + root, a + largest);
maxHeapIndex(a, largest, maxSize);
}
}
int log2(int i) {
//ceil函数返回一个不小于某值的整数
return (int) ceil(log((double)i) / log(2.0));
}
/**
* 生成一个大根堆,思路:
* 从倒数第二层的最右边的节点开始,依次调用maxHeapIndex
*
*/
void maxHeapBuild(int a[], int len) {
//得到高度
int h = log2(len);
//得到可用的最大的下标值
int max = (int) (pow(2.0, h)) - 2;
//循环调用
for (int i = max; i >= 0; i--) {
maxHeapIndex(a, i, len - 1);
}
}
/*
* 堆排序,思路:
* 先进行一次maxHeapBuild,使得root节点为最大的值
* 然后将root节点和最后一个节点的值进行交换
* 然后将最后一个节点断开(maxsize-=1)
* 然后进行maxheapify,因为这时候根节点的左右子树依旧是大根堆,所以只需要maxheapify而不需要maxHeapBuild
* 这样从n-1开始循环到2的时候即可
*/
void maxHeapSort(int a[], int maxSize, int tmp[]) {
maxHeapBuild(a, maxSize); //n
for (int i = maxSize-1; i > 0;) { //循环n-1次
swap(a, a + i);
tmp[i] = a[i];
i--;
//j++;
//printf("%d ",tmp[i]);
if (i == 0) {
tmp[0] = a[0];
} else {
maxHeapIndex(a, 0, i); //logn 执行了n-2次
}
}
for (int i = 0; i < maxSize; i++) {
a[i] = tmp[i];
}
}
int _tmain(int argc, _TCHAR* argv[])
{
int a[] = {0,6,1,4,2,3,5};
int t[7];
maxHeapSort(a,7,t);
for (int i = 0; i < 7; i++)
{
printf("%d\n",a[i]);
}
system("PAUSE");
return 0;
#include<windows.h>
#include <math.h>
void swap(int* a, int* b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
/*
* 得到左子节点的下标
*/
int leftChildIndex(int i) {
return (i + 1) * 2 - 1;
}
/*
* 得到右子节点的下标
*/
int rightChildIndex(int i) {
return (i + 1) * 2;
}
void maxHeapIndex(int a[], int root, int maxSize) {
//得到左子节点的下标
int l = leftChildIndex(root);
//得到右子节点的下标
int r = rightChildIndex(root);
//先默认最大节点的下标值为当前根节点
int largest = root;
//如果左节点存在且左节点的值大于根节点,则标记最大值为左节点
if (l <= maxSize && a[l] > a[root]) {
largest = l;
}
//如果左节点存在且右节点的值大于根节点,则标记最大值为右节点
if (r <= maxSize && a[r] > a[largest]) {
largest = r;
}
//经过标记判断,如果发现最大值确实不是根节点,则进行交换值,且进行递归调用看看交换之后的根节点是否满足大根堆性质
if (root != largest) {
swap(a + root, a + largest);
maxHeapIndex(a, largest, maxSize);
}
}
int log2(int i) {
//ceil函数返回一个不小于某值的整数
return (int) ceil(log((double)i) / log(2.0));
}
/**
* 生成一个大根堆,思路:
* 从倒数第二层的最右边的节点开始,依次调用maxHeapIndex
*
*/
void maxHeapBuild(int a[], int len) {
//得到高度
int h = log2(len);
//得到可用的最大的下标值
int max = (int) (pow(2.0, h)) - 2;
//循环调用
for (int i = max; i >= 0; i--) {
maxHeapIndex(a, i, len - 1);
}
}
/*
* 堆排序,思路:
* 先进行一次maxHeapBuild,使得root节点为最大的值
* 然后将root节点和最后一个节点的值进行交换
* 然后将最后一个节点断开(maxsize-=1)
* 然后进行maxheapify,因为这时候根节点的左右子树依旧是大根堆,所以只需要maxheapify而不需要maxHeapBuild
* 这样从n-1开始循环到2的时候即可
*/
void maxHeapSort(int a[], int maxSize, int tmp[]) {
maxHeapBuild(a, maxSize); //n
for (int i = maxSize-1; i > 0;) { //循环n-1次
swap(a, a + i);
tmp[i] = a[i];
i--;
//j++;
//printf("%d ",tmp[i]);
if (i == 0) {
tmp[0] = a[0];
} else {
maxHeapIndex(a, 0, i); //logn 执行了n-2次
}
}
for (int i = 0; i < maxSize; i++) {
a[i] = tmp[i];
}
}
int _tmain(int argc, _TCHAR* argv[])
{
int a[] = {0,6,1,4,2,3,5};
int t[7];
maxHeapSort(a,7,t);
for (int i = 0; i < 7; i++)
{
printf("%d\n",a[i]);
}
system("PAUSE");
return 0;
}
1.所谓的弄一个堆,堆的父指针为 (n+1)/2 -1
2.其次就是大堆,所谓的大堆就是父指针的值要比大于左右子指针
3.算法的开始是从子叶开始建立大堆,然后从子叶向父指针递归建立大堆。最后建立出一个大堆,
4.但是大堆并不是排序完的,获得最后的排序时,先从树顶取出最大的元素,然后最大的元素跟第n个元素(数组最后一个元素)交换,
然后再从第1个到第n-1个数重新再建立大堆,再取出最大的元素,以此类推。