堆排序(heapsort)

图片描述

古巷悠悠岁月深,青石老街印旧痕
今夜小楼听风雨,不见当年伞下人git

前言

堆排序是排序算法中的一种,算法时间复杂度是O(n log(n))。这里主要介绍堆的构建以及怎样经过heapify操做完成堆排序。代码是用C语言完成的,算法不难,你们能够本身用其余语言实现一下。github

什么是堆(Heap)

Heap须要知足两个条件:算法

1.Complete Binary Tree :须要是一颗彻底二叉树
2.Parent > Children:父节点的值必定要大于子节点的值

什么是彻底二叉树api

生成节点的顺序是从上往下、从左往右依次生成数组

以下图所示:
图片描述函数

父节点的值大于子节点的值ui

以下图所示:
图片描述spa

怎么样用代码表示堆

1.假设先有这样一颗彻底二叉树,它已是一个堆了code

图片描述

2.1 咱们按照从上往下、从左往右的顺序对每一个节点数字进行编号,
2.2 咱们能够用一个一维数组表示排序

图片描述

2.3 使用数组的下标来表示一个彻底二叉树的好处就是从任何一个节点出发我均可以经过计算来拿到这个节点的父节点和子节点

图片描述

构建堆

1.假设拿到了一堆数字:10 4 3 5 1 2,这些数字放在了一颗彻底二叉树上面,以下图所示:

图片描述

2.heapify:

把彻底二叉树调整成堆,咱们把这种操做起个名字叫:heapify

1.第一次heapify操做:把4(父节点)、十、3这三个子节点进行比较,找到最大值和父节点进行交换
交换后以下图:

图片描述

2.第二次heapify操做,把4(父节点)、五、1这三个子节点进行比较,找到最大值和父节点进行交换
交换后以下图:

图片描述

3.这样咱们就生成了一个堆:知足彻底二叉树、父节点值大于子节点的值

123步的代码实现:

void swap(int *tree, int max, int i) {
        int temp = tree[i];
        tree[i] = tree[max];
        tree[max] = temp;
    }
    
    /**
     对一个二叉树进行heapify操做
    
     @param tree 表示二叉树的数组
     @param n 二叉树的节点个数
     @param i 表示要对哪一个节点进行heapify操做
     */
    void heapify(int *tree, int n, int i) {
        if (i >= n) { // 递归函数出口
            return;
        }
        // 找到i节点的两个子节点
        int c1 = i*2 + 1;
        int c2 = i*2 + 2;
        // 找个三个节点的最大值 假设i是最大值
        int max = i;
        if(c1 < n && tree[c1] > tree[max]) { // c1 < n 表示节点下面没有子节点
            max = c1;
        }
        if (c2 < n && tree[c2] > tree[max]) {
            max = c2;
        }
        if (max != i) { // max != i b若是i已是最大值了就不用交换了
            swap(tree, max, i);
            heapify(tree, n, max);//max节点继续heapify
        }
    }
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            int tree[] = {4,10,3,5,1,2};
            int n = 6;
            heapify(tree, n, 0);
            
            for (int i = 0; i < n; i++) {
                printf("%d\n", tree[i]);
            }
        }
        return 0;
    }

输出结果:
图片描述

4.若是一棵彻底二叉树的节点的值都是乱序,咱们就能够从倒数第二层开始往上对每一个节点进行heapify,流程以下:
1.
图片描述

2.
图片描述

3.
图片描述

4.
图片描述

代码实现:

void buildHeap(int *tree, int n) {
        int lastNode = n-1;
        int parent = (lastNode-1)/2;
        for (int i = parent; i>=0; i--) {
            heapify(tree, n, i);
        }
    }
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            int tree1[] = {2,5,3,1,10,4};
            int m = 6;
            buildHeap(tree1, m);
            for (int i = 0; i < m; i++) {
                printf("%d\n", tree1[i]);
            }
        }
        return 0;
    }

输出结果:

图片描述

画出树结构:

图片描述

堆排序 heapsort

1.假设有一棵树是堆的结构,因此父节点大于子节点,且根节点是最大的

图片描述

2.首先第一步,根节点和最后一个节点交换,这样最大节点就跑到最后一位

图片描述

3.第二步把最后一位节点砍断

图片描述

4.由于刚刚作了第一步的交换,咱们就破坏了堆结构,因此咱们要作heapify,以此类推

代码实现:

void heapSort (int *tree, int n) {
        buildHeap(tree, n);
        for (int i = n-1; i>=0; i--) {
            swap(tree, i, 0);// 交换更节点和末位节点
            heapify(tree, i, 0); //破坏堆结构后作heapify操做
        }
    }
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            int tree[] = {2,5,3,1,10,4};
            int m = 6;
            heapSort(tree, m);
            for (int i = 0; i < m; i++) {
                printf("%d\n", tree[i]);
            }
        }
        return 0;
    }

输出结构:

图片描述

源码地址

连接描述

相关文章
相关标签/搜索