前言
本章总结堆排序。-_-
☆☆☆ 算法目录导航页,包含基础算法、高级算法、机器学习算法等☆☆☆
1.堆的定义
堆实际上是一棵完全二叉树,满足2个性质:
1.堆的每一个父节点都大于(或小于)其子节点;
2.堆的每个左子树和右子树也是一个堆。
堆分为两类:
1、最大堆(大顶堆):堆的每个父节点都大于其孩子节点;
2、最小堆(小顶堆):堆的每个父节点都小于其孩子节点;
2.堆排序过程
堆排序过程分3块:
1.初始化堆,即调整为堆;
2.交换堆顶和最后一个节点值,然后输出最后一个节点;
3.将剩余的节点继续调整为堆。
注意:交换完成后,要考虑子节点及其子节点所在树的堆结构是否发生变化。
小顶堆为例,画了个简易图如下:
3.小顶堆代码示例
import java.util.Arrays;
/**
*
* @author wxq
*
*/
public class SortHeap {
/**
* 测试
* @param args
*/
public static void main(String[] args) {
int [] arr = new int [] {1,8,6,4,2,3,5};
heapSort(arr);
System.out.println(Arrays.toString(arr));
}
/**
*
* 调整堆,只考虑3个节点【时刻记住】。
* 完全二叉树特性:可用数组表示左右子树
* 关键点:左子树 left = 2 * root +1
* 右子树 right= left + 1
* 小顶堆为例
*/
static void adjustHeap(int [] arr,int size,int root){
int left = 2 * root +1 ;//左子节点
int right = left + 1; //右子节点
int min_index = root;//假设最小值索引为当前root节点
//左子节点值小于最小值
if(left < size && arr[left] < arr[min_index]){
min_index = left;
}
//右子节点值小于最小值
if(right < size && arr[right] < arr[min_index]){
min_index = right;
}
//如果假设不成立,说明root不是最小,则需要交换。因为小顶堆需要满足节点值都不大于它的左右子节点值。
if(min_index != root){
swap(arr, min_index, root);
//交换完成后,需要调整左右子节点及其叶子节点
adjustHeap(arr, size, min_index);
}
}
/**
* 堆排
* @param arr
*/
static void heapSort(int [] arr){
int size = arr.length;
//最后一个非叶子节点
int last = size/2 - 1;
//1.建堆
for(int i = last; i >= 0;i--){
adjustHeap(arr, size, i);
}
//2.输出(swap)最小值后,再将剩余元素调整为堆
while(size > 1){ //剩余一个数就不需要交换了
swap(arr, 0, size -1); //交换后最后一个节点即为最小值
size--; //输出最小值,此时只剩size-1个数需要调整
adjustHeap(arr, size, 0);//剩余元素继续调整,从堆顶开始
}
}
/**
* 交换
* @param arr
* @param a
* @param b
*/
static void swap(int[] arr, int a, int b) {
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
}
4.大顶堆代码示例
/**
* 当前节点为k (数组表示完全二叉树时,k为下标):
* 父节点:(k -1) / 2
* 左孩子:2 * k + 1
* 右孩子:2 * k + 2
* @param arr
* @param curRoot 当前筛选的节点,【【【【注意:筛选只考虑非叶子节点!!!!!
* @param size 数组大小
*/
private static void adjustHeap(int[] arr, int curRoot, int size) {
int left = 2 * curRoot + 1;
int right= 2 * curRoot + 2;
int max_index = curRoot;//假设当前非叶子节点为当前子树的最大值
//发生交换之前,只考虑当前子树(3个节点的大小比较)
if(left < size && arr[left] > arr[max_index]){
max_index = left;
}
if(right < size && arr[right] > arr[max_index]){
max_index = right;
}
//若当前节点不是最大,就交换,交换后就要调整
if(max_index != curRoot){
//只要发生了交换,就要调整堆
swap(arr, max_index, curRoot);
adjustHeap(arr, max_index, size);
}
}
5.小顶堆其他代码示例(不好理解)
/**
* 小顶堆,非递归,不好理解~
*/
static void adjustDown_min(int arr[], int root, int size)
{
int left = root * 2 + 1;//左孩子
int right = left + 1; //右孩子
while (left < size)
{
if (right<size && arr[left] > arr[right])//子节点中找较小的
{
left++;
}
if (arr[root] < arr[left])
{
break;
}
swap(arr, left, root);
root = left;
left = root * 2 + 1;
}
}