java 如何使用多线程查找未排序数组中的第k个最小元素

mm9b1k5b  于 2023-03-28  发布在  Java
关注(0)|答案(2)|浏览(147)

我需要学习如何使用多线程在未排序数组中正确查找第k个值。我将数组划分为子数组并在每个子数组中找到第k个值。但有时,这些值与真实答案不匹配。因此,我需要对每个子数组进行排序,然后对这些子数组进行一般排序,或者这里是使用多线程在未排序数组中查找第k个值的另一种算法?我的代码:

import java.util.*;
import java.util.stream.Stream;

public class SearchingItemThread implements Runnable{
    private int[] arr;
    private int left;
    private int right;
    private int k;
    private int median;

    public SearchingItemThread(int[] arr, int left, int right, int k){
        this.arr = arr;
        this.left = left;
        this.right = right;
        this.k = k;
    }

    @Override
    public void run() {
       median = select(0, arr.length - 1, k);
    }

    private int select(int left, int right, int k) {
        if (left == right) {
            return arr[left];
        }
        int pivotIndex = partition(left, right);
        if (k == pivotIndex) {
            return arr[k];
        } else if (k < pivotIndex) {
            return select(left, pivotIndex - 1, k);
        } else {
            return select(pivotIndex + 1, right, k);
        }
    }

    private int partition(int left, int right) {
        int pivotIndex = getPivot(left, right);
        int pivotValue = arr[pivotIndex];
        swap(pivotIndex, right);
        int storeIndex = left;
        for (int i = left; i < right; i++) {
            if (arr[i] < pivotValue) {
                swap(i, storeIndex);
                storeIndex++;
            }
        }
        swap(storeIndex, right);
        return storeIndex;
    }

    private int getPivot(int left, int right) {
        return new Random().nextInt(right - left + 1) + left;
    }

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

    public int getMedian() {
        return median;
    }
}

 public int findResultByMultithreading(int numberOfThreads, List<Integer> list, int target){

        int[][] subArrays = new int[numberOfThreads][];
        int subarraySize = list.size() / numberOfThreads;
        for (int i = 0; i < numberOfThreads; i++) {
            int startIndex = i * subarraySize;
            int endIndex = (i == numberOfThreads - 1) ? list.size() : (i + 1) * subarraySize;
            subArrays[i] = Arrays.copyOfRange(list.stream().mapToInt(Integer::intValue).toArray(), startIndex, endIndex);
        }

        Thread[] searcher = new Thread[numberOfThreads];
        SearchingItemThread[] runnables = new SearchingItemThread[numberOfThreads];
        List<Integer> medians = new ArrayList<>();

        for (int i = 0; i <= numberOfThreads - 1; i++) {
            runnables[i] = new SearchingItemThread(subArrays[i], 0, subArrays[i].length - 1, target);
            searcher[i] = new Thread(runnables[i]);

            searcher[i].start();
        }
        for (int i = 0; i < numberOfThreads; i++) {
            try {
                searcher[i].join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        for (int i = 0; i < numberOfThreads; i++) {
            medians.add(runnables[i].getMedian());
        }
        
        System.out.println(medians);
}

例如,我有一个数组:[4,7,2,9,5,1,6,8,3]和k = 3。如果我把这个数组分成三组,我会得到[4,7,2],[9,5,1]和[6,8,3]。在每个子数组中,第三个元素是[7,9,8]。这些值与真实答案不匹配- 3

1sbrub3j

1sbrub3j1#

您使用并行快速选择来查找每个子数组中的第k个最小元素。这并不一定是所有子数组中第k个最少的元素。但是这些快速选择为你做的不仅仅是找到每个子数组中第k个最少的元素。它们重新排列数组,以便每个子数组中所有第k个最少的元素都在一端。在这些 nk 个元素中的某个地方是总体的第 k 个最小的。
有几种方法可以继续。例如,
1.您可以对每个子数组的 k 个最小元素进行排序(并行),然后使用类似于 n 路合并的方法来找到总体最小值(此部分较少或不并行)。

  • 您可以通过几种不同的方式使用堆/优先级队列来查找目标编号,例如
  • 将所有 nk 个最小元素添加到最小堆中,然后进行 k 次选择,或
  • k 个元素形成一个最大堆,然后检查其他(n-1)k 个元素:如果一个元素E小于最大值,则删除最大值并将E插入到堆中。2在考虑了所有元素之后,堆中剩余的最大值就是目标元素。
  • 将每个子阵列的最小元素组形成最小堆,并且每次从任何堆中进行 k 次选择。

这些基于堆的部件可能需要全部串行化。

y1aodyip

y1aodyip2#

你想使用k个线程找到第k个最小的元素,每个线程都有一个数组的分区。
找到每个分区的最小值。最小值中的最大值是结果的初始值。现在不再需要该线程。其他线程继续搜索其分区中的第二小项,并将其与当前候选项进行比较。无论哪个线程的第二小项大于当前候选项,都可以停止其工作。如果有一些线程的第二-如果最小项小于当前候选项,则可以继续搜索。
重复这种操作方式,直到没有更多的线索继续搜索,并且仍然站立的候选人是对问题的回答。

相关问题