Algorithm 实现quickselect
我正在尝试实现quickselect算法。尽管如此,我已经很好地理解了它背后的理论;我发现很难把它转换成一个运行良好的程序 下面是我如何一步一步地实施它,以及我面临的问题: 问题:在[]={2,1,3,7,5,4,6}中找到第四个最小元素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
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。