堆排序的两种写法

项目介绍

  • 本项目通过分解各大厂的常见笔面试题,追本溯源至数据结构和算法的底层实现原理,知其然知其所以然;
  • 建立知识结构体系,方便查找,欢迎更多志同道合的朋友加入项目AlgorithmPractice,(欢迎提issue和pull request)。

什么是堆排序

  • 数组,按照树的结构来存储,即数组的第 i 位,其左孩子如果存在,那么存储在 2i+1 位上,其右孩子如果存在,那么存储在 2i+2 位上。
  • 堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆

两种解法

  • 1、建堆整堆法
  • 2、直接整堆法

正文开始

1、建堆整堆法

  • 代码实现:HeapSort,测试用例:HeapSortTest
  • 设计思路
    • 首先从数组的n/2开始,往回遍历至0,
    • 对于每个遍历到的元素,需要依次对其左右孩子进行对比,数值大的进行交换
    • 发生交换的情况下,需要再依次进行递归比较
  • 主要代码
建堆和整堆
public void sortMethod(int[] heap) {
    int temp;
    //输入检查
    if (!check(heap)) {
        return ;
    }
    //初试化建堆
    for (int i = (heap.length - 1) / 2; i >= 0 ; i--) {
        heapify_big(heap, i, heap.length - 1);
    }
    //交换堆顶和数组末尾元素,循环整堆,注意边界值
    for (int i = heap.length - 1; i > 0; i--) {
        temp = heap[0];
        heap[0] = heap[i];
        heap[i] = temp;
        heapify_big(heap, 0, i-1);
    }
}
整堆的细节
//整堆函数——大顶堆
public void heapify_big(int[] heap, int parent, int border){
    //左孩子,最大值标记
    int flag = parent * 2 + 1;
    //越界判断:如果左孩子存在
    if(flag > border){
        return ;
    }
    //如果右孩子存在
    if(flag + 1 <= border){
        //左右孩子对比,找最大值
        flag = heap[flag] > heap[flag + 1] ? flag : flag + 1;
    }
    //对比父节点和孩子结点,找最大值,发生交换,并递归其最大值孩子结点
    if(heap[flag] > heap[parent]){
        int temp = heap[flag];
        heap[flag] = heap[parent];
        heap[parent] = temp;
        heapify_big(heap, flag, border);
    }
}
  • 注意事项

2、直接整堆法

  • 代码实现:HeapSort2,测试用例:HeapSort2Test
  • 设计思路
    • 每一次整堆,都会把array[0]整出来,因此通过交换它来排序
    • 内部整堆是从 n/2 处开始,不断循环到0
  • 主要代码
public void sortMethod(int[] array) {
    //输入检查
    if (!check(array)) {
        return;
    }
    int length = array.length - 1;
    for (int i = 0; i < length; i++) {
        heapify_big(array, length - i);
        int temp = array[0];
        array[0] = array[length - i];
        array[length - i] = temp;
    }
}
public void heapify_big(int[] array, int bound) {
	//数组从0开始,因此中间值是 (bound - 1) / 2
	int mid = (bound - 1) / 2;
	int temp;
	for (int i = mid; i >= 0; i--) {
		int flag = 2 * i + 1;
		if (flag + 1 <= bound) {
		flag = array[flag] > array[flag + 1] ? flag : flag + 1;
		}
	if (flag <= bound && array[flag] > array[i]) {
		temp = array[flag];
		array[flag] = array[i];
		array[i] = temp;
		}
	}
}
  • 注意事项
    • 建堆整堆法,是先建堆,然后维护它,维护的时候,会有递归的操作
    • 直接整堆法,是通过两层循环实现,不需要递归的。

你可能感兴趣的:(数据结构和算法及其应用)