每日一算法|堆排序---第八天

Posted 江小湖资源分享平台

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了每日一算法|堆排序---第八天相关的知识,希望对你有一定的参考价值。

堆排序






每日一算法|堆排序---第八天

算法

原理

堆排序(英语:Heapsort)是指利用这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

堆算法在排序算法中算是比较难的一种算法,你要了解堆和二叉树等数据结构的相关知识。堆是具有以下性质的完全二叉树:1.每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;2.或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。(见下图)

我们拿到一组数据之后,先把它整理成二叉树的结构。例如有一原始数列{2、10、9、5、6、1},写成二叉树为

每日一算法|堆排序---第八天

要满足堆的性质:父节点要比孩子节点大,显然上图中根节点要比它的左右孩子节点10和9都要小,所以要拿根节点2和孩子节点中大的那一个交换(想想为什么要和大的交换?),即2与10交换位置。

每日一算法|堆排序---第八天

此时再观察交换后二叉树中以2为父节点的结构不符合堆的性质,所以把父节点2与它的右孩子节点6交换。

每日一算法|堆排序---第八天

最终我们得到:

每日一算法|堆排序---第八天

此时的数列为{10、6、9、5、2、1},接着把第一位置的10和最后一位的1交换位置,数列为{1、6、9、5、2、10},第一趟的过程结束。

第二次时,把10排除在外,把剩下顺序的数列再按照上诉步骤进行下去即可。没进行一次,我们都能把最大的数找出来,就像有一个大土堆,我们把最大块的推到堆顶。

我们把上面的过程总结一下:堆排序分为两步

1.构造堆。

2.固定最大值再构造堆




对应下来的数组为:




C语言



#include <stdio.h>
#include <stdlib.h>
void swap(int *a, int *b) {
    int temp = *b;
    *= *a;
    *= temp;
}
void max_heapify(int arr[], int start, int end) {
    // 建立父節點指標和子節點指標
    int dad = start;
    int son = dad * 2 + 1;
    while (son <= end) { // 若子節點指標在範圍內才做比較
        if (son + 1 <= end && arr[son] < arr[son + 1]) // 先比較兩個子節點大小,選擇最大的
            son++;
        if (arr[dad] > arr[son]) //如果父節點大於子節點代表調整完畢,直接跳出函數
            return;
        else { // 否則交換父子內容再繼續子節點和孫節點比較
            swap(&arr[dad], &arr[son]);
            dad = son;
            son = dad * 2 + 1;
        }
    }
}
void heap_sort(int arr[], int len) {
    int i;
    // 初始化,i從最後一個父節點開始調整
    for (= len / 2 - 1; i >= 0; i--)
        max_heapify(arr, i, len - 1);
    // 先將第一個元素和已排好元素前一位做交換,再重新調整,直到排序完畢
    for (= len - 1; i > 0; i--) {
        swap(&arr[0], &arr[i]);
        max_heapify(arr, 0, i - 1);
    }
}
int main() {
  int arr[] = { 3, 5, 3, 0, 8, 6, 1, 5, 8, 6, 2, 4, 9, 4, 7, 0, 1, 8, 9, 7, 3, 1, 2, 5, 9, 7, 4, 0, 2, 6 };
    int len = (int) sizeof(arr) / sizeof(*arr);
    heap_sort(arr, len);
    int i;
    for (= 0; i < len; i++)
        printf("%d ", arr[i]);
    printf("\n");
    return 0;
}



Java



    //堆排序

    public static void heapSort(int[] arr) {

        //构造大根堆

        heapInsert(arr);

        int size = arr.length;

        while (size > 1) {

            //固定最大值

            swap(arr, 0, size - 1);

            size--;

            //构造大根堆

            heapify(arr, 0, size);

 

        }

 

    }

 

    //构造大根堆(通过新插入的数上升)

    public static void heapInsert(int[] arr) {

        for (int i = 0; i < arr.length; i++) {

            //当前插入的索引

            int currentIndex = i;

            //父结点索引

            int fatherIndex = (currentIndex - 1) / 2;

            //如果当前插入的值大于其父结点的值,则交换值,并且将索引指向父结点

            //然后继续和上面的父结点值比较,直到不大于父结点,则退出循环

            while (arr[currentIndex] > arr[fatherIndex]) {

                //交换当前结点与父结点的值

                swap(arr, currentIndex, fatherIndex);

                //将当前索引指向父索引

                currentIndex = fatherIndex;

                //重新计算当前索引的父索引

                fatherIndex = (currentIndex - 1) / 2;

            }

        }

    }

    //将剩余的数构造成大根堆(通过顶端的数下降)

    public static void heapify(int[] arr, int index, int size) {

        int left = 2 * index + 1;

        int right = 2 * index + 2;

        while (left < size) {

            int largestIndex;

            //判断孩子中较大的值的索引(要确保右孩子在size范围之内)

            if (arr[left] < arr[right] && right < size) {

                largestIndex = right;

            } else {

                largestIndex = left;

            }

            //比较父结点的值与孩子中较大的值,并确定最大值的索引

            if (arr[index] > arr[largestIndex]) {

                largestIndex = index;

            }

            //如果父结点索引是最大值的索引,那已经是大根堆了,则退出循环

            if (index == largestIndex) {

                break;

            }

            //父结点不是最大值,与孩子中较大的值交换

            swap(arr, largestIndex, index);

            //将索引指向孩子中较大的值的索引

            index = largestIndex;

            //重新计算交换之后的孩子的索引

            left = 2 * index + 1;

            right = 2 * index + 2;

        }

 

    }

    //交换数组中两个元素的值

    public static void swap(int[] arr, int i, int j) {

        int temp = arr[i];

        arr[i] = arr[j];

        arr[j] = temp;

    }




Python



def buildMaxHeap(arr):
    import math
    for i in range(math.floor(len(arr)/2),-1,-1):
        heapify(arr,i)

def heapify(arr, i):
    left = 2*i+1
    right = 2*i+2
    largest = i
    if left < arrLen and arr[left] > arr[largest]:
        largest = left
    if right < arrLen and arr[right] > arr[largest]:
        largest = right

    if largest != i:
        swap(arr, i, largest)
        heapify(arr, largest)

def swap(arr, i, j):
    arr[i], arr[j] = arr[j], arr[i]

def heapSort(arr):
    global arrLen
    arrLen = len(arr)
    buildMaxHeap(arr)
    for i in range(len(arr)-1,0,-1):
        swap(arr,0,i)
        arrLen -=1
        heapify(arr, 0)
    return arr



以上是关于每日一算法|堆排序---第八天的主要内容,如果未能解决你的问题,请参考以下文章

冲刺大厂每日算法&面试题,动态规划21天——第八天

蓝桥集训(附加面试题)第八天

蓝桥集训(附加面试题)第八天

python数据结构与算法第八天排序算法

爱创课堂每日一题第八天说说你对作用域链的理解?

每日算法&面试题,大厂特训二十八天——第二十八天(数组)