java中二叉树中第k大的数,寻找第k大的数

目录:

1、引子

2、排序解决法

3、类快排解法

4、最小堆解法

1、引子

日常编码中,常见遇到这样的问题,“寻找最大的数”,此问题非常容易,可暴力直接遍历找出,也可使用分冶策略找出最大值(详见分冶算法)。

本文中需要寻找第k大的数,笔者目前想到3个方法可解决它。

2、排序解决法

如果是一个有序数组,那么寻找第k的大数则相当简单了,且效率为1。数组排序算法中相对较优的算法为快速排序,效率为N*lgN,将数组从到到小排列,第k大的数则为array[k-1]。

快排的思想为,从数组中取任意一个值key,将大于key的值放在key右边,小于key的值放在key左边。key的左边和右边则都是有序的了,然后递归key左边的子数组和key右边的子数组,直到每个子数组长度为1,此时,整个数组均有序了。

代码如下

public static int partition(int[] array, int left, int right) {

int k = array[left];

int i = left;

int j = right;

while (j > i) {

while (array[j] < k && j > i) {

j--;

}

if (j > i) {

array[i] = array[j];

i++;

}

while (array[i] > k && j > i) {

i++;

}

if (j > i) {

array[j] = array[i];

j--;

}

}

array[i] = k;

return i;

}

public static void quickSort(int[] array, int left, int right) {

if (left >= right) {

return;

}

int i = partition(array, left, right);

quickSort(array, left, i - 1);

quickSort(array, i + 1, right);

}

本文中快排略有差异,是按从大到小顺序排列。

快排的partition算法有两种写法,具体可查看快速排序及主定理。此解法效率为N*lgN

3、类快排解法

由于只要求找出第k大的数,没必要将数组中所有值都排序。

快排中的partition算法,返回key在数组中的位置,如果key的位置正好等于k-1,那么问题则得到解决,如果key的位置不等于k-1,可使用递归查找对应子数组。直到key的位置等于k-1,则找对问题的解。

public static int findK(int[] array, int left, int right, int k) {

int i = partition(array, left, right);

if (i == k - 1) {

return array[k - 1];

} else if (i > k - 1) {

return findK(array, left, i - 1, k);

} else if (i < k - 1) {

return findK(array, i + 1, right, k);

}

return 0;

}

此解法的效率值为N*lgK,由于K是常数,所以此解法效率值为N,优于排序解法

4、最小堆解法

最小堆是一种特殊的数组结构,它实质是一个完全二叉树,且树中子节点的值均大于父节点的值,详见 堆排序及优先队列。

考虑到只需要找到第k大的数,构造一个大小为k的最小堆,堆中根节点为最小值。如果数组中最大的几个数均在堆中,那么堆中根节点的值就是问题的解。

构造最小堆

public static void maxHeapify(int[] array, int size, int i) {

int left = 2 * i + 1;

int right = 2 * i + 2;

int small = i;

if (left < size) {

if (array[small] > array[left]) {

small = left;

}

}

if (right < size) {

if (array[small] > array[right]) {

small = right;

}

}

if (small != i) {

int temp = array[small];

array[small] = array[i];

array[i] = temp;

maxHeapify(array, size, small);

}

}

public static void buildHeap(int[] array, int size) {

for (int i = size - 1; i >= 0; i--) {

maxHeapify(array, size, i);

}

}

最小堆已构造完成,将数组中剩余的值与根节点相比,大于根节点的值则将根节点的值与之交换,同时维护最小堆的特性,遍历结束,则根结点即为问题的解。

public static int findKByHeap(int[] array, int k) {

buildHeap(array, k);

for (int i = k + 1; i < array.length; i++) {

if (array[i] > array[0]) {

int temp = array[i];

array[i] = array[0];

array[0] = temp;

maxHeapify(array, k, 0);

}

}

return array[0];

}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值