八种排序算法(四)----- 堆排序

堆排过程:

先将待排序的数视为完全二叉树(按层次遍历顺序进行编号,从0开始)

完全二叉树的最后一个非叶子节点,也就是最后一个节点的父结点。最后一个节点的索引为数组长度len-1,那么最后一个非叶子节点的索引应该是为

(len-1)/2.也就是从索引为2的节点开始,如果其子节点的值大于其本身的值,则把他和较大子节点进行交换,即将索引2处节点和索引5处元素交换。交换后的结果如图:

建堆从最后一个非叶子节点开始即可

向前处理前一个节点,也就是处理索引为0的节点,此时9<79,9<49,因此需要交换。应该拿索引为0的节点与索引为1的节点交换,因为79>49,如图

如果某个节点和它的某个子节点交换后,该子节点又有子节点,系统还需要再次对孩子节点进行判断。如图因为1处,3处,4处中,1处的值大于3,4处的值,所以还需要交换

注:将每次堆排序得到的最大元素与当前规模数组最后一个元素交换

 

非递归实现:

//初始排序为大根堆
void hell(int *arr,int len)
{
    for(int start = len/2 -1;start>=0;start--) //每个大根堆的根
    {
        int tmp = arr[start];
        int i=0;
        for(i=2*start + 1;i<len;i=2*i+1)//其根与孩子的关系
        {
            if(i+1 < len && arr[i] < arr[i+1]) //判断是否有右孩子
                i++;
            if(arr[i] < tmp) //孩子都小于tmp
                break;
            else  if(arr[i]>tmp) // 大的数值换到根上
                arr[start] = arr[i];
            else
                ;
            start = i;//start移动到i处

        }
            arr[start] = tmp;//循环结束将tmp放到合适的根上
    }
}

void hell_adjust(int *arr,int len)
{
    hell(arr,len);
}

void hell_sort(int *arr,int len)
{
    int tmp = 0;
    hell(arr,len);
    for(int i=len-1;i>0;--i)
    {
        tmp = arr[i];
        arr[i] = arr[0];
        arr[0] = tmp;
        hell_adjust(arr,i-1);
    }
}

递归实现:

void adjust(int *arr,int len,int index)
{
    int left = 2*index + 1;
    int right = 2*index + 2;
    int maxidx = index;
    if(left < len && arr[left] > arr[maxidx])
        maxidx = left;
    if(right < len && arr[right] > arr[maxidx])
        maxidx = right;
    if(maxidx != index)
    {
        swap(arr[maxidx],arr[index]);
        adjust(arr,len,maxidx); //递归调整其它不满足堆性质的部分
    }
}

void heapdort(int arr[],int size)
{
    for(int i=size/2 - 1;i>=0;i--) // 对每一个非叶结点进行堆调整
        adjust(arr,size,i);
    for(int i=size-1;i>=1;i--)
    {
        swap(arr[0],arr[i]); //将当前最大的位置放到数组末尾
        adjust(arr,i,0); //将未完成排序的部分继续进行堆排
    }
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值