我正在从XML文件导入项目。每个XML元素(FoodItem
,Person
,Order
,CoffeeRun
)都是一个类&每个元素都有一个唯一的ID(该类是唯一的)。
<person>
<id>0</id>
<name>...</name>
</person>
<FoodItem>
<id>0</id>
<name>Coffee</name>
</FoodItem>
我正在尝试开发一个子类DatabaseItem
,以确保一个类中没有2个对象具有相同的ID。你能帮助我开发一种有效的算法来帮助我,确保没有对象与另一个对象具有相同的ID吗?
我的两种方法对我来说似乎有点低效:
到目前为止,使用包含所有USED ID的静态类向量。当创建一个新的DatabaseID( int requestedID )
对象时,我通过遍历向量中的所有使用值来检查ID是否可用,以检查ID是否已经存在,我认为那是Big-O'n的速度?
使用静态类bool vector
,其中vector
的每个元素对应一个id(因此vector[1]
将对应ID为1的对象)。我通过查看vector
中的元素是否为真if ( v[nID] == true ) { // this ID is already taken }
来检查是否已经使用了ID。这似乎效率低下,因为这意味着我的vector
会占用很多记录吗?
有关高效算法的任何建议都会非常有用:
class DatabaseItem
{
public:
static unsigned int instanceCount;
DatabaseItem()
{
// Assign next available ID
}
DatabaseItem( unsigned int nID )
{
// Check that that id is not already taken
// if id is taken, look for next available id &
// give the item that id
}
private:
unsigned int uniqueID;
};
// My solution: Do you have any better ideas that ensure no objects jave the same ID?
// This seems REALLY inefficient...
class DatabaseItem
{
public:
static unsigned int instanceCount;
static vector <unsigned int> usedIDs;
DatabaseItem()
{
DatabaseItem::instanceCount++;
uniqueID = instanceCount;
usedIDs.add( instanceCount );
}
DatabaseItem( unsigned int nID )
{
if ( isIDFree( nID ) )
{
uniqueID = nID;
}
else uniqueID = nextAvailableID();
DatabaseItem::instanceCount++;
}
bool isIDFree( unsigned int nID )
{
// This is pretty slow to check EVERY element
for (int i=0; i<usedIDs.size(); i++)
{
if (usedIDs[i] == nID)
{
return false;
}
}
return true;
}
unsigned int nextAvailableID()
{
while ( true )
{
unsigned int ID = 0;
if ( isIDFree( ID ) )
{
return ID;
}
else ID++;
}
}
private:
unsigned int uniqueID;
};
// Alternate that uses boolean vector to track which ids are occupied
// This means I take 30000 boolean memory when I may not need all that
class DatabaseItem
{
public:
static unsigned int instanceCount;
static const unsigned int MAX_INSTANCES = 30000;
static vector <bool> idVector;
// Is this how I initialise a static class vector...? (note this code will be outside the class definition)
// vector <bool> DatabaseItem::idVector( MAX_INSTANCES, false );
DatabaseItem()
{
uniqueID = nextAvailableID();
idVector[uniqueID] = true;
}
DatabaseItem( unsigned int nID )
{
if ( nID >= MAX_INSTANCES )
{
// not sure how I shd handle this case?
}
if ( idVector[nID] == false )
{
uniqueID = nID;
idVector[nID] = true;
}
else
{
uniqueID = nextAvailableID();
idVector[uniqueID] = true;
}
instanceCount++;
}
unsigned int nextAvailableID()
{
for (int i=0; i<idVector.size(); i++)
{
if ( !idVector[i] )
{
return i;
}
}
return -1;
}
bool isIDFree( unsigned int nID )
{
// Note I cannot do this: Because I am using Mosync API & it doesn't support any C++ exceptions'
// I declare idVector with no size! so not idVector( 30000, false)... just idVector;
// then I allow an exception to occur to check if an id is taken
try
{
return idVector[nID];
}
catch (...)
{
return true;
}
}
private:
unsigned int uniqueID;
};
答案 0 :(得分:1)
每个bool实现一个vector<bool>
,所以它不会浪费你所假设的空间。
set<unsigned int>
是解决此问题的简单方法。 vector<bool>
更快。两者都可以使用一点内存。根据您的使用模式,还有一些其他解决方案:
unsigned int all_taken_upto_this;
与set<int>
相结合,涵盖高于all_taken_upto_this
的所有古怪ID - 从集合中移除并在可能的情况下增加计数器。
A map<unsigned int, unsigned int>
在逻辑上被视为已采用或自由序列的begin,end
。这需要花一点时间才能正确实现(在两个元素之间添加最后一个ID时合并连续的地图元素,例如。)
您可能使用预制的“稀疏位集”类型数据结构 - 我不知道任何实现OTOH。
答案 1 :(得分:0)
根据元素的数量和其他几个问题,您可能会考虑在地图中实际存储它们(或至少指向它们)。这将很容易实现,但需要一些空间。另一方面,它将为您提供id
的快速查找,如果XML中存在交叉引用,这可能是一个明显的优势。地图(假设指针)看起来像:
std::map<int, std::shared_ptr<Object> > id_map;
std::shared_ptr<Object> p( new Object( xml ) );
if ( !id_map.insert( std::make_pair( p->id, p ) ).second ) {
// failed to insert, the element is a duplicate!!!
}
答案 2 :(得分:0)
如果您没有使用整数,则可以查看GUID(全局唯一ID)。根据您使用的平台,您通常可以找到几个实用程序函数来动态生成GUID。如果使用Visual Studio,我使用了CoCreateGuid函数。
如果您被锁定为32位整数,则另一个选项选项是哈希表。如果每个XML元素都是唯一的,则散列函数可以生成唯一的散列值。根据数据集的大小,仍然存在很小的冲突概率。我使用的那个似乎与我使用的数据集具有相当低的冲突率称为Jenkins hash function