算法——找出N个整数中最大的K个数(Java实现)

引言

  算法思路来自找出N个整数中最大的K个数,可以看出,TopK问题,基本上是排序算法的延伸:

  1. 利用全排序,再倒数K个数;
  2. 快速排序,分区分治;
  3. 类似快速排序,分区找第K大的数;
  4. 堆排序,建立最小堆;
  5. 计数排序,先计数,再倒数K个数;

实现

import java.util.Arrays;
import java.util.Random;

public class TopK {

    private static int[] getRandomInts(int count, int max) {

        if (count <= 0 || max <= 0) {
            return null;
        }

        Random random = new Random();

        int[] result = new int[count];

        for (int i = 0; i < count; i++) {
            result[i] = random.nextInt(max);
        }

        return result;
    }


    private static void swap(int[] a, int i, int j) {
        int temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }

    private static int partition(int[] a, int left, int right) {
        int pivot = left;
        int index = pivot + 1;

        for (int i = index; i <= right; i++) {
            if (a[pivot] > a[i]) {
                swap(a, i, index);
                index++;
            }
        }

        swap(a, index - 1, pivot);

        return index - 1;
    }

    private static void partitionTopK(int[] a, int start, int end, int k) {

        if (k == 0) {
            return;
        }

        int left = start;
        int right = end;
        int partitionIndex = partition(a, left, right);

        if (right - partitionIndex + 1 < k) {
            partitionTopK(a, left, partitionIndex - 1, k - (right - partitionIndex + 1));
        } else if (right - partitionIndex + 1 > k) {
            partitionTopK(a, partitionIndex + 1, end, k);
        } else {
            return;
        }
    }

    private static int[] quickTopK(int[] a, int k) {
        int left, right;
        left = 0;
        right = a.length - 1;
        partitionTopK(a, left, right, k);

        return Arrays.copyOfRange(a, a.length - k, a.length);
    }

    private static void buildMinHeap(int[] a, int k) {
        for (int i = k / 2; i >= 0; i--) {
            heapAdjust(a, i, k);
        }
    }

    private static void heapAdjust(int[] a, int parentIndex, int length) {
        int leftIndex = parentIndex * 2 + 1;
        int rightIndex = parentIndex * 2 + 2;
        int smallest = parentIndex;

        if (leftIndex < length && a[leftIndex] < a[smallest]) {
            smallest = leftIndex;
        }

        if (rightIndex < length && a[rightIndex] < a[smallest]) {
            smallest = rightIndex;
        }

        if (smallest != parentIndex) {
            swap(a, smallest, parentIndex);
            heapAdjust(a, smallest, length);
        }
    }

    private static int[] heapTopK(int[] a, int k) {

        buildMinHeap(a, k);

        int length = a.length;
        int smallest = a[0];

        for (int i = k; i < length; i++) {
            if (a[i] > smallest) {
                swap(a, i, 0);
                heapAdjust(a, 0, k);
                smallest = a[0];
            }
        }

        return Arrays.copyOfRange(a, 0, k);
    }


    public static void main(String[] args) {

        int count, max, k;
        count = 20;
        max = 100;
        k = 5;

        int[] randomInts = getRandomInts(count, max);
        if (randomInts == null) {
            return;
        }

        int[] quickRandomInts = Arrays.copyOf(randomInts, randomInts.length);
        int[] quickTopK = quickTopK(quickRandomInts, k);
        System.out.println(Arrays.toString(quickTopK));

        int[] heapRandomInts = Arrays.copyOf(randomInts, randomInts.length);
        int[] heapTopK = heapTopK(heapRandomInts, k);
        System.out.println(Arrays.toString(heapTopK));


    }
}

一些思考

  排序算法作为非常重要的算法,不仅能够给出排序的各种实现,能够对比讨论算法时空间复杂度,而且是解决类似问题的基础,更重要的是,能够培养人用多个角度看待问题,逐步深入的解决问题。
  前两天看到一篇文章,其中提到,算法是创业成功的理论和实践基础。初步理解,这其中的“算法”是一种思路,但更是一种,“深入行业——认识问题——抽象问题——解决问题——从深度角度挖掘问题,螺旋上升”的自我进化,不确定有没有最好的,但是“我们一直在路上”。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
C语言寻n个整数第K小的数可以使用快速选择算法。该算法的基本思想是利用快速排序的分治思想,每次选择一个pivot元素将数组分成两部分,然后根据pivot元素的位置与K的大小关系确定下一步搜索的方向。具体实现如下: 1. 定义一个函数findKthSmallest,输入参数为n个整数的数组a,数组长度n和要寻的第K小的数k,返回值为第K小的数。 2. 在函数内部定义一个递归函数quickSelect,输入参数为数组a,数组长度n,要寻的第K小的数k,返回值为第K小的数。 3. 在quickSelect函数内部实现快速选择算法的主要步骤: - 选择一个pivot元素,可以随机选取或者选取最左边的元素。 - 将数组a分成两部分,小于pivot的元素放在左边,大于等于pivot的元素放在右边。 - 如果pivot的位置为k-1,则返回pivot元素。 - 如果pivot的位置小于k-1,则说明要在右边继续搜索第K小的数,递归调用quickSelect函数。 - 如果pivot的位置大于k-1,则说明要在左边继续搜索第K小的数,递归调用quickSelect函数。 4. 在findKthSmallest函数调用quickSelect函数,并返回结果。 下面是使用快速选择算法n个整数第K小的数的示例代码: ```c #include <stdio.h> void swap(int *a, int *b) { int temp = *a; *a = *b; *b = temp; } int quickSelect(int a[], int n, int k) { int pivot = a[0]; int left = 0, right = n - 1; while (left <= right) { while (left <= right && a[left] < pivot) { left++; } while (left <= right && a[right] >= pivot) { right--; } if (left <= right) { swap(&a[left], &a[right]); left++; right--; } } if (k - 1 == right) { return pivot; } else if (k - 1 < right) { return quickSelect(a, right + 1, k); } else { return quickSelect(a + right + 1, n - right - 1, k - right - 1); } } int findKthSmallest(int a[], int n, int k) { if (k <= 0 || k > n) { printf("k is out of range\n"); return -1; } return quickSelect(a, n, k); } int main() { int a[] = {3, 1, 4, 2, 5}; int n = 5; int k = 3; int kth = findKthSmallest(a, n, k); printf("The %dth smallest element is %d\n", k, kth); return 0; } ``` 输结果为: ``` The 3th smallest element is 3 ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值