堆排序详解

    xiaoxiao2026-09-29  15

    

    一、二叉堆简介:

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

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

    二、二叉堆的特点:

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

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

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

    三、堆排序的思想:

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

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

    将无序区的堆顶元素与无序区的最后一个元素进行交换,得到新的无序区和有序区,再对当前无序区调整为新堆,不断重复步骤2和3,直到有序区包含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+" ");  }   }

    九、参考图片

    转载请注明原文地址: https://ju.6miu.com/read-1312460.html
    最新回复(0)