堆排序实现及应用

堆排序实现及应用

大家好,又见面了,我是全栈君。

        堆排序(Heapsort)是指利用堆这样的数据结构所设计的一种排序算法。

堆积是一个近似全然二叉树的结构。并同一时候满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

        堆排序实现及应用

一、堆的结构

       一般都用数组来表示堆,i结点的父结点下标就为(i – 1) / 2。它的左右子结点下标分别为2 * i + 1和2 * i + 2。

如第0个结点左右子结点下标分别为1和2。

这是从0開始的结构。

二、堆的分类

        堆分为最大堆(大顶堆)和最小堆(小顶堆),顾名思义就是父节点和左右孩子节点的关系,假设父节点大于全部的子节点的堆就是大顶堆,父节点小于全部子节点的堆就是小顶堆,选择大顶堆和小顶堆决定了排序的顺序,是从大到小还是从小到大排序。

三、堆的操作

1、创建及堆的插入

在堆中插入元素,事实上是一个上浮的操作,由于插入节点是在堆的最后,这个节点可能会破坏堆,所以须要通过调节这个插入元素的位置来终于恢复堆的有序性,这个操作就是一个上浮的操作。

堆排序实现及应用

上浮代码例如以下:
//k是插入元素的位置
void swim(int a[], int k)
{
    int j;
    while(k > 0)
    {
        j = (k - 1) / 2; //是k的父节点
        if(a[j] > a[k])
        {
           swap(&a[j], &a[k]);
           k = j;
        }
        else
        {
           break;
        }
    }
}


2、删除

依照定义删除仅仅能是删除第一个节点,也就是根节点,为了方便重建堆。所以须要将最后一个节点替换到根节点。然后又一次整理堆,这时就须要下降(sink)操作,将根节点逐渐的向下交换,最后使堆达到定义的要求。
堆排序实现及应用

代码例如以下:
//n是节点总数。删除总是从根节点開始
void sink(int a[], int n, int i)
{
   int j;
   while((2 * i + 1) < n)
   {
       j = 2 * i + 1;
       if(j + 1 < n && a[j] > a[j+1]) j++;
       if(a[j] < a[i])
       {
           swap(&a[i], &a[j]);
           i = j;
       }
       else
       {
           break;
       }
   }
}

3、建堆

怎样将一个普通的数组建成一个堆呢,那就须要对当前堆中的非叶子节点进行sink操作。最后达到堆的要求
堆排序实现及应用

代码例如以下:
void build_heap(int a[], int n)
{
   int i;
   for(i = (n/2 -1); i >= 0; i--)
   {
       sink(a, n, i);
   }
}

四、堆排序

回到正题。堆排序事实上就是不断的交换根节点和最后节点的过程。不断的缩小未排序集合的过程,这当中使用的就是sink操作
void heap_sort(int a[], int n)
{
   int i;
   for(i = n - 1; i > 0; i--)
   {
      swap(&a[i], &a[0]);
      sink(a, i, 0);
   }
}

最后将总体做了一个測试,代码例如以下:

#include <stdio.h>void swap(int *a, int *b){    int tmp = *a;    *a = *b;    *b = tmp;}//k是插入元素的位置void swim(int a[], int k){    int j;    while(k > 0)    {        j = (k - 1) / 2; //是k的父节点        if(a[j] > a[k])        {           swap(&a[j], &a[k]);           k = j;        }        else        {           break;        }    }}//n是节点总数。删除总是从根节点開始void sink(int a[], int n, int i){   int j;   while((2 * i + 1) < n)   {       j = 2 * i + 1;       if(j + 1 < n && a[j] > a[j+1]) j++;       if(a[j] < a[i])       {           swap(&a[i], &a[j]);           i = j;       }       else       {           break;       }   }}void build_heap(int a[], int n){   int i;   for(i = (n/2 -1); i >= 0; i--)   {       sink(a, n, i);   }}void heap_sort(int a[], int n){   int i;   for(i = n - 1; i > 0; i--)   {      swap(&a[i], &a[0]);      sink(a, i, 0);   }}int main(){    int a[4] = {10, 40, 30, 5};    swim(a, 3);    int i;    for(i = 0; i < 4; i++){       printf("%d\t", a[i]);    }    printf("\n");    int b[4] = {50, 10, 20, 40};    sink(b, 4, 0);    for(i = 0; i < 4; i++){       printf("%d\t", b[i]);    }    printf("\n");    int c[10] = {9, 12, 17, 30, 50, 20, 60 , 65, 4, 19};    build_heap(c, 10);    for(i = 0; i < 10; i++){       printf("%d\t", c[i]);    }    printf("\n");    heap_sort(c, 10);    for(i = 0; i < 10; i++){       printf("%d\t", c[i]);    }    printf("\n");}


