串行的链表排序
template<typename T>
std::list<T> quick_sort(std::list<T> input) {
if (input.empty()) return input;
std::list<T> result;
// 基准元素放入result中
result.splice(result.begin(), input, input.begin());
// 避免遍历链表 我们取首元素作为基准元素
T const& pivot = *result.begin();
// 返回指向>=基准元素的第一个元素 【input.begin(), divide_point, input.end()】
auto divide_point = std::partition(input.begin(), input.end(), [&](T const& t) {
return t < pivot;
});
std::list<T> lower_part;
// 【input.begin(), divide_point)移动到lower_part末尾
// 将 input 中从开头到 divide_point 之前的元素移动到 lower_part 的末尾
lower_part.splice(lower_part.end(), input, input.begin(), divide_point);
// Move传入避免拷贝 结果隐式移动方式向外返回
auto new_lower(quick_sort(std::move(lower_part)));
auto new_higher(quick_sort(std::move(input)));
// 注意 基准元素之前已经放在result中
// new_higher所含元素放在基准元素之后
result.splice(result.end(), new_higher);
// new_lower 放在基准元素之前
result.splice(result.begin(), new_lower);
return result;
}
int main() {
std::list<int> input = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
auto result = quick_sort(std::move(input));
for (auto it = result.begin(); it != result.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
运用future实现并行快速排序
#include <iostream>
#include <future>
#include <vector>
#include <numeric>
#include <chrono>
#include <functional>
#include <condition_variable>
#include <mutex>
#include <list>
template<typename T>
std::list<T> parallel_quick_sort(std::list<T> input) {
if (input.empty()) return input;
std::list<T> result;
// 基准元素放入result中
result.splice(result.begin(), input, input.begin());
// 避免遍历链表 我们取首元素作为基准元素
T const& pivot = *result.begin();
// 返回指向>=基准元素的第一个元素 【input.begin(), divide_point, input.end()】
auto divide_point = std::partition(input.begin(), input.end(), [&](T const& t) {
return t < pivot;
});
std::list<T> lower_part;
// 【input.begin(), divide_point)移动到lower_part末尾
// 将 input 中从开头到 divide_point 之前的元素移动到 lower_part 的末尾
lower_part.splice(lower_part.end(), input, input.begin(), divide_point);
// Move传入避免拷贝 结果隐式移动方式向外返回
std::future<std::list<T>> new_lower(std::async(¶llel_quick_sort<T>, std::move(lower_part)));
auto new_higher(parallel_quick_sort(std::move(input)));
// 注意 基准元素之前已经放在result中
// new_higher所含元素放在基准元素之后
result.splice(result.end(), new_higher);
// new_lower 放在基准元素之前
result.splice(result.begin(), new_lower.get());
return result;
}
int main() {
std::list<int> input = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
auto result = parallel_quick_sort(std::move(input));
for (auto it = result.begin(); it != result.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
代码中,链表的前半部分的排序不再由当前线程执行,而是通过std::async()在另一个线程上操作。
然后递归调用parallel_quick_sort,并发生成多个线程,线程数=2^递归层数
注意,一旦线程库判断任务过多,std::async()的实现可能并不是在新线程上操作,而是按照同步方式生成新任务,从而减小开销。
std::partition操作耗时比较长,它是串行调用的,所以上述代码仍然有上升空间。
除了使用std::async外,可以自己实现一下spawn_task函数,包装下std::packaged_task和std::thread。
使用 std::invoke_result_t 可以更清晰地表达函数对象的返回类型,避免了使用 std::result_of 时可能出现的模板参数推导问题。
template<typename F, typename A>
std::future<std::invoke_result_t<F, A>> spawn_task(F&& f, A&& a) {
using result_type = std::invoke_result_t<F, A>;
std::packaged_task<result_type(A&&)> task(std::move(f));
std::future<result_type> res(task.get_future());
std::thread t(std::move(task), std::move(a));
t.detach();
return res;
}
可以顺着这个思路升级到复杂的实现:向队列中添加任务,由线程池中的工作线程负责运行。
文章展示了如何使用C++实现快速排序算法,首先是一个串行版本,然后是一个利用std::async进行并行处理的版本,尝试通过多线程提升排序效率。尽管std::async可能在任务过多时转为同步执行,但提出了自定义spawn_task函数以及使用线程池来优化的可能性。
2546

被折叠的 条评论
为什么被折叠?



