随机选择算法

Posted

技术标签:

【中文标题】随机选择算法【英文标题】:Randomized Selection Algorithm 【发布时间】:2014-10-15 00:10:13 【问题描述】:

我正在尝试实现一个,其中一个数组填充有随机数,用户选择一个位置,程序返回与数组排序版本中的位置一致的值,而不实际对数组进行排序。

问题是程序在给定位置给出元素的值,但在未排序的数组中。

import java.util.*;

public class RandomizedSelection 

    public static void main(String[] args) 
        int maxSize = 10; // max size of the array
        int[] arr = new int[maxSize];

        // fill array with random numbers between the range of 0-200
        for (int i = 0; i < maxSize; i++) 
            int n = (int)(java.lang.Math.random()*199); 
            arr[i] = n;
        

        System.out.println("There is an array of 100 elements in the range" +
                            " of 0 - 200. Select a location to view" +
                            " the value.");

        Scanner in = new Scanner(System.in);
        int userChoice = in.nextInt(); // get user's choice of i

        int loc = randomizedSelect(arr, 0, arr.length-1, userChoice);

        System.out.println(loc);

        System.out.println("The array was:\n" + Arrays.toString(arr));
    

    public static int randomizedSelect(int[] array, int p, int r, int i) 
        if (p == r)
            return array[p];

        if (i == 0)
            return -1;

            int mid = randomizedPartition(array, p, r);
            int k = mid - p + 1;

            if (k == i) 
                return array[mid];
            else if (i < k)
                return randomizedSelect(array, p, mid-1, i);
            else
                return randomizedSelect(array, mid+1, r, i-k);

    

    public static int randomizedPartition(int[] array, int start, int end) 
        Random rand = new Random();
        int pivotIdx = rand.nextInt((end - start) + 1) + start;
        int pivot = array[pivotIdx];

        swap(array[pivotIdx], array[end]);
        pivotIdx = end;

        int i = start - 1;

        for (int j = start; j <= end-1; j++) 
            if (array[j] <= pivot) 
                i++;
                swap(array[i], array[j]);
            
        
        swap(array[i+1], array[pivotIdx]);
        return i+1;
    

    public static void swap(int i, int j) 
        int temp = i;
        i = j;
        j = temp;
           

如果用户选择位置选项 4,此程序的输出是: 50 数组为:[195, 24, 111, 50, 37, 128, 196, 117, 167, 195]

排序后的数组应该是: [24、37、50、111、117、128、167、195、195、196] 这应该使位置选择 4 等于 111,而不是 50。

【问题讨论】:

【参考方案1】:

尝试将您的排序数组,或者至少在每次调用randomizedPartition 结束时数组看起来如何。你会发现数组从创建时开始并没有改变。

现在尝试在每次调用swap 后查看您的数组,您会再次注意到swap 方法未更改数组。所以现在我们知道swap 方法并没有像你想要的那样工作。

为什么会这样?

您是否阅读过有关按引用传递与按值传递的内容?

对于原语 java 使用 passe-by-value 而不是引用,因此 swap 方法的 ij 参数是存储在数组中的值的副本,改变了 i 或 @987654329 的值@ 根本不会影响数组。

尝试将交换的签名更改为

private static void swap(int[] array, int indexI, int indexJ) ...

更改swap 方法的主体以移动数组中的元素,看看效果如何。

顺便说一句,使用更好的变量名,您的代码会更好。此外,用于初始化数组的随机数生成器的范围也不正确。

【讨论】:

非常感谢您解决这个问题。我调整了 swap 方法来移动数组中的元素,现在我得到一个数组索引越界错误。这是否与我的随机数生成器用于初始化数组的上述错误范围有关? 否,随机数生成器不会导致您的索引越界错误。从堆栈跟踪中找到错误行。然后在该行之前输出您用来索引数组的值。如果其中任何一个大于或等于 maxSize,您将收到错误消息。尝试附加调试器并查看这些值的来源。对于调试,为随机数生成器 rand = new Random(1); // Remove the 1 before release 使用固定种子可能更容易,这将使随机数每次都相同。

以上是关于随机选择算法的主要内容,如果未能解决你的问题,请参考以下文章

Dijkstra 算法随机选择具有相同最小权重的相邻节点

随机选择第k小元素随机快速排序-算法设计与分析实验四

随机选择第k小元素随机快速排序-算法设计与分析实验四

随机选择第k小元素随机快速排序-算法设计与分析实验四

随机森林算法OOB_SCORE最佳特征选择

c_cpp 【随机化算法】线性时间选择算法【7.3.1】舍伍德(舍伍德)算法