最近在看一本计算机经典著作《编程珠玑 第2版》,第一章开篇谈到怎样在内存有限的情况下给一个磁盘文件排序,文中使用到了位向量来解决此问题,本人菜鸟觉得此方法很经典,遂在此总结一下,方便日后查阅。
所谓位排序,即是将位向量中的每一位与一个待排序的整数相关联,位向量中待排序整数值的位置1,位向量的位数大于等于待排序整数的最大值,如:要对13, 9, 15, 8, 3,,12,7进行排序,则可以使用一个16位的位向量1011 0011 1000 1000来对这些要排序的整数进行标识,即:第3位(从0开始)的1代表要排序的整数3,第7位的1代表待排序的整数7....。标识完后,然后通过一个迭代对位向量的每一位(从左到又,或从右到左)进行判断,如果为1,即输出当前的迭代值(即为待排序的整数值),迭代完成后输出的序列即为排序后的序列。
要实现位排序,需要以下三个步骤:
1、首先实现一个位向量;
2、将待排序整数序列映射到位向量;
3、迭代判断位向量的每一位(从左到右或从右到左),如果为1,则输出当前迭代值(即为待排序的整数值)。
1、位向量的实现:
即实现位向量的置位、清零、判断这3个操作。
/--------------------------------------------------------.h 文件------------------------------------------------------------------------------------------/
#ifndef _CBITMAP_H_
#define _CBITMAP_H_
#define BITPERWORD 32 // 本例使用整形数组实现位向量,整形占4byte=32bit
#define SHIFT 5 // 判断当前要置位或清零的位位于哪个数组中,即确定数组的下标
#define MASK 0x1F // 置位清零掩码,cpp文件中将对将对该掩码进行说明
class CBitMap
{
// construct、deconstruc
public:
CBitMap(unsigned int BitNum);
~CBitMap();
public:
int *a; // 位向量指针
public:
void set(int i); // 位向量第i位置1
void clr(int i); // 位向量第i位清0
bool test(int i); // 位向量第i位是否为1,是,返回TRUE,否,返回FALSE
};
#endif
/-----------------------------------------------------------------------------------------.cpp文件-----------------------------------------------------------------------------------------------------/
#include "stdafx.h"
#include <memory>
#include "CBitMap.h"
// BitNum: 待排序整数的最大值
CBitMap::CBitMap(unsigned int BitNum)
{
a = new int [BitNum/BITPERWORD + 1]; // 将整形数组看成一个位向量 假设待排序的整数的最大值为100,则100/32+1 = 4,即用数组a[4](共128位)即 可表示所有待排序的整数,其中a[0]代表低32位,a[1]代表次低32位,a[2]代表次高32位,a[3]代表高32位。
}
CBitMap::~CBitMap()
{
delete []a;
a = NULL;
}
// 将位向量第i位置1
void CBitMap::set(int i)
{
a[i>>SHIFT] |= (1<<(i&MASK)); // i>>SHIFT===> i>>5 <===> i/32,即判断第i位在数组中的下标。i&MASK===>i&0x1f <===> i%32,如:i=