堆排序算法(排升序)分析研究

本文深入解析了堆排序的原理,包括大顶堆和小顶堆的概念,向下调整算法的实现,以及堆排序的时间复杂度。通过实例展示了堆排序如何优化直接选择排序,提高排序效率。
摘要由CSDN通过智能技术生成


前言

堆排序(Heap Sort)就是对直接选择排序的一种改进。此话怎讲呢?直接选择排序在待排序的n个数中进行n-1次比较选出最大或者最小的,但是在选出最大或者最小的数后,并没有对原来的序列进行改变,这使得下一次选数时还需要对全部数据进行比较,效率大大降低。

堆排序算法是Floyd和Williams在1964年共同发明的,同时他们发明了“堆”这种数据结构。
————————————————

一、堆排序的原理以及基础知识

1.大顶堆&&小顶堆

  • 堆是具有下列性质的完全二叉数:每个节点的值都大于或等于其左右孩子节点的值,称为大顶堆(大堆);或者每个节点的值都小于或者等于其左右孩子节点的值,称为小顶堆(小堆)
    大小顶堆如图所示:

在这里插入图片描述

2.堆的物理结构与逻辑结构

  • 堆的逻辑结构是一颗完全二叉数
  • 堆的物理结构是一个数组
  • 通过下标父子节点的关系:
    leftchild=parent2+1
    rightchild = parent
    2+2
    parent = (child-1)/2(child是左孩子或者右孩子)
  • 堆的两个特性:
    (1).结构性:用数组表示的完全二叉数
    (2).有序性:任一节点的关键字是其子树所有节点的最大值(或者最小值)
    图形:
    在这里插入图片描述

二、推排序的步骤

1.建堆

(1)向下调整算法

  • 前提: 左右子树均为大堆。
  • 操作:从根节点开始,选出左右孩子小的那一个,跟父亲比较,如果比父亲小就交换,然后再继续往下调,调到叶子节点就终止
  • 图文解释:
    在这里插入图片描述
    代码实现:(此情况只给出算法函数,具体调用到主函数中,最后会给出完整的堆排序程序代码)
void Swap(int* p1, int* p2)
{
    int tmp = *p1;
    *p1 = *p2;
    *p2 = tmp;
}
void AdjustDown(int* a, int n, int root)//向下调整算法
//时间复杂度:O(logN)
{
    int parent = root;
    int child = parent * 2 + 1;(左孩子公式)
    while (child < n)
    {
        if (a[child + 1] > a[child] && child + 1 < n) {
            ++child;
            //让child始终为左右孩子中小的那个
        }
        //小的往上浮,大的往下沉
        if (a[child] > a[parent]) {
            Swap(&a[child], &a[parent]);
            parent = child;
            child = parent * 2 + 1;
        }
        else {
            break;
        }
    }
}

(2)重复利用向下调整算法来建立大堆

  • 这里我们采用自底向上的建堆方式:该建堆方式是从倒数第二层的节点(叶子节点的上一层开始),从右向左,从下向上的向下进行调整
  • 最后一个非叶子节点的公式:(n-1-1)/2{利用此公式来计算的parent = (child-1)/2(child是左孩子或者右孩子)}
  • 代码实现:(此情况只给出算法函数,具体调用到主函数中,最后会给出完整的堆排序程序代码)
for (int i =(n-1-1)/2 ;i >= 0;--i) {
    AdjustDown(a, n, i);
}

2.排升序(以此为例子)

  • 操作:第一个数据和最后一个数据交换,把他不看做堆里面的,前n-1个数据再进行向下调整算法,选出次大的数据,再进行交换,重复以往。
  • 代码实现(此情况只给出算法函数,具体调用到主函数中,最后会给出完整的堆排序程序代码)
 int end = n - 1;
 while (end>0)
 {
     Swap(&a[0], &a[end]);
     AdjustDown(a, end, 0);
     --end;
 }

三、堆排序的时间复杂度计算

在这里插入图片描述
在这里插入图片描述
综上所述:总的时间复杂度为O(N*log(N))

总的代码实现:

#include<stdio.h>
void Print(int* a, int n) {
    for (int i = 0; i < n; i++)
    {
        printf("%d ", a[i]);
    }
    printf("\n");
}
void Swap(int* p1, int* p2)
{
    int tmp = *p1;
    *p1 = *p2;
    *p2 = tmp;
}
void AdjustDown(int* a, int n, int root)//向下调整算法,建堆
//时间复杂度:O(logN)
{
    int parent = root;
    int child = parent * 2 + 1;//(左孩子的公式)
    while (child < n)
    {
        if (a[child + 1] > a[child] && child + 1 < n) {
            ++child;
            //让child始终为左右孩子中小的那个
        }
        //小的往上浮,大的往下沉
        if (a[child] > a[parent]) {
            Swap(&a[child], &a[parent]);
            parent = child;
            child = parent * 2 + 1;
        }
        else {
            break;
        }
    }
}
void HeapSort(int* a, int n)
{
    for (int i =(n-1-1)/2 ;i >= 0;--i) {//从倒数第一个非叶子节点开始调整
        AdjustDown(a, n, i);
    }
    //排升序,要建大堆!!操作:第一个和最后一个交换,把他不看做堆里面。前n-1个数向下调整,选出次大的数,再跟倒数第二个位置交换
    int end = n - 1;
    while (end>0)
    {
        Swap(&a[0], &a[end]);
        AdjustDown(a, end, 0);
        --end;
    }
}
int main()
{
int a[] = { 3, 5, 2, 7, 8, 6, 1, 9, 4, 0 };
HeapSort(a, sizeof(a) / sizeof(int));
Print(a, sizeof(a) / sizeof(int));
}

总结

本文详细介绍了选择排序的优化算法–堆排序,大大降低了时间复杂度,提高了排序的效率。

  • 29
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值