堆排序实现及应用

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/115277.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • oracle中更改表名语句,转:取Oracle 表名 字段名 注释等实用语句

    oracle中更改表名语句,转:取Oracle 表名 字段名 注释等实用语句1、查找表的所有索引(包括索引名,类型,构成列):selectt.*,i.index_typefromuser_ind_columnst,user_indexesiwheret.index_name=i.index_nameandt.table_name=i.table_nameandt.table_name=要查询的表2、查找表的主键(包括名称,构成列):select…

    2022年5月17日
    43
  • java把集合转为数组_java根据下标删除数组元素

    java把集合转为数组_java根据下标删除数组元素Arrays.asList()方法返回的是一个Arrays的内部类ArrayList,而不是java.util.ArrayList.内部类中没有重写add()方法. 解决办法是重新创建一个集合,把旧的传递进去

    2022年8月23日
    10
  • android deeplink流程,Android Deeplink探究[通俗易懂]

    android deeplink流程,Android Deeplink探究[通俗易懂]移动端深度链接,简称deeplink。这是一种通过uri链接到app特定位置的一种跳转技术,不单是简单地通过网页、app等打开目标app,还能达到利用传递标识跳转至不同页面的效果。参考CreateDeepLinkstoAppContent场景在推广、广告、应用间跳转的场景下,使用极多。这里将根据以下要点来介绍deeplink。intentintent-filterscheme原理介绍in…

    2022年6月29日
    139
  • 一文解读光纤收发器单模和多模的区别![通俗易懂]

    一文解读光纤收发器单模和多模的区别![通俗易懂]光纤收发器是进行光电信号转换的设备,现在光纤收发器的技术越发成熟,应用也越来越广泛,所以我们在选择或者采购光纤收发器时,对光纤收发器做一定的了解是有好处的,接下来我们就来给大家详细介绍一下光纤收发器的单模和多模的区别?一起来看看吧!光纤收发器有单模和多模之分,其最根本的区别就是传输距离远近。单模光纤收发器的工作模式是单节点、一个端口信号传输,所以信号传输距离比较长,组成跨城域局域网的建设;多模光纤收发器就刚好相反,其工作模式是多节点、多端口信号传输,所以信号传输距离比较短,但是价格低、使用方便,多用

    2022年10月21日
    3
  • 腾讯云ssl证书_腾讯云认证证书

    腾讯云ssl证书_腾讯云认证证书如今在网站使用https已经是非常普遍的事情,对于站长来说,https证书似乎已经成为了必备,今天我们为大家介绍申请腾讯云https证书的方法与过程首先打开腾讯云的管理控制台,进入证书管理页面,我们可以看到这里有一个叫做申请证书的按钮,点击它腾讯云会让你选择证书的类型,因为我们要申请免费的,选择左边的亚洲诚信免费版DVSSL证书即可,右边的为收费证书填入自己的域名以及申请邮箱,注意域名的格式为你需…

    2025年10月11日
    3
  • dex字符串解密_DEX文件混淆加密

    dex字符串解密_DEX文件混淆加密现在部分app出于安全性(比如加密算法)或者用户体验(热补丁修复bug)会考虑将部分模块采用热加载的形式Load。所以针对这部分的dex进行加密是有必要的,如果dex是修复的加密算法,你总不想被人一下就反编译出来吧。当然也可以直接用一个加密算法对dex进行加密,Load前进行解密就可以了,但是最好的加密就是让人分不清你是否加密了。一般逆向过程中拿到一个可以直接反编译成java…

    2022年6月27日
    197

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号