堆排序(JAVA)

package org.rev.algorithm;

/**
 * 堆排序,时间复杂度为O(nlogn),是利用堆的性质进行的一种选择排序。
 * 
 * 大顶堆是一个完全二叉树,所有的父节点都大于或等于它的左右子节点,即a[i]>=a[2i+1]&&a[i]>=a[2i+2]。 
 *(小顶堆是父节点<=子节点)
 * 
 * 对于完全二叉树,任意节点a[i]的父节点的索引值是(i-1) / 2 向下取整。
 * 
 * 1.对于序列a[0]-a[n-1],构建大顶堆,堆顶a[0]为最大值。
 * 
 * 2. 交换堆顶a[0]和最后一个元素a[n-1],此时,a[0]-a[n-2]是无序的,a[n-1]是有序的。
 * 
 * 3. 交换后的a[0]可能是违反大顶堆的,需要再次构建大顶堆,并交换a[0]和a[n-2]。
 *    此时a[0]-a[n-3]是无序的,a[n-2]-a[n-1]是有序的。
 * 
 * 4. 如此循环n次,i次循环后,a[n-i]-a[n-1]都是有序的,直到i=n,此时a[0]-a[n-1]已是有序数列。
 * 
 */
public class HeapSort {

  public static void main(String[] args) {
    int[] data = {39, 11, 38, 97, 86, 37, 12, 4, 51, 18};
    // 堆排序
    HeapSort hs = new HeapSort();
    hs.heapSort(data);
    System.out.println("排序之后:");
    hs.print(data);
  }

  /**
   * 堆排序
   */
  public void heapSort(int[] data) {
    for (int i = 0; i < data.length; i++) { // 循环建堆
      buildMaxHeap(data, data.length - 1 - i); // 建堆,排序结果是升序
      // buildMinHeap(data, data.length - 1 - i); // 建堆,排序结果是降序
      swap(data, 0, data.length - 1 - i); // 交换堆顶和最后一个元素
      print(data);
    }
  }

  /**
   * 对数组data[0]到data[lastIndex]构建大顶堆
   * 
   * @param data 等待构建大顶堆的数组
   * @param lastIndex 数组中最后一个元素的索引值
   */
  public void buildMaxHeap(int[] data, int lastIndex) {

    for (int i = (lastIndex - 1) / 2; i >= 0; i--) { // 从最后一个元素的父节点开始
      int k = i; // 保存当前正在判断的节点

      while (2 * k + 1 <= lastIndex) { // 若节点data[k]的左子节点存在
         // tmpIndex记录较大节点的索引值,初始值为当前节点的左子节点的索引值
        int tmpIndex = 2 * k + 1; 

        // 比较左右子节点哪个大
        // 满足此条件说明右子节点存在,否则此时tmpIndex应该等于 lastIndex
        if (tmpIndex < lastIndex) { 
          // (data[2*k+1] <data[2*k+2]),左子节点小于右子节点
          if (data[tmpIndex] < data[tmpIndex + 1]) { 
            // tmpIndex总是记录较大节点的索引值
            tmpIndex++;
          }
        }

        // 使最大值位于父节点
        if (data[k] < data[tmpIndex]) {
          swap(data, k, tmpIndex); // 交换两个元素在数组中的位置
          k = tmpIndex;
        } else {
          break;
        }

      }
    }
  }

  /**
   * 对数组data[0]到data[lastIndex]构建小顶堆
   * 
   * @param data 等待构建小顶堆的数组
   * @param lastIndex 数组中最后一个元素的索引值
   */
  public void buildMinHeap(int[] data, int lastIndex) {

    for (int i = (lastIndex - 1) / 2; i >= 0; i--) { // 从最后一个元素的父节点开始
      int k = i; // 保存当前正在判断的节点

      while (2 * k + 1 <= lastIndex) { // 若当前节点的子节点data[2k+1]存在
        // tmpIndex,记录较小节点的索引值,初始值为当前节点的左子节点的索引值
        int tmpIndex = 2 * k + 1; 

        // 比较左右子节点哪个小
        // 满足此条件说明右子节点存在,否则此时tmpIndex应该等于 lastIndex
        if (tmpIndex < lastIndex) { 
          // (data[2*k+1] >data[2*k+2]),左子节点大于右子节点
          if (data[tmpIndex] > data[tmpIndex + 1]) { 
            // tmpIndex总是记录较小节点的索引值
            tmpIndex++;
          }
        }

        // 使小值位于父节点
        if (data[k] > data[tmpIndex]) {
          swap(data, k, tmpIndex); // 交换两个元素在数组中的位置
          k = tmpIndex;
        } else {
          break;
        }

      }
    }
  }

  /**
   * 交换两个元素在数组中的位置
   * 
   * @param data
   * @param i
   * @param j
   */
  public void swap(int[] data, int i, int j) {
    if (i == j) {
      return;
    }

    /*
     * int tmp = data[i]; 
     * data[i] = data[j]; 
     * data[j] = tmp;
     * 
     * 下面三句代码和上面注释掉的三句效果一样,时间换空间的游戏。
     */
    data[i] = data[i] + data[j];
    data[j] = data[i] - data[j];
    data[i] = data[i] - data[j];

  }

  /*
   * 输出数组中的元素
   */
  private void print(int[] data) {

    for (int i = 0; i < data.length; i++) {
      System.out.print(data[i] + "\t");
    }
    System.out.println();
  }

}

