Java实现堆排序(大根堆)的示例代码

堆排序是一种树形选择排序方法,它的特点是:在排序的过程中,将array[0,...,n-1]看成是一颗完全二叉树的顺序存储结构,利用完全二叉树中双亲节点和孩子结点之间的内在关系,在当前无序区中选择关键字最大(最小)的元素。

1. 若array[0,...,n-1]表示一颗完全二叉树的顺序存储模式,则双亲节点指针和孩子结点指针之间的内在关系如下:

任意一节点指针 i:父节点:i==0 ? null : (i-1)/2

        左孩子:2*i + 1

        右孩子:2*i + 2

2. 堆的定义:n个关键字序列array[0,...,n-1],当且仅当满足下列要求:(0 <= i <= (n-1)/2)

      ① array[i] <= array[2*i + 1] 且 array[i] <= array[2*i + 2]; 称为小根堆;

      ② array[i] >= array[2*i + 1] 且 array[i] >= array[2*i + 2]; 称为大根堆;

3. 建立大根堆:

n个节点的完全二叉树array[0,...,n-1],最后一个节点n-1是第(n-1-1)/2个节点的孩子。对第(n-1-1)/2个节点为根的子树调整,使该子树称为堆。

对于大根堆,调整方法为:若【根节点的关键字】小于【左右子女中关键字较大者】,则交换。

之后向前依次对各节点((n-2)/2 - 1)~ 0为根的子树进行调整,看该节点值是否大于其左右子节点的值,若不是,将左右子节点中较大值与之交换,交换后可能会破坏下一级堆,于是继续采用上述方法构建下一级的堆,直到以该节点为根的子树构成堆为止。

反复利用上述调整堆的方法建堆,直到根节点。

4.堆排序:(大根堆)

  ①将存放在array[0,...,n-1]中的n个元素建成初始堆;

  ②将堆顶元素与堆底元素进行交换,则序列的最大值即已放到正确的位置;

  ③但此时堆被破坏,将堆顶元素向下调整使其继续保持大根堆的性质,再重复第②③步,直到堆中仅剩下一个元素为止。

堆排序算法的性能分析:

  空间复杂度:o(1);

  时间复杂度:建堆:o(n),每次调整o(log n),故最好、最坏、平均情况下:o(n*logn);

  稳定性:不稳定

建立大根堆的方法:

//构建大根堆:将array看成完全二叉树的顺序存储结构
  private int[] buildMaxHeap(int[] array){
    //从最后一个节点array.length-1的父节点(array.length-1-1)/2开始,直到根节点0,反复调整堆
    for(int i=(array.length-2)/2;i>=0;i--){
      adjustDownToUp(array, i,array.length);
    }
    return array;
  }

  //将元素array[k]自下往上逐步调整树形结构
  private void adjustDownToUp(int[] array,int k,int length){
    int temp = array[k];
    for(int i=2*k+1; i<length-1; i=2*i+1){  //i为初始化为节点k的左孩子,沿节点较大的子节点向下调整
      if(i<length && array[i]<array[i+1]){ //取节点较大的子节点的下标
        i++;  //如果节点的右孩子>左孩子,则取右孩子节点的下标
      }
      if(temp>=array[i]){ //根节点 >=左右子女中关键字较大者,调整结束
        break;
      }else{  //根节点 <左右子女中关键字较大者
        array[k] = array[i]; //将左右子结点中较大值array[i]调整到双亲节点上
        k = i; //【关键】修改k值,以便继续向下调整
      }
    }
    array[k] = temp; //被调整的结点的值放人最终位置
  }

堆排序:

//堆排序
  public int[] heapSort(int[] array){
    array = buildMaxHeap(array); //初始建堆,array[0]为第一趟值最大的元素
    for(int i=array.length-1;i>1;i--){
      int temp = array[0]; //将堆顶元素和堆低元素交换,即得到当前最大元素正确的排序位置
      array[0] = array[i];
      array[i] = temp;
      adjustDownToUp(array, 0,i); //整理,将剩余的元素整理成堆
    }
    return array;
  }

