我正在处理一个大数据集,所以我决定实现从快速排序算法派生的线性选择算法,因为它在几乎线性的时间内给出数组中的第 n 个最小元素。这是我的实现:
long Random(long lower, long upper)
{
long num = (rand() % (upper - lower + 1)) + lower;
return num;
}
long partition(long arr[], long l, long r, long pivot)
{
long j = l;
long pi = arr[pivot];
swap(&arr[pivot], &arr[r]);
for (int i = l; i < r; i++)
{
if ((arr[i] < pi) && (j != i))
{
swap(&arr[j], &arr[i]);
j++;
}
}
swap(&arr[r], &arr[j]);
return j;
}
long select(long arr[], long l, long r, long n, int i)
{
if (n == 1)
{
return arr[0];
}
long pivot = Random(l, r);
long x = partition(arr, l, r, pivot);
if (x == i)
{
return arr[x];
}
else if (x > i)
{
return select(arr, l, x, (x - 1), i);
}
else
{
return select(arr, x, r, (n - x), (i - x));
}
}
int main(void)
{
srand(time(0));
FILE *f;
f = fopen("integers.txt", "r");
long arr[SIZE];
for (int i = 0; i < SIZE; i++)
{
fscanf(f, "%ld", &arr[i]);
}
fclose(f);
long in;
cout << "Enter the index you want to find - ";
cin >> in;
cout << select(arr, 0, (SIZE - 1), SIZE, (in - 1)) << endl;
}
它不仅给出了错误的答案,而且每次都给出了不同的答案。我不知道为什么,我使用 srand 和 rand 函数的方式有问题,还是我的算法有其他问题?
提前致谢
答案 0 :(得分:0)
在partition
中,当arr[j]
时arr[i]
与arr[i] < pi
交换,但我们对arr[j]
一无所知,除了{{1} } 从 j
开始(不是 1, l。请不要使用单个 l
作为变量名,这很容易引起误解)。
给定OP的签名并保持几乎相同的算法,它可以像下面这样写。
l
long partition(long arr[], long left, long right, long pivot_index)
{
using std::swap;
// "Protect" the pivotal value moving it to the right.
long pivot = arr[pivot_index];
swap(arr[right], arr[pivot_index]);
// Find the first element of the right partition.
long j = left;
while ( arr[j] < pivot && j < right)
++j;
// Corner case, the pivot is the max value too.
if ( j == right)
return j;
// Move all the elements less than the pivotal value to the left.
for (long i = j + 1; i < right; ++i)
{
if ( arr[i] < pivot )
{
swap(arr[j], arr[i]);
// j is the index of the first element not less than the pivot.
++j;
}
}
// Put the pivot "back" in place.
swap(arr[j], arr[right]);
return j;
}
也需要一些调整。
select
请注意,您实际上并不需要传递数组/分区的大小(元素数),可以通过其极端情况来推断。
另请注意,在标准库中,通常将范围的值作为一对迭代器(或实际的 std::range
,因为 C++20)进行传递。见例如std::nth_element
和 std::partition
以及它们可能的实现。