在C ++中从两个(或更多)短整数生成唯一ID的最佳方法是什么?我试图唯一地识别图中的顶点。顶点包含两到四个短整数作为数据,理想情况下,ID将是它们的某种散列。优先考虑便携性和独特性,超越速度或轻松。
这里有很多很棒的答案,今晚我会尝试一下,看看最适合我的问题。关于我正在做什么的几句话。
图表是音频文件中的样本集合。我使用图形作为马尔可夫链从旧文件生成新的音频文件。由于每个顶点存储一些样本并指向另一个样本,并且样本都是短整数,因此从数据生成ID似乎很自然。将它们组合成长长的听起来不错,但也许只需要0 1 2 3 generateID
就可以了。不确定需要多少空间来保证唯一性,如果每个顶点存储2个16位样本,那么有2 ^ 32种可能的组合是否正确?所以如果每个顶点存储4个样本,那么有2 ^ 64种可能的组合?
与此问题无关的图书馆和平台特定解决方案。我不希望任何可能编译我的程序的人必须下载额外的库或更改代码以适应他们的操作系统。
答案 0 :(得分:8)
有时最简单的事情效果最好。
您是否可以在Vertex对象中添加一个id字段,并按照构造顺序为其分配一个数字?
static int sNextId = 0;
int getNextId() { return ++sNextId; }
答案 1 :(得分:5)
一个简单的解决方案是使用64位整数,其中低16位是第一个顶点坐标,接下来的16位是第二个,依此类推。这对于您的所有顶点都是唯一的,但不是很紧凑。
所以这里有一些半成品代码。希望我的演员阵容正确。
uint64_t generateId( uint16_t v1, uint16_t v2, uint16_t v3, uint16_t v4)
{
uint64_t id;
id = v1 | (((uint64_t)v2) << 16) | (((uint64_t)v3) << 32) | (((uint64_t)v4) << 48);
return id;
}
可选择这可以通过联盟完成(Leon Timmermans的好主意,见评论)。这样非常干净:
struct vertex
{
uint16_t v1;
uint16_t v2;
uint16_t v3;
uint16_t v4;
};
union vertexWithId
{
vertex v;
uint64_t id;
};
int main()
{
vertexWithId vWithId;
// Setup your vertices
vWithId.v.v1 = 2;
vWithId.v.v2 = 5;
// Your id is automatically setup for you!
std::cout << "Id is " << vWithId.id << std::endl;
return 0;
}
答案 2 :(得分:0)
保证ID唯一的唯一方法就是让你拥有更多的id组合,而不是从你获得的ID中获取ID
例如,对于2个短路(假设16位),您应该使用32位int
int ID = ((int)short1 << 16) | short2;
对于4个短裤,你需要一个64位的int等...
基本上任何其他冲突(多个东西可能会得到相同的ID)都可以保证。
然而,一个不同的方法(我认为会更好)获取id将是在插入顶点时将它们移出:
unsigned LastId = 0;//global
unsigned GetNewId(){return ++LastId;}
这也可以让您为每个顶点添加更多/不同的数据。但是,如果您希望创建超过2 ^ 32个顶点而不重置它,这可能不是最好的方法。
答案 3 :(得分:0)
使用很长的长时间,这样你就可以存储所有4种可能性,然后将每个短位移位:
((long long)shortNumberX)&lt;&lt; 0,4,8或12
确保在转移之前进行投射,否则您的数据可能会结束。
编辑:忘记添加,你应该将它们组合在一起。
答案 4 :(得分:0)
如果您更喜欢便携性,那么boost::tuple很不错:
您需要一个包含4个项目的元组:
typedef boost::tuple<uint16,uint16,uint16,uint16> VertexID;
您可以像这样分配:
VertexID id = boost::make_tuple(1,2,3,4);
boost元组已经支持比较,相等等,因此很容易在容器和算法中使用。
答案 5 :(得分:0)
问题中“ID”的定义并不是很明确:您是否需要将其用作快速Vertex查找的关键?您可以为std::map
定义比较器(参见下面的示例)
您是否需要能够区分具有相同坐标的两个Vertex对象(但在另一个字段中有所不同)?定义一些'id factory'(cfr。单例模式),它可以生成例如一系列整数,与Vertex对象的值无关。 - Fire Lancer建议的方式很多(但要注意线程安全问题!)
在我看来,两个坐标相同的顶点是相同的。那你为什么还需要额外的身份证?
只要您在此类型上定义“strict weak ordering”,就可以将其用作例如std::map
,
struct Vertex {
typedef short int Value;
Value v1, v2;
bool operator<( const Vertex& other ) const {
return v1 < other.v1 || ( v1 == other.v1 && v2 < other.v2 ) ;
};
Vertex x1 = { 1, 2 };
Vertex x2 = { 1, 3 };
Vertex y1 = { 1, 2 }; // too!
typedef std::set<Vertex> t_vertices;
t_vertices vertices;
vertices.insert( x1 );
vertices.insert( x2 );
vertices.insert( y1 ); // won't do a thing since { 1, 2 } is already in the set.
typedef std::map<Vertex, int> t_vertex_to_counter;
t_vertex_to_counter count;
count[ x1 ]++;
assert( count[x1] == 1 );
assert( count[y1] == 1 );
count[ x2 ]++;
count[ y1 ]++;
assert( count[x1] == 2 );
assert( count[y1] == 2 );
答案 6 :(得分:0)
如果你在Windows上,你可以使用CoCreateGUID API,在Linux上你可以使用/ proc / sys / kernel / random / uuid,你也可以看看'libuuid'。
答案 7 :(得分:0)
如果您正在构建一个存储顶点的哈希表,我可以考虑几种方法来避免冲突:
或者,您可以使用哈希表实现来处理冲突(例如unordered_map / hash_map),并专注于应用程序的其余部分。
答案 8 :(得分:0)
试试这个:
int generateID()
{
static int s_itemID{ 0 };
return s_itemID++; // makes copy of s_itemID,
increments the real s_itemID,
then returns the value in the copy
}
来自here。
答案 9 :(得分:0)
实现自己的散列可能很乏味,而且容易出现一些问题,当您推出或部分推出系统时,这些问题很难调试和解决。 Windows API 中已经提供了一个更好的唯一 ID 实现。您可以查看更多详情here;
https://docs.microsoft.com/en-us/windows/win32/api/guiddef/ns-guiddef-guid
答案 10 :(得分:-1)
关闭袖口我会说使用素数,
id = 3 * value1 + 5 * value2 + .... + somePrime * valueN
确保你没有溢出你的id空间(长?长?)。由于你有一个固定数量的值只是废弃一些随机素数。不要费心去生成它们,列表中有足够的内容可以让你停留一段时间。
但是,我对这个证据有点粗略,也许更多的数学家可以把我联系起来。可能与数字的唯一素数因子分解有关。