堆排序-乡巴老都能懂

来源:互联网 发布:淘宝客推广的入口 编辑:程序博客网 时间:2024/06/04 20:14

堆排序-乡巴老都能懂

什么是堆排序?

堆排序是由 :大顶堆或者小顶堆  堆调整    堆排序  这三个部分组成;
本文介绍的思路顺序是:创建对调整函数     创建大顶堆      然后堆排序;

什么是大顶堆?

大顶堆   一个树根 下分两个树杈    ;就像一棵树 就是大顶堆,
树根(根节点)什么居然问我树根? 没有树根 你树杈怎么长出来的,没有树杈怎么长叶子?
树杈(叶节点)  ?   有些人想起了去掏鸟蛋,我们的树有些特别 比较好爬,不会划伤你, 
因为什么呢? 树杈就是树根的分支 ,树根就2个树杈,一个树杈下就两个小树杈,你想要多大 它就分多少
我家树没有树杈?我晕,你没有树杈 就一个树根 你家树 估计是拴牛用的, 那你就不需要这么麻烦用程序来计算了,就一个怎么排序啊
跟我大顶堆有什么关系?因为大顶堆就是将数据以树的机构摆放起来,
怎么将数据已树的结构摆放起来啊? 需要堆调整啊?来了,请看下面。后续的代码都会注释 呈上

什么树堆调整 ?

已数组为例,将数组  摆放成树的结构
 int n =9; 多少个数组元素 int  index  从哪个元素开始分配孩子
 int Lchlid = index *2 + 1;//左孩子   孩子分配方法,
    int Rchlid = index *2 + 2 ;//右孩子
到底怎么摆放  ?   
1.首先你需要直到摆放多少个的数据(数组元素个数)
2.分配你的孩子,就像上面的左孩子右孩子 
3. 我分配多少个不能一辈子总是分配吧,  我说过一个树结构至少要有两个树杈左孩子的下标>n 超出右孩子右孩子也不
    会存在,  所以要找到他们的条件  (调整的条件)(终止的条件3)
// 1 2 3 4 5 6 7 8 9

//根   左   右
//1     3   4我们将1作为根,计算后它的L孩子是3,R孩子是4 (调整的条件1)
//2     5   6
//3     7   8
//4     9   情况2:下标4分配孩子 有左孩子 ,右孩子不符合条件了( 调整的条件2)
//5    (11  12) return情况1:下标5的孩子是 左11 右12 而数组个数是9,超出9就下标越界了,这种情况是我们(终止的条件)
情况1 左孩子(L)> n return 左孩子不存在,右孩子自然也没有 我们就不调整了,返回
情况2 左孩子(L)< n && 右孩子> n 了 只有左孩子
情况3 左孩子(L)< n && 右孩子 < n 左右孩子都存在 我们就开始调整
堆调整:
将数值大的放到根节点上
if 左孩子>nreturn;
       if 根<左孩子 交换
else 左孩子<右孩子交换
递归 将左孩子 作为下次的根节点参数传入 将它后面的分支调整
递归 将右孩子 作为下次的根节点参数传入 将它后面的分支调整
至此堆调整函数完毕 作用:(调整一个根和孩子) 这个堆调整怎么用呢? 往下看
创建大顶堆:
就是循环 对每一个元素进行调整,
for(i-n-1;i>=0;i--)
调用堆调整
大顶堆完毕 作用(将数组都调整完 ,并且最大值挑选出来放在第一个根上)
堆排序 :
调用 大顶堆 
一次将最大值交换给最后面,最后面不参与新的排序,
N-1  直到 循环到下标1 停止循环
堆排序完毕作用(堆调整完的值放到最后,最后不参与调整,排序完成)
代码实例:
#include <stdio.h>#include <stdlib.h>#include <time.h>//堆调整:  大顶堆,//参数:arr 数组,n 数组元素个数,index是需要调整的下标//void adjust(int arr[], int n,int index){    int Lchlid = index *2 + 1;//左孩子    int Rchlid = index *2 + 2 ;//右孩子    int tmp ; //交换// 1 2 3 4 5 6 7 8 9 10//根   左   右//1     3   4//2     5   6//3     7   8//4     9   10//5    (11  12) return//如何判断有没有孩子      //方法:通过判断下标是不是在数组个数的范围内    //举例:下标5的孩子是 左11 右12 而数组个数是10,超出10就不存在孩子      //判断右孩子是否存在:        //1.右孩子的下标>左孩子   2.左孩子存在并且 右孩子下标不能超出元素个数n        //Rchlid >= n  就说明越界了,就不存在//没有左孩子,右孩子也不会存在,就不调整(不成立的条件返回)    if(Lchlid >= n)        return;    //有左孩子的情况下 则进入下面的判断    //在以上条件下,        //1.右孩子不存在  或者 2.左孩子的值比右孩子大值    if(Rchlid >= n || arr[Lchlid] >arr[Rchlid])    {//比较根节点和左孩子的值:(~~有些人分不清下标和值了),        if(arr[index] < arr[Lchlid])//根节点小于左孩子节点         {            tmp = arr[index];            arr[index] = arr[Lchlid];            arr[Lchlid] = tmp ;            //对调整后的左孩子节点继续进行堆调整                //如果左孩子<n 就一直对左孩子的左孩子进行调整,直到条件终止,即>n            adjust(arr , n, Lchlid);        }        return ;    }   //有左孩子也有右孩子 比较左右孩子调整            //思路:将值大的放在 左孩子身上            //递归调用 判断右孩子的孩子    else //有右孩子  并且 右孩子比左孩子大    {        //比较根节点和右孩子,        if(arr[index] < arr[Rchlid])//根节点小于右孩子节点        {            tmp = arr[index];            arr[index] = arr[Rchlid];            arr[Rchlid] = tmp ;            //对调整后的右孩子节点继续进行堆调整            adjust(arr , n, Rchlid);        }          return ;    }}//2.创建一个大顶堆void createHeap (int arr[] , int n){    int i;    //从后到前 对每一个元素进行调整    for (i = n-1; i>=0; i--)    {//比如 i= n=10   没有孩子        //  i= 9 没有孩子 i= 8 没有孩子        // i = 4 左 9 右10 开始调整孩子        adjust(arr,n,i);    }}//3.堆排序void heapSort (int arr[] ,int n){    int tmp;    //创建大顶堆    createHeap(arr,n);  //最大值在下标0,将下标0和 最后下标n-1交换  最大的放到最后了    //    do    {        //堆顶节点和最后节点交换        tmp = arr[0];        arr[0] = arr[n - 1];        arr[n-1] = tmp;        n--;        //对堆顶节点进行调整        adjust( arr , n , 0);       //将最大值又放到了最上面,下标0,直到n=1最后一次循环    }while(n>1);}//打印数组void PrintArray(int arr[] , int n){    int i;    for (i = 0 ;i<n; i++)        printf("%d ",arr[i]);    printf("\n*****************************\n");}int main(){    int arr[10];    int i;    srand((unsigned)time(NULL));    for(i = 0 ; i < 10; i++)        arr[i]= rand() % 100;    PrintArray(arr, 10);    heapSort(arr,10);    PrintArray(arr,10);    return 0;}




原创粉丝点击