堆排序方法对记录数较少的文件并不值得提倡,但对n较大的文件还是很有效的。因为其运行时间主要耗费在建初始堆和调整建新堆时进行的反复“筛选”上。

堆排序在最坏的情况下,其时间复杂度也为O(nlogn)。相对于快速排序来说,这是堆排序的最大优点。此外,堆排序仅需一个记录大小的供交换用的辅助存储空间。

参考 http://www.cnblogs.com/mengdd/archive/2012/11/30/2796845.html

时间: 2024-11-08 03:45:50

堆排序(JAVA)的相关文章

堆排序(Java实现)

<算法导论>中堆排序主要将其分为堆的性质.维护堆的性质.建堆.堆排序算法 堆的性质:给定一个结点的下标i,很容易计算得到它的父结点.左孩子和右孩子的下标(伪代码): PARENT(i) return i/2 LEFT(i) return 2i RIGHT(i) return 2i+1 这里针对下标从1开始的数组,然而实际上我们涉及的数组都是从0开始.为了改进上面的伪代码,可以使用移位来解决,其伪代码: PARENT(i) return (i-1)>>1 LEFT(i) return

堆排序JAVA实现

package kpp.sort; /** * 堆的定义如下: n个元素的序列{k0,k1,...,ki,…,k(n-1)}当且仅当满足下关系时,称之为堆. " ki<=k2i,ki<=k2i+1;或ki>=k2i,ki>=k2i+1.(i=1,2,…,[n/2])" 若将和此次序列对应的一维数组(即以一维数组作此序列的存储结构)看成是一个完全二叉树, 则完全二叉树中每一个节点的值的都大于或等于任意一个字节的值(如果有的话),称之为大顶堆. 则完全二叉树中每一个

第6章 堆排序 java实现 最简版

只考虑int类型的排序,以后考虑泛型实现. 1 public class Heap { 2 3 public int heap_size;//在build_max_heap中初始化,由heap_sort自动调用 4 5 public int parent(int i){ 6 return (i - 1) / 2; 7 } 8 public int left(int i){ 9 return 2 * i + 1; 10 } 11 public int right(int i){ 12 return

排序算法(三)堆排序及有界堆排序Java实现及分析

1.堆排序基数排序适用于大小有界的东西,除了他之外,还有一种你可能遇到的其它专用排序算法:有界堆排序.如果你在处理非常大的数据集,你想要得到前 10 个或者前k个元素,其中k远小于n,它是很有用的. 例如,假设你正在监视一 个Web 服务,它每天处理十亿次事务.在每一天结束时,你要汇报最大的k个事务(或最慢的,或者其它最 xx 的).一个选项是存储所有事务,在一天结束时对它们进行排序,然后选择最大的k个.需要的时间与nlogn成正比,这非常慢,因为我们可能无法将十亿次交易记录在单个程序的内存中.

leetcode215.数组中的第k个最大元素(快排/堆排序 java)***

class Solution { public int findKthLargest(int[] nums, int k) { int len=nums.length; int left=0,right=len-1; int target=len-k; //第k大的元素的数组下标就是len-k,可通过找规律得出 while(true){ int index=partition(nums,left,right); //index用来判断nums[left]排在数组中的第几位大小,并将其移到对应的位

堆排Java代码实现

堆排复习: 结论:堆排算法时间复杂度为O(nlgn),额外空间复杂度为O(1); 在开始堆排序过程之前先要熟悉两个结构 1,完全二叉树:若设二叉树的深度为h,除第 h 层外,其它各层 (1-h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树.(摘自百度百科) 大白话:说白了就是建立二叉树的过程中,二叉树每一层都是满节点的,最后一层的节点不许中间有空缺: 2,大根堆:大根堆要求根节点的关键字既大于或等于左子树的关键字值,又大于或等于右子树的关键字值.(摘自百

堆排序算法学习小记

1.完全二叉树的概念 若设二叉树的深度为h,除第 h 层外,其它各层 (1-h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树. 完全二叉树是由满二叉树而引出来的.对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树. (1)所有的叶结点都出现在第k层或k-l层(层次最大的两层) (2)对任一结点,如果其右子树的最大层次为L,则其左子树的最大层次为L或L+l. 一棵二叉树至多只有最下面

八种排序算法(内部排序)

八种排序算法很长时间没有使用了,今天做一个总结,方便以后自己用的时候参考. 这八种排序算法都是内部算法,这八种排序算法分别是: 1. 插入排序 1)直接插入排序 2)希尔排序 2.选择排序 1)简单选择排序 2)堆排序 3.交换排序 1)冒泡排序 2)快速排序 4.归并排序 5.基数排序 一.直接插入排序 将一个记录插入到已经排好序的有序表中,从而得到一个新的.记录数增1的有序表.在实际操作中,先将序列的第一个记录看成是一个有序的子序列,然后从第二个.第三个.……记录逐个进行插入,直至整个序列有

leetcode 做过的题目总结

双指针: leetcode167. 两数之和 II - 输入有序数组(双指针) leetcode 633.平方数之和(双指针 java) leetcode 345.反转字符串中的元音字母(双指针 java)(有地方不懂) leetcode 680.验证回文字符串 II(双指针 java) leetcode 88.合并两个有序数组(双指针 java) leetcode 141.环形链表(双指针 java) 排序: leetcode215.数组中的第k个最大元素(快排/堆排序 java)*** 只写