标签:
一个数组可以看成是一棵树。(数组下标0 是根节点 2i+1是节点的左孩子 2i+2是右孩子 )
这棵树的父亲节点 大于 左右孩子节点 ,称之为大顶堆。
这棵树的父亲节点 小于 左右孩子节点 ,称之为小顶堆。
堆排序 (以大顶堆 为例) 主要分为两个 部分
1>调整节点
void Adjust(int arr[],int nLen,int Index) { int MaxIndex; //判断要调整的节点 有几个孩子 if(2*Index+1<= nLen-1) { //这个 判断进来 证明至少有一个 孩子 记住孩子里面数最大的 if(2*Index+2<= nLen-1) { //有左 右两个 孩子 if( arr[2*Index+2] >arr[2*Index+1] ) MaxIndex=2*Index+2; else MaxIndex=2*Index+1; } else { //只有一个左 孩子 MaxIndex=2*Index+1; } } else { //没有左孩子 不用调整了 return ; } //将孩子里面最大的数和父亲节点的数进行比较 if(arr[MaxIndex]> arr[Index]) { //如果大于父亲节点 就进行交换 arr[MaxIndex]=arr[MaxIndex]^arr[Index]; arr[Index]=arr[MaxIndex]^arr[Index]; arr[MaxIndex]=arr[MaxIndex]^arr[Index]; //交换完成 要 调整 交换过的节点 Adjust(arr, nLen,MaxIndex ); } }
2>将无序的数组变成 大顶堆
void CreateHeap(int arr[],int nLen) { //参数检查 if(arr==NULL || nLen<=0) return ; //创建 大顶堆 //从最后一个父亲节点开始创建 for(int i=nLen/2-1;i>=0;i++) { Adjust(arr,nLen,Index); } //循环 将 大顶堆的 第一个元素和 最后一个元素进行交换 for(int i=nLen-1;i>0;i--) { arr[0]=arr[0]^arr[i]; arr[i]=arr[0]^arr[i]; arr[0]=arr[0]^arr[i]; //对改动的节点 重新调整 Adjust(arr,i,0); } }
要点:
1>每次调用 adjust 函数进行调整 如果调整成功 一定要将有改变过的 孩子节点 继续调用adjust 调整
2>adjust 函数里面要做好 对有无 孩子 有几个孩子的判断
后记:
堆排序是一种选择排序.
时间复杂度是O(nlog2n)
//1 从最后一个 根节点开始调用循环节点调整函数直到根节点
//2 将这个堆的顶和最后一个元素 替换
//3 因为改变了 头 所以把头得索引当参数 传进 循环节点 调整函数 数组长度--
//4 循环2,3步骤
重点在 节点调整函数 上面
这个函数 只处理三个节点的 关系
1>根节点
2>根的左孩子
3>根的右孩子
所以 一进到这个函数里 处理逻辑是
1>有左孩子么 没有 return;
2>有右孩子么
没有 让 左孩子成为最大索引
有 找左右孩子的最大值索引
3>用最大值 跟根比较
比根大 就交换
4>看发生过交换么
发生过交换 要将被 改变过的孩子索引当参数递归调用此函数
标签:
原文地址:http://www.cnblogs.com/ming-rui/p/5330396.html