删除堆顶元素(即序列中的最大值):先将堆的最后一个元素与堆顶元素交换,由于此时堆的性质被破坏,需对此时的根节点进行向下调整操作。

//删除堆顶元素操作
  public int[] deleteMax(int[] array){
    //将堆的最后一个元素与堆顶元素交换,堆底元素值设为-99999
    array[0] = array[array.length-1];
    array[array.length-1] = -99999;
    //对此时的根节点进行向下调整
    adjustDownToUp(array, 0, array.length);
    return array;
  }

对堆的插入操作:先将新节点放在堆的末端,再对这个新节点执行向上调整操作。

假设数组的最后一个元素array[array.length-1]为空,新插入的结点初始时放置在此处。

//插入操作:向大根堆array中插入数据data
  public int[] insertData(int[] array, int data){
    array[array.length-1] = data; //将新节点放在堆的末端
    int k = array.length-1; //需要调整的节点
    int parent = (k-1)/2;  //双亲节点
    while(parent >=0 && data>array[parent]){
      array[k] = array[parent]; //双亲节点下调
      k = parent;
      if(parent != 0){
        parent = (parent-1)/2; //继续向上比较
      }else{ //根节点已调整完毕,跳出循环
        break;
      }
    }
    array[k] = data; //将插入的结点放到正确的位置
    return array;
  }

测试:

