一、二叉堆简介:
二叉堆是一个完全二叉树或者是近似完全二叉树。
堆分为最大堆和最小堆,最大堆的任意非叶结点的关键字不小于其左右孩子结点的关键字,最小堆反之。
二、二叉堆的特点:
-
若其结点的编号为[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+" ");
}
}
九、参考图片