堆排序详解



一、二叉堆简介:

二叉堆是一个完全二叉树或者是近似完全二叉树。

堆分为最大堆和最小堆,最大堆的任意非叶结点的关键字不小于其左右孩子结点的关键字,最小堆反之。

二、二叉堆的特点:

  1. 若其结点的编号为[0,n-1],其中n为结点的个数,若当前结点的编号为i,则其左孩子结点的编号为2i+1,其右孩子的编号为2i+2,其父结点的编号为(i-1)/2

  2. 若其结点的编号为[0,n-1],则其(n-1)/2+1,n-1这些编号的结点都是叶子结点;

  3. 利用最小堆来进行降序排序,利用最大堆来进行升序排序。

三、堆排序的思想:

  1. 构造最小堆:初始待排序的序列构建成一个最小堆,此堆为初始的无序区;从二叉堆的最后一个非叶子结点开始调整,每次调整都是从父结点、左孩子结点,右孩子结点三者中选择最小者和父结点进行交换(交换之后可能造成被交换的孩子结点不满足二叉堆的性质,因此每次交换之后要重新对被交换的孩子结点进行调整)。

  2. 交换元素:将堆顶元素与最后一个元素进行交换,得到一个新的无序区和新的有序区,且满足无序区的数据不小于有序区的元素;调整堆:由于交换后新的堆顶不满足堆的性质,因此需要对当前无序区调整为新堆,

  3. 将无序区的堆顶元素与无序区的最后一个元素进行交换,得到新的无序区和有序区,再对当前无序区调整为新堆,不断重复步骤23,直到有序区包含n-1个元素,即结束排序。

四、空间复杂度:堆排序每次只对一个元素进行操作,是就地排序的,其空间复杂度为O(1);

五、时间复杂度:O(N*lgN)

六、稳定性:不稳定;堆排序在交换数据的时候,是比较父结点和子结点之间的数据,所以即使存在2个数值相等的兄弟结点,他们的相对顺序在排序中也可能发生变化。

算法稳定性 -- 假设在数列中存在a[i]=a[j],若在排序之前,a[i]a[j]前面;并且排序之后,a[i]仍然在a[j]前面。则这个排序算法是稳定的!)

七、最好情况和最坏情况:待补充;

八、java代码实现

package cq.sortAlgorithm.com;

import org.junit.Test;

public class HeapSort {
 
 //建立最小堆
 public static void BulidMinHeap(int[] array)
 {
  int n = array.length-1;
  for(int i =(n-1)/2;i>=0;i--)
  {
   //HeapSort.partMinHeap(array, i, n);
   HeapSort.MinHeapFixDown(array, i, n);
  }
  for(int data:array)
    System.out.print(data+" ");
 }
 //结点区间为[0,n-1],即从结点i=(n-1)/2开始进行调整,
 //结点i的右子节点为2i+1,左子节点为2i+2;  
 /**
  * 该代码只下沉一次
  * @param array
  * @param i
  * @param n
  */
 public static void partMinHeap(int[] array,int i,int n)
 {
  int temp;
  temp = array[i];
  int j =2*i+1;
  if(j <= n)
  {
   if(j+1<= n && array[j]>array[j+1])
   {
    j++;
   }
   if(array[j] <temp)
   {  
    array[i]=array[j];
    array[j] =temp;
   }
  }
 }
/**
 * 当前结点i进行下沉
 * @param array :数据源
 * @param i  :当前节点的编号
 * @param n  :最后一个节点的编号
 */
 public static void MinHeapFixDown(int[] array,int i,int n)
 {
  int j = 0;
  int temp =0;
  j = 2*i+1;
  temp = array[i];
  while(j<=n)
  {
   if(j+1<= n && array[j]>array[j+1])
   {
    j++;
   }
   if(array[j] >= temp)
   {  
    break;
   }
   array[i] =array[j];
   i = j;
   j =2*i +1;
  }
  array[i] = temp;
 }

 public static void MinHeapFixUp(int[] array,int i)
 {
  int j,temp;
  j = (i-1)/2;
  temp = array[i];
  while(i!= 0 && j>= 0)
  {
   if(array[j] <= temp)
   {
    break;
   }
   //将父结点往下移
   array[i] =array[j];
   i = j;
   j =(i-1)/2;
  }
  array[i] =temp;
 }
 
 //堆的删除 ,删除堆顶元素array[0]
 public static void MinHeapDel(int[] array,int n)
 {
  int temp = array[n];
  array[n] =array[0];
  array[0] = temp;
  HeapSort.MinHeapFixDown(array, 0, n-1);
  for(int data:array)
     System.out.print(data+" ");
 }
 //堆的插入
 public static void MinHeapAdd(int[] array)
 {
  HeapSort.MinHeapFixUp(array,array.length-1);
  for(int data:array)
     System.out.print(data+" ");
 }
 //@Test
 public void test()
 {
  int[] array ={3,3,8,12,32,4,5,18,23};
  HeapSort.BulidMinHeap(array); //构建最小堆
  System.out.println();
  HeapSort.MinHeapDel(array,array.length-1);//删除堆顶元素
  System.out.println();
  array[array.length-1] = 16;//添加一个元素
  HeapSort.MinHeapAdd(array); 
 }
 @Test
 public  void MinHeapSort()
 {
  int[] array = {12,3,2,15,2,8,18,2,45};
   //构建最小堆
  HeapSort.BulidMinHeap(array); 
  
  for(int i = array.length-1;i>0;i--)
  {
   //交换数据
   int temp = array[i];    
   array[i] = array[0];
   array[0] = temp;
            //调整数据   
   HeapSort.MinHeapFixDown(array, 0, i-1);
   
  }
  System.out.println();
  for(int data:array)
     System.out.print(data+" ");
 }
 
}

九、参考图片



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值