Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 实现quickselect_Algorithm_Quickselect - Fatal编程技术网

Algorithm 实现quickselect

Algorithm 实现quickselect,algorithm,quickselect,Algorithm,Quickselect,我正在尝试实现quickselect算法。尽管如此,我已经很好地理解了它背后的理论;我发现很难把它转换成一个运行良好的程序 下面是我如何一步一步地实施它,以及我面临的问题: 问题:在[]={2,1,3,7,5,4,6}中找到第四个最小元素 k=4 索引:0 | 1 | 2 | 3 | 4 | 5 | 6 对应值:2 | 1 | 3 | 7 | 5 | 4 | 6 最初,l=0和r=6 步骤1)将pivot作为最左边的元素(在这个问题中pivot始终是最左边的)- pivot\u index=0

我正在尝试实现quickselect算法。尽管如此,我已经很好地理解了它背后的理论;我发现很难把它转换成一个运行良好的程序

下面是我如何一步一步地实施它,以及我面临的问题:

问题:在[]={2,1,3,7,5,4,6}中找到第四个最小元素

k=4

索引:
0 | 1 | 2 | 3 | 4 | 5 | 6

对应值:
2 | 1 | 3 | 7 | 5 | 4 | 6

最初,
l=0
r=6

步骤1)将pivot作为最左边的元素(在这个问题中pivot始终是最左边的)-

pivot\u index=0

pivot\u值=2

步骤2)应用分区算法;将枢轴放在正确的位置(
[p]
)-

我们得到以下数组:
1 | 2 | 3 | 7 | 5 | 4 | 6

其中,
pivot\u index=i-1=1

因此,
pivot\u值=2

步骤3)
pivot\u索引
k
-

k=3
pivot\u index=1
<代码>k>
pivot\u索引

因此,第k个最小数位于数组的右侧

右数组=
i到r
,我们不再需要处理左部分(
l到i-1

步骤4)我们将
k
的值修改为
k-(枢轴索引)
=>4-1=2<代码>k=3

问题是:k的值不应该是2吗?因为在数组的左边有两个值:
1 | 2
?我们是否应该将
k
计算为
k-(枢轴指数+1)

让我们假设
k=3
是正确的

步骤5)要处理的“新”数组:
3 | 7 | 5 | 4 | 6
以及相应的索引:
2 | 3 | 4 | 5 | 6

现在,
pivot\u index=2
pivot\u index=3

步骤6)在上述阵列上应用分区算法-

3 | 7 | 5 | 4 | 6
(数组保持不变,因为枢轴本身是最低值)。
i=3

pivot\u index=i-1=2
pivot\u值=3

步骤7)
pivot\u索引
k

k=3
pivot\u index=2

k>pivot\u索引

等等

这种方法正确吗?

这是我的代码,它不工作。我使用了一个随机数生成器来选择一个随机轴,然后该轴与数组中的第一个元素交换

#include<stdio.h>
#include<stdlib.h>

void print_array(int arr[], int array_length){

    int i;

    for(i=0; i<array_length; ++i) {
        printf("%d ", arr[i]);
    }

}

int random_no(min, max){

    int diff = max-min;
    return (int) (((double)(diff+1)/RAND_MAX) * rand() + min);

}

void swap(int *a, int *b){

    int temp; 

    temp = *a;
    *a = *b;
    *b = temp;
}

int get_kth_small(int arr[], int k, int l, int r){

    if((r-l) >= 1){

        k = k + (l-1); 

        int pivot_index = random_no(l, r);

        int i, j;
        swap(&arr[pivot_index], &arr[l]);           //Switch the pivot with the first element in the array. Now, the pivit is in arr[l]

        i=l+1;

        for(j=l+1; j<=r; ++j){
            if(arr[j]<arr[l]){
                swap(&arr[j], &arr[i]);
                ++i;
            }
        }

        swap(&arr[l], &arr[i-1]);                   //Switch the pivot to the correct place; <p, p, >p

        printf("value of i-1: %d\n", i-1);
        printf("Value of k: %d\n", k);

        if(k == (i-1)){
            printf("Found: %d\n", arr[i]);
            return 0;
        }

        if(k>(i-1)){
            k=k-(i-1);
            get_kth_small(arr, k, i, r);
        } else {
            get_kth_small(arr, k, l, r-1);
        }

        //get_kth_small(arr, k, i, r);
        //get_kth_small(arr, k, l, i-1);

    }

}

void main(){

    srand(time(NULL));

    int arr[] = {2,1,3,7,5,4,6};
    int arr_size = sizeof(arr)/sizeof(arr[0]);
    int k = 3, l = 0;
    int r = arr_size - 1;

    //printf("Enter the value of k: ");
    //scanf("%d", &k);

    get_kth_small(arr, k, l, r);

    print_array(arr, arr_size);
    printf("\n");

}
#包括
#包括
无效打印数组(整数数组[],整数数组长度){
int i;
对于(i=0;i=1){
k=k+(l-1);
int pivot_index=随机数(l,r);
int i,j;
swap(&arr[pivot_index],&arr[l]);//使用数组中的第一个元素切换pivot。现在,pivit位于arr[l]中
i=l+1;

对于(j=l+1;j您所描述的是实现快速选择的有效方法。有许多其他方法可用于选择轴,其中大多数方法将提供更好的预期复杂度,但本质上算法是相同的。

步骤2:将轴放在正确的位置”:不要这样做。事实上,你不能将轴放在正确的位置,因为你不知道它是什么。分区规则是将所有小于或等于轴的元素放在大于轴的元素之前。只需将轴放在原来的位置

快速选择如下所示:要在
N
元素中找到
K
th,1)选择一个轴值,2)将所有元素移动到小于或等于轴的位置,形成两个长度为
Nle
Ngt
的区域,3)在相关区域上以(
K
Nle
)或(
K-Nle
Ngt
),直到
N=1


实际上,可以为轴取任何值,即使数组中没有一个值;但是分区必须确保
Nle
Ngt
非零。

但是k的值正确吗?(参见步骤4后的问题)你把这两个放在你正在考虑的数组部分中,所以K应该是代码>3 < /COD>。一个更优化的解决方案是丢弃枢轴并且只考虑数组的剩余部分,在这种情况下K的正确值是2。我看。不幸的是,我不能使我的程序与上面的逻辑一起工作。我也粘贴了我的代码,以防万一。你可以帮忙。我不明白。我可以根据p确定轴应该在哪里,其中p是轴。这正是我执行选择排序的方式,它工作得非常完美。所有小于p的值都在左侧,所有值都大于右侧的p,以及我们选择的轴(在这种情况下,最小的元素)介于两者之间。这是我的快速排序程序,它的工作原理是:你所需要的只是=p。轴心位置并不重要。有关C#的简单实现,请参阅。你应该能够非常轻松地转换为C。