堆排序

  1. 堆结构就是用数组实现的完全二叉树
  2. 完全二叉树如果子树最大值在顶部就是大根堆
  3. 完全二叉树如果子树最小值都在顶部就是小根堆
  4. 优先队列操作,就是堆操作

堆排序

1.先让整个数组都变成大根堆,建立堆过程。
1) 从上到小下,时间复杂度为O(N*logN)
2)从下到上的方法,时间复杂度为0(N)
2. 把堆的最大值和堆末尾的值交换,然后减少堆的大小之后再去调整堆,一直周而复始,时间复杂度为O(N * logN)
3. 堆的大小减小为0后,排序完成。

在这里插入图片描述
在这里插入图片描述

 private static void heapSort(int[] arr) {

        //先找到非叶子节点,构建大根堆
        for (int i = (arr.length - 1) / 2; i >= 0; i--) {
          //从i向下找,保证每个元素都能被找到,如果从0开始如果最大值正好在第一位,
           // 后面无法比较,找到某一个叶子节点的最大值
            heapify(arr, i, arr.length);
        }

        int heapSize = arr.length;
        while (heapSize > 1) {
            swap(arr, --heapSize, 0);
            heapify(arr,0, heapSize);
        }
    }


private static void heapify(int[] arr, int index, int heapSize) {
        int left = 2 * index + 1;
        while (left < heapSize) {
            int max = left;

            //左数、右数比较比较
            //如果left+ 1不超过树的长度,并且右数比左数大,max设置为左数
            if (left + 1 < heapSize && arr[left + 1] > arr[left]) {
                max = left + 1;
            }
            //index和左右两个数最大值比较,找到最大的
            max = arr[max] < arr[index] ? index : max;

            //如果最大值与index值相同,
            if (arr[max] == arr[index]) {
                break;
            }
            //如果最大值比index大,则交换最大值
            if (arr[max] > arr[index]) {
                swap(arr, index, max);
            }
            //下沉
            index = max;
            left = 2 * index + 1;
        }
    }

堆排序的拓展题目

               已知一个几乎有序的数组,几乎有序是指,如果把数组排好序的话,每一个元素的移动距离不超过k,并且k对于数组来说比较小,请选择一个合适的算法进行排序。

几乎有序的数组,移动距离不超过k,那么意味着这个数的最小值就在这个k长度数组里面,构建最小堆,然后k个一比较,比较到结束,把剩余的重新比较。

 private static void sortAlmostArr(int[] arr, int k, int heapSize) {
        //先将k元素拷贝下来
        int[] temp = Arrays.copyOf(arr, k);

        //构建小根堆,保证父亲节点都是最大的
        for (int i = (k -1)/2; i >=0; i--) {
            heapiSmall(temp, i, k);
        }
        
        
        //从k位向后走,不断构建小根堆开始
        for (int i = k; i < heapSize; i++) {
            //由于构建了小根堆,最小值index为0将temp第一个元素获取出来就是他的
            int tep = temp[0];
            temp[0] = arr[i];
            arr[i-k] =tep;
            //从0位置上不断的找最小值
            heapiSmall(temp, 0, k);
        }

        //正好begin走到n-k位置上,end越界了,所以从begin到end要重新排序
        for(int i = heapSize - k ; i < heapSize; i++) {
            arr[i] = temp[0];
            swap(temp, 0, --k);
            heapiSmall(temp,i, k);
        }
    }
private static void heapiSmall(int[] temp, int index, int heapSize) {
        int left = 2 * index + 1;
        while (left < heapSize) {
            int max = left;
            if (left + 1 < heapSize && temp[left+ 1] < temp[left]) {
                max = left + 1;
            }

            if (temp[index] < temp[max]) {
                max = index;
            }

            if (temp[index] == temp[max]) {
                break;
            }

            if (temp[max] < temp[index]) {
                swap(temp, max, index);
            }
            index = max;
            left = 2 * index + 1;
        }
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值