堆排序

#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;

}



1.所谓的弄一个堆,堆的父指针为 (n+1)/2 -1

2.其次就是大堆,所谓的大堆就是父指针的值要比大于左右子指针

3.算法的开始是从子叶开始建立大堆,然后从子叶向父指针递归建立大堆。最后建立出一个大堆,

4.但是大堆并不是排序完的,获得最后的排序时,先从树顶取出最大的元素,然后最大的元素跟第n个元素(数组最后一个元素)交换,

然后再从第1个到第n-1个数重新再建立大堆,再取出最大的元素,以此类推。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值