public void toString(int[] array){
    for(int i:array){
      System.out.print(i+" ");
    }
  }

  public static void main(String args[]){
    HeapSort hs = new HeapSort();
    int[] array = {87,45,78,32,17,65,53,9,122};
    System.out.print("构建大根堆:");
    hs.toString(hs.buildMaxHeap(array));
    System.out.print("\n"+"删除堆顶元素:");
    hs.toString(hs.deleteMax(array));
    System.out.print("\n"+"插入元素63:");
    hs.toString(hs.insertData(array, 63));
    System.out.print("\n"+"大根堆排序:");
    hs.toString(hs.heapSort(array));
  }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Java 堆排序实例(大顶堆、小顶堆)

    堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法.堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点. 堆排序的平均时间复杂度为Ο(nlogn) . 算法步骤: 1. 创建一个堆H[0..n-1] 2. 把堆首(最大值)和堆尾互换 3. 把堆的尺寸缩小1,并调用shift_down(0),目的是把新的数组顶端数据调整到相应位置 4. 重复步骤2,直到堆的尺寸为1 堆: 堆实际上是一棵完全二叉树,其任何一非叶节点满足性质:

  • Java实现基本排序算法的示例代码

    目录 1. 概述 2. 插入排序 2.1 直接插入排序 2.2 希尔排序(缩小增量排序) 3. 选择排序 3.1 直接选择排序 3.2 堆排序 4. 交换排序 4.1 冒泡排序 4.2 快速排序 5. 归并排序 6. 计数排序(非比较类型的排序) 7. 排序算法总结 1. 概述 排序概念:就是将一串记录按照其中某个或某些关键字的大小,递增或递减的排列起来的操作. 稳定性:通俗的将就是数据元素不发生有间隔的交换,例如: 内部排序:数据元素全部放在内存中的排序 外部排序:数据元素太多不能一次加载到内

  • C++实现二叉树及堆的示例代码

    1 树 树是一种非线性数据结构,它是由n个有限结点组成的具有层次关系的集合.把它叫树是因为它是根朝上,叶子朝下的 来上图瞧瞧 1.1 树的相关名词 2 二叉树 2.1 二叉树的概念 一颗二叉树是结点的一个有限集合,该集合或者为空,或者是由一个根结点加上两棵分别称为左子树和右子树. 如图所示: 二叉树有以下特点: 1.每个二叉树最多有两颗子树,所以二叉树不存在度为2的结点. 2.二叉树的子树有左右之分,其子树的顺序不能颠倒. 2.2 二叉树的性质 1.若规定根结点的层数为第一层,则一颗非空二叉树的

  • Java多线程编程实现socket通信示例代码

    流传于网络上有关Java多线程通信的编程实例有很多,这一篇还算比较不错,代码可用.下面看看具体内容. TCP是Tranfer Control Protocol的 简称,是一种面向连接的保证可靠传输的协议.通过TCP协议传输,得到的是一个顺序的无差错的数据流.发送方和接收方的成对的两个socket之间必须建 立连接,以便在TCP协议的基础上进行通信,当一个socket(通常都是server socket)等待建立连接时,另一个socket可以要求进行连接,一旦这两个socket连接起来,它们就可以

  • java导出json格式文件的示例代码

    本文介绍了java导出json格式文件的示例代码,分享给大家,具体如下: 生成json文件代码: import java.io.File; import java.io.FileWriter; import java.io.Writer; public class CreateFileUtil { /** * 生成.json格式文件 */ public static boolean createJsonFile(String jsonString, String filePath, String

  • Java异常退出条件的判断示例代码

    无论是功能性代码还是算法性代码,程序都是一系列流程的合集 既然是流程就分为:一般流程和异常流程: 一般流程保证了基本功能: 异常流程则是对程序稳定性的保证,不能因为一些非法输入,项目就挂了: 注意,布尔表达式的先后顺序,有时不可以交换 if (null == instance || instance.isEmpty()) 0. 常见异常退出条件 参数为空: 表示长度,表示索引的整型为负数,或者超出待索引数组或容器的范围: 1. String 的 startsWith 函数 首先来看 String

  • java poi导出图片到excel示例代码

    本文实例为大家分享了java使用poi导出图片到Excel的具体代码,供大家参考,具体内容如下 代码实现 Controller /** * 导出志愿者/人才数据 * @param talent_type * @return */ @RequestMapping("/exportData") public void exportData(Integer talent_type, HttpServletResponse response) { String fileId = UUID.ra

  • Java 8 Lambda 表达式比较器使用示例代码

    引言 在这个例子中,我们将向您展示如何使用 java8 lambda 表达式编写一个 Comparator 来对 List 进行排序. 经典的比较器示例: Comparator<Developer> byName = new Comparator<Developer>() { @Override public int compare(Developer o1, Developer o2) { return o1.getName().compareTo(o2.getName());

  • Java 使用 FFmpeg 处理视频文件示例代码详解

    目前在公司做一个小东西,里面用到了 FFmpeg 简单处理音视频,感觉功能特别强大,在做之前我写了一个小例子,现在记录一下分享给大家,希望大家遇到这个问题知道解决方案. FFmpeg是一套可以用来记录.转换数字音频.视频,并能将其转化为流的开源计算机程序.采用LGPL或GPL许可证.它提供了录制.转换以及流化音视频的完整解决方案.它包含了非常先进的音频/视频编解码库libavcodec,为了保证高可移植性和编解码质量,libavcodec里很多code都是从头开发的. FFmpeg在Linux平

  • java IP地址网段计算的示例代码

    根据IP地址与字段掩码计算网段最大最小IP package c04; import java.net.UnknownHostException; public class IPNetworkSegmentCalculation { public static void main(String[] args) throws UnknownHostException { String ip = "192.168.126.2"; String mask = "255.255.255

  • 使用Java对Hbase操作总结及示例代码

    前面已经给大家讲解过如何使用Hbase建表,以及基本的操作和一些常用shell命令,今天就给大家介绍下如何使用java对Hbase进行各种操作. 没印象的话可以再去浏览下: Hbase入门教程,shell命令大全讲解 Java操作Hbase主要方法: 1.Configuration 在使用Java API时,Client端需要知道HBase的配置环境,如存储地址,zookeeper等信息. 这些信息通过Configuration对象来封装,可通过如下代码构建该对象: Configuration

随机推荐