并行快速排序

并行快速排序

感谢网友浅水清流投递本稿。

并发算法是多核时代开始流行的技术趋势,比如tbbppl都提供了大量有用的并发算法。

经典算法中,排序是一个很适合采用分治法并发的场合,比如快速排序

常规的快速排序,先在数组中选取一个基准点,将数组分区为小于基准点和大于基准点(相同的数可以到任一边),对分区的子数组递归的执行分区的操作,当子数组长度为1时退出递归。此时数组就完成了排序过程。

01 int partition(int* array, int left, int right)
02 {
03         int index = left;
04         int pivot = array[index];
05         swap(array[index], array[right]);
06         for (int i=left; i<right; i++)
07         {
08                 if (array[i] > pivot)    // 降序
09                         swap(array[index++], array[i]);
10         }
11         swap(array[right], array[index]);
12         return index;
13 }
14  
15 void qsort(int* array, int left, int right)
16 {
17         if (left >= right)
18                 return;
19         int index = partition(array, left, right);
20         qsort(array, left, index - 1);
21         qsort(array, index + 1, right);
22 }

对快排的过程分析可以发现,分区以及对子数组排序的过程均可以并发执行,这里首先对数组进行分区,生成分区数组,为了保证不同分区不受到影响需要先完成分区再进行排序。

01 template <typename key, typename container >void parallel_sort(container & _container)template <typename key, typename container >
02 void partition_less(std::vector<key> * vless, container * _container, key privot){
03 for(size_t i = 0; i < (*_container).size(); i++){
04         if ((*_container)[i] < privot){
05             vless->push_back((*_container)[i]);
06         }
07     }
08 }
09  
10 template <typename key,  typename container >
11 void partition_more(std::vector<key> * vmore, container * _container, key privot){
12 for(size_t i = 0; i < (*_container).size(); i++){
13         if ((*_container)[i] >= privot){
14             vmore->push_back((*_container)[i]);
15         }
16     }
17 }

在完成分区之后,递归执行排序操作,并将排序好的分区重新写入待排序数组。

01 template <typename key, typename container >
02 int sort_less(container * _container, std::vector<key> & vless, boost::atomic_uint32_t * depth){
03     parallel_sort_impl<key>(&vless, *depth);
04  
05     for(size_t i = 0; i < vless.size(); i++){
06         (*_container)[i] = vless[i];
07     }
08  
09     return 0;
10 }
11  
12 template <typename key, typename container >
13 int sort_more(container * _container, std::vector<key> & vmore, boost::atomic_uint32_t * depth){
14     parallel_sort_impl<key>(&vmore, *depth);
15  
16     size_t pos = (*_container).size()-vmore.size();
17     for(size_t i = 0; i < vmore.size(); i++){
18         (*_container)[i+pos] = vmore[i];
19     }
20  
21     return 0;
22 }
23  
24 template <typename key, typename container >
25 void parallel_sort_impl(container * _container, boost::atomic_uint32_t & depth){
26     if (_container->size() < threshold || depth.load() > processors_count()){
27         std::sort(_container->begin(), _container->end());
28     }else{
29         key privot = (*_container)[_container->size()/2];
30  
31     std::vector<key> vless, vmore;
32     auto partition_result = std::async(std::launch::async, partition_less<key, container>, &vless, _container, privot);
33     partition_more(&vmore, _container, privot);
34     partition_result.get();
35  
36         auto result = std::async(std::launch::async, sort_less<key, container>, _container, vless, &depth);
37         sort_more(_container, vmore, &depth);
38         result.get();
39     }
40 }

这里采取了一个有趣的策略,就是通过数组的大小,计算出排序好的元素在原数组中的位置(这样即使是并发的访问数组,但是因为不同的线程各自访问的自己的下标位置,所以仍然是线程安全的),然后将排序好的数组直接写入到原数组,完成整个排序。

这里的并发采用了c++11中的promise:http://imcc.blogbus.com/logs/174131661.html

(全文完)如果您喜欢此文请点赞,分享,评论。


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是使用OpenMP编写的并行快速排序算法的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <omp.h> #define SIZE 1000000 void quicksort(int *arr, int left, int right); int partition(int *arr, int left, int right); int main() { int arr[SIZE]; int i; // 初始化数组 for (i = 0; i < SIZE; i++) { arr[i] = rand() % 100; } double start_time = omp_get_wtime(); // 并行快速排序 #pragma omp parallel { #pragma omp single nowait quicksort(arr, 0, SIZE-1); } double end_time = omp_get_wtime(); // 验证排序结果 for (i = 0; i < SIZE-1; i++) { if (arr[i] > arr[i+1]) { printf("Sort Error!\n"); break; } } printf("Sort Done!\n"); printf("Time: %f seconds\n", end_time-start_time); return 0; } void quicksort(int *arr, int left, int right) { int pivot; if (left < right) { pivot = partition(arr, left, right); #pragma omp task shared(arr) { quicksort(arr, left, pivot-1); } #pragma omp task shared(arr) { quicksort(arr, pivot+1, right); } } } int partition(int *arr, int left, int right) { int pivot = arr[right]; int i = left - 1; int j, temp; for (j = left; j <= right-1; j++) { if (arr[j] <= pivot) { i++; temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } temp = arr[i+1]; arr[i+1] = arr[right]; arr[right] = temp; return i+1; } ``` 在这个例子中,我们使用了OpenMP的任务并行来实现快速排序。在`quicksort`函数中,我们使用了`#pragma omp task`指令来创建任务,并使用`shared`属性来共享数组`arr`。这里的`nowait`属性告诉OpenMP不要等待任务完成,而是继续执行下一个语句。 在`main`函数中,我们使用了`#pragma omp parallel`指令来创建线程,并使用`single`属性来保证`quicksort`函数只被调用一次。`omp_get_wtime`函数用于计时。 最后,我们验证了排序结果,并输出了执行时间。 需要注意的是,为了避免任务创建过多导致性能下降,我们可以使用`if`子句来控制任务的创建。例如,在`quicksort`函数中,当`left < right`时才创建任务,否则直接进行串行排序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值