概述
问题的来源:
http://topic.csdn.net/u/20080415/10/a676aaa4-766e-4429-a86d-821f2e5ff775.html
问题描述:
有近30万个vector <int>(每个vector <int>中的值为0~179),如:
vector
<
vector
<
int
>>
a;
a[ 0 ] = {0,3,179} ;
a[ 1 ] = {} ; // 该vector为空
a[ 2 ] = {2,6,8,56,119,36} ;
a[ 3 ] = {0,3,179} ;
a[ 4 ] = {1,2,3,4,5,6,7,8,9,10...,179} ; // “满”,表示从0到179间的数均在该vector中
// ....
a[ 310000 ] = {/*...*/};
a[ 0 ] = {0,3,179} ;
a[ 1 ] = {} ; // 该vector为空
a[ 2 ] = {2,6,8,56,119,36} ;
a[ 3 ] = {0,3,179} ;
a[ 4 ] = {1,2,3,4,5,6,7,8,9,10...,179} ; // “满”,表示从0到179间的数均在该vector中
// ....
a[ 310000 ] = {/*...*/};
每个vector <int>中是没有重复的数据的。即不可能出现类似a[n]={1,3,25,25,98}中有2个25的情况。
先要对上述31万个vector <int>进行压缩,压缩原则为
- 空vector <int>删除,如a[1]
- “满”vector <int>删除,如a[4]
- 相同vector <int>删除其中一个,如a[0]和a[3]相同,则删除其中任意一个
- 互补vector <int>删除其中一个,互补的意思是两vector <int>不相交且其并集为“满”vector <int>
问题分析:
对于问题所描述的数据,不难看出,不管是 a 的各个项还是 a[n] 的各个项,都具有唯一、无序(有顺序但不重要)的典型的集合的特征。或者说,问题的目的就是要把原来的数据转换为一个集合的集合。
这里需要注意的是,根据原则 4 ,0~179 的集合具有互补等价的关系。这一点,在设计算法的时候需要注意。
以变换代替原问题的压缩,是解决这个问题的主要思路。
这里需要注意的是,根据原则 4 ,0~179 的集合具有互补等价的关系。这一点,在设计算法的时候需要注意。
以变换代替原问题的压缩,是解决这个问题的主要思路。
数据的表示:
对于集合,可以用 STL 中的 set 来实现。而对于全集较小的 0~179 的集合,更恰当的方法是用非标准的 bitset 来实现。即用 180 位的 bitset 来表示0~179是否存在与集合中。
这样整个数据大体上是这样:
其中 CompBitSet 用于比较两个 bitset ,以决定顺序以及判断是否等价。
这样整个数据大体上是这样:
set
<bitset<180>, CompBitSet>
a;
排序的问题:
由于0~179的集合具有互补等价的关系,在确定顺序和判断是否等价的时候,需要一些特别的处理。
bitset 内部是用 unsigned long 实现的,如果能充分利用这一点,无疑会大大提高比较判断的效率。
当 两个 bitset 进行比较的时候,利用互补等价的条件,将参与比较的两个 bitset 通过等价变换(补集)将特定位(比如第 0 位)转换为特定值。然后再把两个 bitset 进行高效率的数值比较(bitset具体是什么顺序并不重要,重要的是有序,不重复)。
具体的实现是:
bitset 内部是用 unsigned long 实现的,如果能充分利用这一点,无疑会大大提高比较判断的效率。
当 两个 bitset 进行比较的时候,利用互补等价的条件,将参与比较的两个 bitset 通过等价变换(补集)将特定位(比如第 0 位)转换为特定值。然后再把两个 bitset 进行高效率的数值比较(bitset具体是什么顺序并不重要,重要的是有序,不重复)。
具体的实现是:
//
--------------------------------------
// 对两个 bitset 进行数值比较
template < size_t _N >
bool operator < ( const bitset < _N > & a, const bitset < _N > & b){
size_t i;
for (i = 0 ; i <= (_N - 1 ) / 32 ;i ++ ){
if (a._W(i) != b._W(i)) return (a._W(i) < b._W(i));
}
return false ;
}
// --------------------------------------
// 用于 set 的比较类
struct CompBitSet{
bool operator ()( const itemset & a, const itemset & b) const {
return (a[0] ? ~a : a) < (b[0] ? ~b : b);
}
};
// 对两个 bitset 进行数值比较
template < size_t _N >
bool operator < ( const bitset < _N > & a, const bitset < _N > & b){
size_t i;
for (i = 0 ; i <= (_N - 1 ) / 32 ;i ++ ){
if (a._W(i) != b._W(i)) return (a._W(i) < b._W(i));
}
return false ;
}
// --------------------------------------
// 用于 set 的比较类
struct CompBitSet{
bool operator ()( const itemset & a, const itemset & b) const {
return (a[0] ? ~a : a) < (b[0] ? ~b : b);
}
};
实测:
综合前面所述,我们已经把原来的数据压缩的问题转化成数据表示的问题。只要把原来的 vector<vector<int>> 转换为 set<bitset<180>, CompBitSet>,重复的数据就会自然消除。而且,在需要的时候,仍然可以用很小的代价很方便的重构 vector<vector<int>>。
由于没有原始的数据,我这里是用随机数生成的数据进行消除等价项、检查集合构建速度的测试:
实测的结果比较满意,在我的 Athlon 550M/256M 的机子上,生成百万数据集且每条数据项按各种方式执行3次插入,实测用时5:27分钟。 相信,从 vector<vector<int>> 变换为 set<bitset<180>> 再重构 vector<vector<int>> 所需要的时间也不会长。
由于问题的主体已经解决,故原问题中的删除“空”、“满”记录其实已不重要,这里并没有着重处理。实际上,结果中只可能存在一个“空”或“满”的记录,用“item.reset();data.erase(item);”即可删除。
由于没有原始的数据,我这里是用随机数生成的数据进行消除等价项、检查集合构建速度的测试:
/*
* vector<vector<int>> 压缩
*/
#pragma warning(disable:4786)
#include < time.h >
#include < iostream >
#include < bitset >
#include < set >
#define BITLEN 180
using std::bitset;
using std:: set ;
using std::cout;
using std::endl;
// --------------------------------------
struct CompBitSet;
typedef bitset < BITLEN > itemset;
typedef set < itemset,CompBitSet > dataset;
// --------------------------------------
template < size_t _N >
bool operator < ( const bitset < _N > & a, const bitset < _N > & b){
size_t i;
for (i = 0 ; i <= (_N - 1 ) / 32 ;i ++ ){
if (a._W(i) != b._W(i)) return (a._W(i) < b._W(i));
}
return false ;
}
// --------------------------------------
struct CompBitSet{
bool operator ()( const itemset & a, const itemset & b) const {
return (a[0] ? ~a : a) < (b[0] ? ~b : b);
}
};
// --------------------------------------
void listset( const dataset & data){
dataset::const_iterator citer;
for (citer = data.begin();citer != data.end();citer ++ ){
for ( int i = 0 ;i < BITLEN;i ++ ){
if (( * citer)[i])cout << i << ' , ' ;
}
cout << endl;
}
}
// --------------------------------------
void main( void ){
dataset data;
itemset item;
srand((unsigned int )time(NULL));
cout << " Start init data " << endl;
system( " pause " );
int i,j;
time_t begtime,usetime;
begtime = time(NULL);
for (i = 0 ;i < 1000000 ;i ++ ){
item.reset();
for (j = 0 ;j < BITLEN;j ++ )
item. set (rand() % BITLEN);
data.insert(item);
data.insert(item);
data.insert( ~ item);
if ( 0 == i % 123 )cout << ' ' << i;
}
cout << " Times : " << i << endl << " End of Init " << endl;
cout << " Total items : " << data.size() << endl;
usetime = time(NULL) - begtime;
cout << " Use time : " << usetime / 60 << " : " << usetime % 60 << " ( " << usetime << " s) " << endl;
item.reset();
data.insert(item);
data.insert( ~ item);
cout << " Insert empty set and full set " << endl;
cout << " Total items : " << data.size() << endl;
data.erase(item);
cout << " Remove empty set " << endl;
cout << " Total items : " << data.size() << endl;
// listset(data);
}
* vector<vector<int>> 压缩
*/
#pragma warning(disable:4786)
#include < time.h >
#include < iostream >
#include < bitset >
#include < set >
#define BITLEN 180
using std::bitset;
using std:: set ;
using std::cout;
using std::endl;
// --------------------------------------
struct CompBitSet;
typedef bitset < BITLEN > itemset;
typedef set < itemset,CompBitSet > dataset;
// --------------------------------------
template < size_t _N >
bool operator < ( const bitset < _N > & a, const bitset < _N > & b){
size_t i;
for (i = 0 ; i <= (_N - 1 ) / 32 ;i ++ ){
if (a._W(i) != b._W(i)) return (a._W(i) < b._W(i));
}
return false ;
}
// --------------------------------------
struct CompBitSet{
bool operator ()( const itemset & a, const itemset & b) const {
return (a[0] ? ~a : a) < (b[0] ? ~b : b);
}
};
// --------------------------------------
void listset( const dataset & data){
dataset::const_iterator citer;
for (citer = data.begin();citer != data.end();citer ++ ){
for ( int i = 0 ;i < BITLEN;i ++ ){
if (( * citer)[i])cout << i << ' , ' ;
}
cout << endl;
}
}
// --------------------------------------
void main( void ){
dataset data;
itemset item;
srand((unsigned int )time(NULL));
cout << " Start init data " << endl;
system( " pause " );
int i,j;
time_t begtime,usetime;
begtime = time(NULL);
for (i = 0 ;i < 1000000 ;i ++ ){
item.reset();
for (j = 0 ;j < BITLEN;j ++ )
item. set (rand() % BITLEN);
data.insert(item);
data.insert(item);
data.insert( ~ item);
if ( 0 == i % 123 )cout << ' ' << i;
}
cout << " Times : " << i << endl << " End of Init " << endl;
cout << " Total items : " << data.size() << endl;
usetime = time(NULL) - begtime;
cout << " Use time : " << usetime / 60 << " : " << usetime % 60 << " ( " << usetime << " s) " << endl;
item.reset();
data.insert(item);
data.insert( ~ item);
cout << " Insert empty set and full set " << endl;
cout << " Total items : " << data.size() << endl;
data.erase(item);
cout << " Remove empty set " << endl;
cout << " Total items : " << data.size() << endl;
// listset(data);
}
由于问题的主体已经解决,故原问题中的删除“空”、“满”记录其实已不重要,这里并没有着重处理。实际上,结果中只可能存在一个“空”或“满”的记录,用“item.reset();data.erase(item);”即可删除。
总结:
解决这个问题的主导思想,在于选择恰当的数据结构,再配合相应的算法。就这个问题来说,关键有两个:一是用 bitset<180> 来表示数据项,二是在 bitset<180> 的基础上,设计一个高效的比较算法。
最后
以上就是大胆向日葵为你收集整理的set,bitset 的一个应用实例——数据结构和比较算法的全部内容,希望文章能够帮你解决set,bitset 的一个应用实例——数据结构和比较算法所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复