今天看了《編程珠璣》第二版的第一章,感覺使用位域進行數據排序挺有意思的,於是用C++寫了一下簡單的位域排序,現在來寫寫總結。
首先這篇文章的主題是簡單的位域排序,也就是說需要滿足以下的條件:
1.需要排序的數據集中不存在重複的數據;
2.對排序程序所使用的內存沒有限制。
條件限制好了,然後就可以來寫代碼了,下面的代碼均在VS2017上編寫,電腦配置爲i5-6200u + 8G ddr3 1600Mhz內存 + SATA SSD。
首先是生成需要排序的隨機數據集的代碼(生成一百萬個小於一千萬的不重複的正整數),如下所示
#include <set>
#include <random>
#include <fstream>
#include <ctime>
#include <vector>
int main()
{
std::default_random_engine dre(std::time(nullptr));
std::uniform_int_distribution<unsigned> uid(1, 10000000);
std::ofstream output_file("D:/1.txt");
std::vector<unsigned> vec_random_data;
std::set<unsigned> set_random_data;
unsigned random_data = 0;
for (size_t index = 0; index < 10000000; ++index)
{
set_random_data.insert(uid(dre));
if (set_random_data.size() >= 1000000)
{
break;
}
}
vec_random_data.assign(set_random_data.cbegin(), set_random_data.cend());
set_random_data.clear();
std::random_shuffle(vec_random_data.begin(), vec_random_data.end());
for (auto data : vec_random_data)
{
output_file << data << "\n";
}
output_file.close();
return 0;
}
然後是使用一般的排序方法的代碼,將需要排序的文件中的數據讀入內存,排序,輸出,如下所示
#include <fstream>
#include <set>
#include <chrono>
#include <iostream>
int main()
{
unsigned sort_data = 0;
std::ifstream input_file("D:/1.txt");
std::set<unsigned> set_sort_data;
auto begin_time = std::chrono::steady_clock::now();
//用時3272ms,使用34MB內存
while (input_file >> sort_data)
{
set_sort_data.insert(sort_data);
}
input_file.close();
std::ofstream output_file("D:/2.txt");
for (auto data : set_sort_data)
{
output_file << data << "\n";
}
output_file.close();
std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - begin_time).count() << "ms" << std::endl;
return 0;
}
可以看到一般的排序方法(Release模式下)在我的電腦上面所使用的內存爲34MB,花費時間爲3272ms。
最後我們來看看使用位域排序的代碼,步驟爲創建位域-按照文件中的值來設置位域中的位-按照位域中的位輸出排序後的數據,如下所示
#include <fstream>
#include <chrono>
#include <iostream>
#include <bitset>
int main()
{
unsigned sort_data = 0;
std::ifstream input_file("D:/1.txt");
std::set<unsigned> set_sort_data;
auto begin_time = std::chrono::steady_clock::now();
//用時2633ms,使用2MB內存
std::bitset<10000000> bitset_sort_data;
while (input_file >> sort_data)
{
bitset_sort_data[sort_data] = 1;
}
input_file.close();
std::ofstream output_file("D:/2.txt");
for (unsigned index = 0; index < bitset_sort_data.size(); ++index)
{
if (bitset_sort_data[index] == 1)
{
output_file << index << "\n";
}
}
output_file.close();
std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - begin_time).count() << "ms" << std::endl;
return 0;
}
可以看到位域排序的方法(Release模式下)在我的電腦上面帶來了驚人的性能提升,所使用的內存爲2MB,花費時間爲2633ms。
以上就是我對位域排序的總結,可以看到雖然位域排序有條件限制,但是所帶來的性能提升卻是令人驚喜的。
PS:上面所寫的位域排序代碼中,因爲
std::bitset<10000000> bitset_sort_data;
佔用了2MB的棧空間,但是VS2017項目默認棧空間爲1MB,所以會導致棧溢出、程序運行失敗的問題,解決的辦法爲增加VS2017項目的棧空間,詳細可查看這個博客https://blog.csdn.net/wwkaven/article/details/40713961。