我编写代码来并行实现双向选择排序。我使用了c#和parallel.invoke函数。并行调用2个循环,一个用于查找最小值,另一个用于查找最大值。然而,它并没有排序。我想知道是什么问题,因为这种类型的排序无法并行处理,因为每个循环都依赖于另一个循环中存在的数据?...或者我的代码是否有问题?
Parallel.Invoke(
() =>
{
for (int i=0; i < array.Length / 2; i++)
{
int m;
int min = i;
for (m = i + 1; m < array.Length - 1; m++)
if (array[m] < array[min])
min = m;
//swap
int temp = array[min];
array[min] = array[m];
array[m] = temp;
}
},
() =>
{
for (int m = 0; m < array.Length / 2; m++)
{
int length = array.Length - 1;
int max = length - m;
int k;
for (k = length--; k > 0; k--)
if (array[k] > array[max])
max = k;
//swap
int temp = array[max];
array[max] = array[k];
array[k] = temp;
}
});
答案 0 :(得分:2)
我认为如果你在1个线程的同一个循环中搜索最小值和最大值会更容易:(java-code,但我假设你会理解这个原理)
int minimum, maximum;
int k = size();
for(int i = 0; i < size(); ++i)
{
--k;
minimum = i;
maximum = k;
if(k - i <= 0)
break;
for(int j = i; j <= k; ++j)
{
if(greaterThan(minimum, j))
minimum = j;
if(lessThan(maximum, j))
maximum = j;
}
if(minimum != i)
{
swap(minimum, i);
if(maximum == i)
maximum = minimum;
}
if(maximum != k)
swap(maximum, k);
}
您的代码存在以下问题:
说这是数组:
[5,4,3,2,1]
迭代0:第一个线程将找到要放在索引0上的最小元素 第一个线程在索引4处找到最小元素 迭代0:第二个线程将找到放在索引4上的最大元素 第二个线程在索引0
处找到最大元素您已经看到这不会很好地结束,因为两个线程将在索引0和4之间执行交换,导致与现在相同的情况。
另一个问题是如果你的第一个线程是从m - > array.length - 1.如果同时线程2通过交换将最小元素(它不需要,因为它搜索最大值)从索引k移动到“max”。索引“max”为&lt; “M”。这意味着第一个线程永远不会找到下一个最小值,因为它在其位置之前被移动了。
编辑:经过考虑,我认为不可能实现选择排序的直接并行版本。我首先推荐的版本确实无法工作,因为算法每次都找到相同的最小值,因为它没有改变输入数组。
可能的是只在数组的前半部分执行带有线程1的选择排序(并且只允许它在该半部分中找到最小值),而数组的后半部分用于第二个线程。然后最后你可以使用mergesort-algorithm合并两个half。
这样你总是可以使用2个以上的线程;比如说“p”线程数。每个负责输入数组的N / p部分,其中“N”是输入。最后,您只需使用mergesort-algorithm合并每个部分。我自己从未实现它,所以我不能说它是否有效,但我认为会有更好的算法来并行化(如mergesort本身)。
PS:关于上面发布的代码。我认为除了这一部分外,一切似乎都很简单:
if(maximum == i)
maximum = minimum;
这是为了处理这样的情况:
。 。 。一世 。 。 。 ķ
[1,4,3,1,5]
所以i = 1且k = 3(指数)。
该算法将找到:
最大=索引1
最小=指数3
将最小值与索引i上的值进行交换后,情况会发生如下变化:
。 。 。一世 。 。 。 ķ
[1,1,3,4,5]
意味着最大值(整数4)实际上从索引“i”移动到索引“minimum”。如果我们执行交换(最大值,k),则会产生错误的结果。这就是为什么我们需要更新最大元素的索引,如果它位于索引i。