HeapSort(堆排序)入门

时间:2022-07-03 22:09:02

学了数据结构,发现外国人对树这一结构,颇有研究,想想也不难发现,英文的句式结构都是树形的,不像中国的流水形结构,可能促进当前时代发展就是树这种思维模型吧。

正文

堆排序就是基于二叉树实现的选择排序算法,由于它的并不能解决类似(5,3,4,6,6,7,8)这样的数组传进去后,数组中两个相同的六能按输入顺序输出的功能,所以它仍然是不稳定的排序算法。它的实现过程采用了贪心策略,也就是每次比较都选择最大或者最小的值。

实现条件

进行堆排序的结构必须是完全二叉树。

我们把最普通的二叉树从根开始自上到下自左向右给每个节点从0开始编号,现在假设树中的任意一个节点的编号是 i ,二叉树i最多只能有两个孩子节点,分别叫左孩子和右孩子

完全二叉树根据定义必须满足:

i节点如果有右孩子节点,就必须有左孩子节点

根据 二叉树的节点i的编号性质,完全二叉树中的节点i就满足:

i的左孩子节点编号是2 i + 1,其右孩子节点编号是2 i+2

堆是啥?
堆是被限制住的完全二叉树,它必须满足完全二叉树中的任意节点i是最大或最小值的性质,比较范围限制在以i为根节点的子树的所有节点。

堆排序是啥?

  • 转换数据结构(数组 –> 堆)
  • 操作在上进行
    • 挑选最值并锁住
    • 重新对堆进行排序,使其满足堆的性质

过程

需要实现三个函数:

  • HeapSort(int[] array)
  • BuildHeap(int[] array)
  • Max_Heapify(int[] array , int rootNumber)
int[] array = {5,3,4,6,6,7,8};
//本次我们需要得到一个{3,4,5,6,6,7,8}递增队列。
HeapSort(array);

static int heap_size = 0; //用来记录堆节点数量

public static void HeapSort(int[] array){

//转换数据结构(数组 --> 堆)
BuildHeap(array);

//操作在堆上进行(For循环)
for(int i=array.length-1; i>=1; i--){

//将最值挑选出来并锁住
int max = array[0]; //挑选操作完成
array[0] = array[i];//打乱这个堆结构,促使它重新排序选最值
array[i] = max; //替换操作完成
heap_size --; //改变堆节点数量,锁操作完成

//重新对堆进行排序,使其满足堆的性质
Max_Heapify(array,0);
}
}

public static void BuildHeap(int[] array){

heap_size = array.length-1;//初始化堆节点数量

//由于满足完全二叉树的性质,子节点i的父节点必是(i-1)/2
//该for循环是为了使每颗子树都满足堆的性质
for(int i=heap_size/2; i>=0; i--){
Max_Heapify(array,i);//对每个子堆进行操作
}
}

public static void Max_Heapify(int[] array,int rootNumber){

int left = rootNumber*2+1;//得到左孩子节点编号
int right = rootNumber*2+2;//得到右孩子节点编号
int largest = rootNumber;//假设标记根节点为最大值

//选择该颗子树中的最大值
if(left<=heap_size && array[left]>array[rootNumber]){
largest = left;
}
if(right<=heap_size && array[right]>array[largest]){
largest = right;
}

//如果最大值不是根节点,进行替换和递归操作。
if(largest!=rootNumber){
//替换操作
int temp = array[rootNumber];
array[rootNumber] = array[largest];
array[largest] = temp;
//递归操作
Max_Heapify(array,largest);//由于替换掉了largest节点,所以会对以largest为根节点的子树产生影响。
}
}

理解

本次我们实现了一个大顶堆的操作,就是每次都挑选最大值置于堆顶,输出的是数组自下标0开始的一个递增序列。可以观察到在HeapSort的实现途中,heap_size这个变量有着很大的作用,它限制了整个堆的大小,是一个实现数组的数据结构转换成了堆结构的一个基础变量,随着最大值的选出,heap_size也越来越小,整个堆也越来越小。

堆排序和简单选择排序:

两种排序方法都是给定一个个数为n的数组,每次都从中选择最大值然后锁住。
简单选择排序:选择最大值时需要比较的总次数是:n+(n-1)+..+1(个数)
堆排序:选择最大值时需要比较的总次数是:logn+log(n-1)+..+log1(树高)

堆是一个很重要的结构,排序算法是计算机科学里面最基础的功能,所以选择一个好的数据结构去更快更好的实现它也是非常重要的一步。