堆排序算法的理解与实现

完全二叉树

  • 对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。
    完全二叉树

数组转完全二叉树

  • 在不越界的情况下,位置i左孩子下标 2*i +1
  • 在不越界的情况下,位置i右孩子下标 2*i + 2
  • 在不越界的情况下,位置i的父节点(i-1)/2

大根堆

  • 在一个树中,任何一个子树的最大值都是这个子树的头部

小根堆

  • 在一个树中,任何一个子树的最小值都是这个子树的头部

数组变大根堆

  • 首先将数组转化为完全二叉树,将将每一个子节点与父亲节点(i-1)/2相比较,如果比父节点大则与父节点交换

    public static void heapSort(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            heapInsert(arr,i);
        }
    }

    public static void heapInsert(int[] arr, int index) {
        while (arr[index] > arr[(index - 1) / 2]) {
               swap(arr,index,(index-1)/2);
               index = (index-1)/2;
        }
    }

    // 交换函数
    public static void swap(int[] arr, int L, int R) {
        int t = arr[L];
        arr[L] = arr[R];
        arr[R] = t;
    }
  • 复杂度:O(N)

当堆中某个元素发生改变时重新对该元素排序

  • 将发生改变的元素与孩子节点的中的最大值相比较,如果小于则交换,直到该元素无法再交换
 public static void heapify(int[] arr, int index, int heapSize) {
        // 获取左节点
        int leftNode = 2 * index + 1;
        while (leftNode < heapSize) {
            // 判断左右节点哪个节点的元素更大,largest为该点的下标
            int largest = leftNode + 1 < heapSize && arr[leftNode + 1] > arr[leftNode] ? leftNode+1 : leftNode ;
            largest = arr[largest]>arr[index]?largest:index;
            if(largest==index) {
                break;
            }
            swap(arr,largest,index);//largest ! = index
            index = largest;//与左右孩子中较大孩子下标交换
            leftNode = index *2 +1;
        }

    }

堆排序算法的实现思路

  • 首先将该数组转为一个大根堆(利用上述的heapInsert),将堆顶元素依次与最后一个元素交换,数组长度-1,将最后一个元素隔离,再利用上述的heapify方法对元素进行重新排列二叉树,依次类推,直到数组长度为0
  • 时间复杂度:O(n*log n)
    public static void heapSort(int[] arr) {
        if(arr ==null || arr.length <2) {
            return;
        }
        for (int i = 0; i < arr.length; i++) {
            heapInsert(arr, i);
        }
        int size = arr.length;
        swap(arr,0,--size);
        while(size>0) {
            heapify(arr,0,size);
            swap(arr,0,--size);
        }
    }

    // 插入堆,大根堆
    public static void heapInsert(int[] arr, int index) {
        while (arr[index] > arr[(index - 1) / 2]) {
            swap(arr, index, (index - 1) / 2);
            index = (index - 1) / 2;
        }
    }

    // 当堆中某个元素发生改变时重新对该元素排序
    public static void heapify(int[] arr, int index, int heapSize) {
        // 获取左节点
        int leftNode = 2 * index + 1;
        while (leftNode < heapSize) {
            // 判断左右节点哪个节点的元素更大,largest为该点的下标
            int largest = leftNode + 1 < heapSize && arr[leftNode + 1] > arr[leftNode] ? leftNode+1 : leftNode;
            largest = arr[largest]>arr[index]?largest:index;
            if(largest==index) {
                break;
            }
            swap(arr,largest,index);//largest ! = index
            index = largest;//与左右孩子中较大孩子下标交换
            leftNode = index *2 +1;
        }

    }
    // 交换函数
    public static void swap(int[] arr, int L, int R) {
        int t = arr[L];
        arr[L] = arr[R];
        arr[R] = t;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值