第 1 章 第 5 题 空间敏感排序问题( 扩展 ) 位向量实现
问题分析
此前实现的位向量排序需要一个有1000万位的位向量,也就是要占用大概1.2MB的存储空间。本题要求将内存需求从1.2MB限制到1MB。也就是说要用800多万位存放大约1000万个数字并完成排序( 注意是存放1000万个数字而不是表示这些数字中的某一个 )。结合实际情况分析可知,美国的电话号码不会以0或者1开头,因此0 - 1999999这个范围内的数字不用在位向量中占据位置,这样就节省了0.23 - 0.24MB的容量,满足要求。下面我们对本章第 3 题的代码进行改进,使其内存消耗严格固定在1MB之内。
代码实现
1 #include <iostream> 2 #include <fstream> 3 #include <string> 4 5 using namespace std; 6 7 // 每个整数的位数 8 #define BITSPERWORD 32 9 // 每次位移量 10 #define SHIFT 5 11 // 取模掩码 12 #define MASK 0x1F 13 // 位向量的元素个数 14 #define N 10000000 15 #define M 2000000 16 17 // #### 修改部分 #### 18 // 模拟数组( 这次只用了800万位 ) 19 int a[1 + (N-M)/BITSPERWORD]; 20 21 /* 22 * 函数功能:置位向量第i位为1 23 * 函数说明:" i>>SHIFT "等于" i/32 " 获取到位向量目标位对应的模拟数组元素的位置 24 " i & MASK "等于" i%32 " 获取到位向量目标位在对应的模拟数组元素中的位置 25 " 1<<(i & MASK) " 表示一个除了要设置的那位其他位都是0的整数 26 */ 27 void set (int i) { 28 // #### 修改部分 #### 29 // 将记录在位向量中对应的位置提前200万位 30 i -= M; 31 a[i>>SHIFT] |= (1<<(i & MASK)); 32 } 33 34 /* 35 * 函数功能:置位向量第i位为0 36 * 函数说明:" i>>SHIFT "等于" i/32 " 获取到位向量目标位对应的模拟数组元素的位置 37 " i & MASK "等于" i%32 " 获取到位向量目标位在对应的模拟数组元素中的位置 38 " 1<<(i & MASK) " 表示一个除了要清空的那位其他位都是0的整数 39 */ 40 void clr (int i) { 41 // #### 修改部分 #### 42 // 将记录在位向量中对应的位置提前200万位 43 i -= M; 44 a[i>>SHIFT] &= ~(1<<(i & MASK)); 45 } 46 47 /* 48 * 函数功能:获取位向量的第i位 49 * 函数说明:" i>>SHIFT "等于" i/32 " 获取到位向量目标位对应的模拟数组元素的位置 50 " i & MASK "等于" i%32 " 获取到位向量目标位在对应的模拟数组元素中的位置 51 " 1<<(i & MASK) " 表示一个除了要获取的那位其他位都是0的整数 52 */ 53 int tst (int i) { 54 // #### 修改部分 #### 55 // 将记录在位向量中对应的位置提前200万位 56 i -= M; 57 return a[i>>SHIFT] & (1<<(i & MASK)); 58 } 59 60 61 int main() 62 { 63 /* 64 * 清空位向量 65 */ 66 for (int i=0; i < N; i++) { 67 clr(i); 68 } 69 70 string filename; 71 cout << "输入数据文件名( 当前目录下 ):"; 72 cin >> filename; 73 74 fstream io; 75 io.open(filename.c_str()); 76 if (!io) { 77 cout << "打开文件失败" << endl; 78 return 1; 79 } 80 81 /* 82 * 根据数据文件记录给位向量赋值 83 * 赋值完了以后其实已经" 完成排序了 " 84 */ 85 int data; 86 while (io >> data) { 87 set(data); 88 } 89 90 io.close(); 91 io.clear(); 92 io.open(filename.c_str(), fstream::out | fstream::trunc); 93 94 /* 95 * 从位向量获取数据并写回数据文件 96 */ 97 for (int i=0; i <N; i++) { 98 if ( tst(i) ) { 99 io << i << " "; 100 } 101 } 102 103 io.close(); 104 105 return 0; 106 }
说明
1. 如果需要限制空间,有以下三种思路:a. 分析问题本身看看是不是可以减少待处理数据 b. 优化存储结构( 参考稀疏矩阵存储方法 ) c. 牺牲时间换取空间( 参考3 )
2. 本题给出代码执行效率和第 3 题的效率几乎一样( 很显然不做实际测试 ),这也说明了作者的那个观点 --- 很多时候获取空间未必要牺牲时间。
3. 可以采用两次排序的方法,即第一次取出前700万个记录排序,第二次取出剩下的进行排序。但由于两次读取文件,效率会降低不少。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步