|

楼主 |
发表于 2024-11-13 17:23:30
|
显示全部楼层
对正整数排序即可,用位运算再优化一下。
明白了!我们可以通过位运算来进一步优化基数排序。这里是一个使用位运算进行优化的并行基数排序示例:
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
// 获取最大数以确定基数排序的最大位数
int getMax(const std::vector<int>& arr) {
return *std::max_element(arr.begin(), arr.end());
}
// 基数排序中的计数排序步骤
void countSort(std::vector<int>& arr, int exp) {
int n = arr.size();
std::vector<int> output(n);
int count[10] = {0};
// 统计次数
for (int i = 0; i < n; i++) {
count[(arr[i] / exp) % 10]++;
}
// 将计数累加
for (int i = 1; i < 10; i++) {
count[i] += count[i - 1];
}
// 生成输出数组
for (int i = n - 1; i >= 0; i--) {
output[count[(arr[i] / exp) % 10] - 1] = arr[i];
count[(arr[i] / exp) % 10]--;
}
// 将输出数组拷贝回原数组
for (int i = 0; i < n; i++) {
arr[i] = output[i];
}
}
void parallelCountSort(std::vector<int>& arr, int exp) {
int n = arr.size();
std::vector<int> output(n);
int count[10] = {0};
int max_threads = std::thread::hardware_concurrency();
std::vector<std::thread> threads;
auto countFunction = [&](int start, int end) {
for (int i = start; i < end; i++) {
int index = (arr[i] / exp) & 9;
std::unique_lock<std::mutex> lock(mtx);
count[index]++;
}
};
int chunk_size = (n + max_threads - 1) / max_threads;
for (int i = 0; i < max_threads; i++) {
int start = i * chunk_size;
int end = std::min(start + chunk_size, n);
threads.emplace_back(countFunction, start, end);
}
for (auto& t : threads) {
if (t.joinable()) {
t.join();
}
}
// 将计数累加
for (int i = 1; i < 10; i++) {
count[i] += count[i - 1];
}
threads.clear();
auto sortFunction = [&](int start, int end) {
for (int i = end - 1; i >= start; i--) {
int index = (arr[i] / exp) & 9;
std::unique_lock<std::mutex> lock(mtx);
output[count[index] - 1] = arr[i];
count[index]--;
}
};
for (int i = 0; i < max_threads; i++) {
int start = i * chunk_size;
int end = std::min(start + chunk_size, n);
threads.emplace_back(sortFunction, start, end);
}
for (auto& t : threads) {
if (t.joinable()) {
t.join();
}
}
// 将输出数组拷贝回原数组
for (int i = 0; i < n; i++) {
arr[i] = output[i];
}
}
// 基数排序主函数
void radixSort(std::vector<int>& arr) {
int max = getMax(arr);
// 按位数进行计数排序
for (int exp = 1; max / exp > 0; exp *= 10) {
parallelCountSort(arr, exp);
}
}
int main() {
std::vector<int> arr = {170, 45, 75, 90, 802, 24, 2, 66};
radixSort(arr);
std::cout << "Sorted array: ";
for (int num : arr) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
在这个实现中,我们用位运算替代了取模运算,以提高性能。具体来说,使用& 9(即取% 10的效果)来计算每个位上的数字,从而优化了基数排序的速度。同时,我们继续使用C++标准库中的并发控制机制来实现并行处理。
希望这个优化版的基数排序对你有所帮助!如果还有其他需求或问题,尽管告诉我。
对10取模优化掉,用256个队列
明白了,我们可以用每字节8位的位运算和256个队列来优化基数排序。这样,我们每次处理一个字节,从而避开10取模运算。以下是优化后的代码:
#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
// 获取最大数以确定基数排序的最大位数
int getMax(const std::vector<int>& arr) {
return *std::max_element(arr.begin(), arr.end());
}
// 基数排序中的计数排序步骤
void countSort(std::vector<int>& arr, int exp) {
int n = arr.size();
std::vector<std::queue<int>> buckets(256);
// 统计次数并放入对应的桶中
for (int i = 0; i < n; i++) {
int bucketIndex = (arr[i] >> exp) & 0xFF;
buckets[bucketIndex].push(arr[i]);
}
// 将桶中的元素按顺序放回原数组
int index = 0;
for (int i = 0; i < 256; i++) {
while (!buckets[i].empty()) {
arr[index++] = buckets[i].front();
buckets[i].pop();
}
}
}
// 基数排序主函数
void radixSort(std::vector<int>& arr) {
int max = getMax(arr);
int maxBit = 0;
// 确定最大位数
while (max >> maxBit) {
maxBit += 8;
}
// 按每字节进行计数排序
for (int exp = 0; exp < maxBit; exp += 8) {
countSort(arr, exp);
}
}
int main() {
std::vector<int> arr = {170, 45, 75, 90, 802, 24, 2, 66};
radixSort(arr);
std::cout << "Sorted array: ";
for (int num : arr) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
这个版本的基数排序使用每次处理一个字节(8位)的方式,将整数分成256个桶(使用队列实现)。通过位运算(arr[i] >> exp) & 0xFF来提取每字节的值,从而避免了模运算,提高了算法的性能。希望这个优化版的基数排序对你有帮助!如果有任何其他问题或需求,请随时告诉我。
不要用queue,避免动态开销
明白了,我们将不使用队列,避免动态内存分配,直接在数组中进行操作来减少开销。以下是使用静态数组的优化版本:
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
// 获取最大数以确定基数排序的最大位数
int getMax(const std::vector<int>& arr) {
return *std::max_element(arr.begin(), arr.end());
}
// 基数排序中的计数排序步骤
void countSort(std::vector<int>& arr, int exp) {
int n = arr.size();
std::vector<int> output(n);
int count[256] = {0};
// 统计次数
for (int i = 0; i < n; i++) {
int index = (arr[i] >> exp) & 0xFF;
count[index]++;
}
// 将计数累加
for (int i = 1; i < 256; i++) {
count[i] += count[i - 1];
}
// 生成输出数组
for (int i = n - 1; i >= 0; i--) {
int index = (arr[i] >> exp) & 0xFF;
output[--count[index]] = arr[i];
}
// 将输出数组拷贝回原数组
for (int i = 0; i < n; i++) {
arr[i] = output[i];
}
}
// 基数排序主函数
void radixSort(std::vector<int>& arr) {
int max = getMax(arr);
int maxBit = 0;
// 确定最大位数
while (max >> maxBit) {
maxBit += 8;
}
// 按每字节进行计数排序
for (int exp = 0; exp < maxBit; exp += 8) {
countSort(arr, exp);
}
}
int main() {
std::vector<int> arr = {170, 45, 75, 90, 802, 24, 2, 66};
radixSort(arr);
std::cout << "Sorted array: ";
for (int num : arr) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
这个版本使用静态数组count来避免动态内存分配,从而减少了动态开销。通过直接操作数组,提高了基数排序的效率。希望这个优化版对你有帮助!如果还有其他需求或问题,请随时告诉我。
// 将输出数组拷贝回原数组 for (int i = 0; i < n; i++) { arr[i] = output[i]; } 这里用成员函数swap避免复制
明白了,我们可以使用std::vector的swap成员函数来避免复制输出数组。以下是优化后的代码:
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
// 获取最大数以确定基数排序的最大位数
int getMax(const std::vector<int>& arr) {
return *std::max_element(arr.begin(), arr.end());
}
// 基数排序中的计数排序步骤
void countSort(std::vector<int>& arr, int exp) {
int n = arr.size();
std::vector<int> output(n);
int count[256] = {0};
// 统计次数
for (int i = 0; i < n; i++) {
int index = (arr[i] >> exp) & 0xFF;
count[index]++;
}
// 将计数累加
for (int i = 1; i < 256; i++) {
count[i] += count[i - 1];
}
// 生成输出数组
for (int i = n - 1; i >= 0; i--) {
int index = (arr[i] >> exp) & 0xFF;
output[--count[index]] = arr[i];
}
// 使用swap避免复制
arr.swap(output);
}
// 基数排序主函数
void radixSort(std::vector<int>& arr) {
int max = getMax(arr);
int maxBit = 0;
// 确定最大位数
while (max >> maxBit) {
maxBit += 8;
}
// 按每字节进行计数排序
for (int exp = 0; exp < maxBit; exp += 8) {
countSort(arr, exp);
}
}
int main() {
std::vector<int> arr = {170, 45, 75, 90, 802, 24, 2, 66};
radixSort(arr);
std::cout << "Sorted array: ";
for (int num : arr) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
在这个实现中,我们使用std::vector的swap成员函数将output数组和arr数组交换,避免了复制操作,提高了效率。希望这个优化对你有帮助!如果还有其他问题或需求,请随时告诉我。
继续优化,对64位uint64_t进行排序
为了对64位无符号整数 (uint64_t) 进行高效排序,我们可以针对每个字节(8位)进行处理,并使用256个桶来避免模运算。以下是优化后的代码:
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdint>
// 获取最大数以确定基数排序的最大位数
uint64_t getMax(const std::vector<uint64_t>& arr) {
return *std::max_element(arr.begin(), arr.end());
}
// 基数排序中的计数排序步骤
void countSort(std::vector<uint64_t>& arr, int exp) {
int n = arr.size();
std::vector<uint64_t> output(n);
int count[256] = {0};
// 统计次数
for (int i = 0; i < n; i++) {
int index = (arr[i] >> exp) & 0xFF;
count[index]++;
}
// 将计数累加
for (int i = 1; i < 256; i++) {
count[i] += count[i - 1];
}
// 生成输出数组
for (int i = n - 1; i >= 0; i--) {
int index = (arr[i] >> exp) & 0xFF;
output[--count[index]] = arr[i];
}
// 使用swap避免复制
arr.swap(output);
}
// 基数排序主函数
void radixSort(std::vector<uint64_t>& arr) {
uint64_t max = getMax(arr);
int maxBit = 0;
// 确定最大位数
while (max >> maxBit) {
maxBit += 8;
}
// 按每字节进行计数排序
for (int exp = 0; exp < maxBit; exp += 8) {
countSort(arr, exp);
}
}
int main() {
std::vector<uint64_t> arr = {170, 45, 75, 90, 802, 24, 2, 66, 12345678901234567890ULL};
radixSort(arr);
std::cout << "Sorted array: ";
for (uint64_t num : arr) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
这个实现针对64位无符号整数 (uint64_t) 进行优化,使用每字节8位(256个桶)进行排序,并通过位运算来提取每字节的值。此外,使用std::vector的swap成员函数避免了复制操作,提高了效率。希望这个优化版对你有帮助!如果还有其他问题或需求,请随时告诉我。
getMax能否去掉?
是的,我们可以去掉getMax函数。相反,我们可以直接对所有64位无符号整数的每个字节进行排序,因为无论数组中的数值多大,每个数的位数是固定的(64位)。这样我们就可以遍历固定的字节数(8个字节),避免使用getMax来确定最大位数。以下是优化后的代码:
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdint>
// 基数排序中的计数排序步骤
void countSort(std::vector<uint64_t>& arr, int exp) {
int n = arr.size();
std::vector<uint64_t> output(n);
int count[256] = {0};
// 统计次数
for (int i = 0; i < n; i++) {
int index = (arr[i] >> exp) & 0xFF;
count[index]++;
}
// 将计数累加
for (int i = 1; i < 256; i++) {
count[i] += count[i - 1];
}
// 生成输出数组
for (int i = n - 1; i >= 0; i--) {
int index = (arr[i] >> exp) & 0xFF;
output[--count[index]] = arr[i];
}
// 使用swap避免复制
arr.swap(output);
}
// 基数排序主函数
void radixSort(std::vector<uint64_t>& arr) {
// 由于uint64_t是64位,所以处理8字节即可
for (int exp = 0; exp < 64; exp += 8) {
countSort(arr, exp);
}
}
int main() {
std::vector<uint64_t> arr = {170, 45, 75, 90, 802, 24, 2, 66, 12345678901234567890ULL};
radixSort(arr);
std::cout << "Sorted array: ";
for (uint64_t num : arr) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
在这个实现中,我们直接对每个字节进行基数排序(总共8个字节),从而避免使用getMax函数。这样可以进一步简化代码,同时提高排序效率。希望这个版本能满足你的需求!如果有任何其他问题或需求,请随时告诉我。
用C++的并行机制,对以上进行并行
明白了,我们可以用C++的并发控制机制对代码进行并行化。我们将使用std::thread和std::mutex来实现并行处理。以下是优化后的并行基数排序代码:
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdint>
#include <thread>
#include <mutex>
std::mutex mtx;
// 基数排序中的计数排序步骤
void countSort(std::vector<uint64_t>& arr, int exp) {
int n = arr.size();
std::vector<uint64_t> output(n);
int count[256] = {0};
// 统计次数
for (int i = 0; i < n; i++) {
int index = (arr[i] >> exp) & 0xFF;
count[index]++;
}
// 将计数累加
for (int i = 1; i < 256; i++) {
count[i] += count[i - 1];
}
// 多线程生成输出数组
auto sortFunction = [&](int start, int end) {
for (int i = end - 1; i >= start; i--) {
int index = (arr[i] >> exp) & 0xFF;
std::lock_guard<std::mutex> lock(mtx);
output[--count[index]] = arr[i];
}
};
int max_threads = std::thread::hardware_concurrency();
int chunk_size = (n + max_threads - 1) / max_threads;
std::vector<std::thread> threads;
for (int i = 0; i < max_threads; i++) {
int start = i * chunk_size;
int end = std::min(start + chunk_size, n);
threads.emplace_back(sortFunction, start, end);
}
for (auto& t : threads) {
if (t.joinable()) {
t.join();
}
}
// 使用swap避免复制
arr.swap(output);
}
// 基数排序主函数
void radixSort(std::vector<uint64_t>& arr) {
// 由于uint64_t是64位,所以处理8字节即可
for (int exp = 0; exp < 64; exp += 8) {
countSort(arr, exp);
}
}
int main() {
std::vector<uint64_t> arr = {170, 45, 75, 90, 802, 24, 2, 66, 12345678901234567890ULL};
radixSort(arr);
std::cout << "Sorted array: ";
for (uint64_t num : arr) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
在这个实现中,我们使用std::thread来并行化生成输出数组的步骤,并使用std::mutex来确保线程安全。通过这种方法,我们可以充分利用多核处理器的能力,提高排序的性能。希望这个版本能满足你的需求!如果还有其他问题或需求,请随时告诉我。
还有待优化,按照最大并发量进行分块,不用加锁,各自分别排序,然后归并成一个整体有序序列,用recursive_mutex保证归并安全。
[...Copilot长时间无响应...]
你还能优化吗?
[...Copilot长时间无响应...] |
|