2008-09-15 6 views
7

में एक अनन्य आईडी उत्पन्न करना C++ में दो (या अधिक) छोटी चींटियों से एक अद्वितीय आईडी उत्पन्न करने का सबसे अच्छा तरीका क्या है? मैं ग्राफ में शिखर की विशिष्ट पहचान करने की कोशिश कर रहा हूं। शिखर में डेटा के रूप में दो से चार शॉर्ट इन्स होते हैं, और आदर्श रूप से आईडी उनमें से किसी प्रकार का हैश होगा। गति या आसानी से पोर्टेबिलिटी और विशिष्टता पसंद करते हैं।सी ++

यहां बहुत सारे महान उत्तर हैं, मैं आज रात उन सभी को आजमा रहा हूं ताकि यह देखने के लिए कि मेरी समस्या सबसे अच्छी तरह फिट बैठती है। मैं जो कर रहा हूं उस पर कुछ और शब्द।

ग्राफ ऑडियो फ़ाइल से नमूने का संग्रह है। मैं पुरानी फ़ाइल से एक नई ऑडियो फ़ाइल उत्पन्न करने के लिए ग्राफोव चेन के रूप में ग्राफ का उपयोग करता हूं। चूंकि प्रत्येक वर्टेक्स कुछ नमूने स्टोर करता है और दूसरे नमूने को इंगित करता है, और नमूने सभी छोटी चींटियां हैं, इसलिए डेटा से आईडी उत्पन्न करना स्वाभाविक लग रहा था। उन्हें लंबे समय तक लंबे समय तक जोड़ना अच्छा लगता है, लेकिन शायद कुछ 0 0 2 3 generateID जितना सरल हो, मुझे बस इतना चाहिए। सुनिश्चित नहीं है कि विशिष्टता की गारंटी के लिए कितना स्थान आवश्यक है, यदि प्रत्येक वर्टेक्स 2 16 बिट नमूने स्टोर करता है, तो 2^32 संभव संयोजन सही होते हैं? और इसलिए यदि प्रत्येक वर्टेक्स 4 नमूने स्टोर करता है, तो 2^64 संभावित संयोजन होते हैं?

लाइब्रेरी और प्लेटफ़ॉर्म विशिष्ट समाधान इस प्रश्न के लिए वास्तव में प्रासंगिक नहीं हैं। मैं कोई और नहीं चाहता जो मेरे प्रोग्राम को अतिरिक्त पुस्तकालयों को डाउनलोड करने या अपने ओएस के अनुरूप कोड बदलने के लिए संकलित कर सके।

उत्तर

4

एक साधारण समाधान 64 बिट पूर्णांक का उपयोग करना है जहां निचला 16 बिट पहला वर्टेक्स समन्वय है, अगले 16 बिट्स दूसरा है, और इसी तरह। यह आपके सभी शिखरों के लिए अद्वितीय होगा, हालांकि बहुत कॉम्पैक्ट नहीं है।

तो ऐसा करने के लिए यहां कुछ आधा assed कोड है। उम्मीद है कि मुझे सही जगह मिल गई है।

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; 
} 

वैकल्पिक रूप से यह एक संघ (लियोन टिमर्मन से महान विचार, टिप्पणी देखें) के साथ किया जा सकता है।बहुत साफ इस तरह से:

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

मैं वास्तव में बात करता हूं कि एक संघ केवल ऐसा करने के लिए एक क्लीनर तरीका प्रदान करेगा, लेकिन यह स्वाद का विषय है। –

+3

fyi, इस तरह के एक संघ के साथ टाइप-पनिंग अपरिभाषित व्यवहार है। – scpayson

0

खैर आईडी की गारंटी करने के लिए एक ही रास्ता क्या 2 शॉर्ट्स (यह मानते हुए 16bit) के लिए से

जैसे अपने gettings आईडी, आप एक 32 बिट पूर्णांक

का उपयोग करना चाहिए और अधिक से अधिक आईडी संयोजन है बनाने के लिए किया जाता है, अद्वितीय है
int ID = ((int)short1 << 16) | short2; 

और 4 शॉर्ट्स के लिए आप एक 64 बिट पूर्णांक, आदि की आवश्यकता होगी ...

मूल रूप से कुछ और टकराव के साथ

(कई बातें एक ही आईडी प्राप्त कर सकते हैं) काफी की गारंटी है।

हालांकि एक अलग दृष्टिकोण (जो मुझे लगता है कि बेहतर होगा) आईडी उन्हें वितरित करने के लिए किया जाएगा के रूप में कोने डाला जाता है पाने के लिए:

unsigned LastId = 0;//global 

unsigned GetNewId(){return ++LastId;} 

यह भी आप जोड़ने के लिए अधिक/विभिन्न अनुमति देने का प्रभाव पड़ता है प्रत्येक चरम पर डेटा। हालांकि यदि आप इसे रीसेट किए बिना 2^32 से अधिक शीर्षकों को बनाने की उम्मीद करते हैं, तो शायद यह सबसे अच्छी विधि नहीं है। ताकि आप सभी 4 संभावनाओं स्टोर कर सकते हैं

+0

उपयोग और हमेशा निम्न 8 बिट्स 0 के परिणामस्वरूप हमेशा परिणाम होंगे। इसे 16 और स्थानांतरित किया जाना चाहिए। – Patrick

0

लंबे लंबे समय से एक का उपयोग करें, तो प्रत्येक लघु bitshift:

((लंबे) shortNumberX) < < 0, 4, 8, या 12

वाकई डाली बनाने स्थानांतरण से पहले, या आपका डेटा अंत को छोड़ सकता है।

संपादित करें: जोड़ने के लिए भूल गए, आपको या उन्हें एक साथ करना चाहिए।

8

कभी कभी सबसे सरल बातें सबसे अच्छा काम करता है।

क्या आप वर्टेक्स ऑब्जेक्ट में केवल एक आईडी फ़ील्ड जोड़ सकते हैं और इसे निर्माण के क्रम में एक नंबर असाइन कर सकते हैं?

static int sNextId = 0; 
int getNextId() { return ++sNextId; } 
-1

कफ मैं कहना चाहता हूँ उपयोग रूढ़ अंक बंद,

id = 3 * value1 + 5 * value2 + .... + somePrime * valueN 

करें कि आप अपने आईडी अंतरिक्ष अतिप्रवाह नहीं करते हैं (लंबी? लंबे?)। चूंकि आपके पास निश्चित संख्या में मूल्य हैं, कुछ यादृच्छिक प्राइम को बकवास करें। उन्हें उत्पन्न करने से परेशान न हों, थोड़ी देर के लिए आपको जाने के लिए सूचियों में पर्याप्त उपलब्ध हैं।

हालांकि मैं सबूत पर थोड़ा स्केची हूं, शायद कोई और गणितीय मुझे हुक कर सकता है। शायद किसी संख्या के अद्वितीय प्राइम कारक बनाने के साथ कुछ करना है।

0

आप पोर्टेबिलिटी पसंद करते हैं, तो boost::tuple अच्छा है:

आप 4 मदों की एक टपल चाहेगा:

typedef boost::tuple<uint16,uint16,uint16,uint16> VertexID; 

आप इस तरह प्रदान कर सकते हैं:

VertexID id = boost::make_tuple(1,2,3,4); 

बढ़ावा tuple पहले से तुलना, समानता, आदि के लिए समर्थन है, तो कंटेनर और एल्गोरिदम में उपयोग करना आसान है।

0

प्रश्न में "आईडी" की परिभाषा वास्तव में स्पष्ट नहीं है: क्या आपको तेज़ वेरटेक्स लुकअप के लिए इसे एक कुंजी के रूप में उपयोग करने की आवश्यकता है? आप std::map के लिए एक तुलनित्र परिभाषित कर सकते हैं (उदाहरण के लिए नीचे देखें)

क्या आपको दो वर्टेक्स ऑब्जेक्ट्स के बीच समान समन्वय (लेकिन किसी अन्य क्षेत्र में अलग) के बीच अंतर करने में सक्षम होना चाहिए? कुछ 'आईडी फैक्ट्री' (सीएफआर। सिंगलटन पैटर्न) को परिभाषित करें जो उत्पन्न करता है उदा। इन्ट्स का एक अनुक्रम, वेरटेक्स वस्तुओं के मूल्यों से असंबंधित। - जिस तरह से फायर लांसर सुझाता है (लेकिन थ्रेड-सुरक्षा मुद्दों से सावधान रहें!)

मेरी राय में, समान निर्देशांक वाले दो कोष्ठक समान हैं। तो आपको अतिरिक्त आईडी की आवश्यकता क्यों होगी?

जैसे ही आप इस प्रकार पर '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); 
0

आप विंडोज पर हैं, तो आप CoCreateGUID एपीआई का उपयोग कर सकता है, लिनक्स पर आप/proc/sys/कर्नेल/यादृच्छिक/UUID उपयोग कर सकते हैं, आप भी 'libuuid' देख सकते हैं।

0

आप जिसमें आपके कोने स्टोर करने के लिए एक हैश तालिका का निर्माण कर रहे हैं, मैं तरीके टकराव से बचने के लिए की एक जोड़ी के बारे में सोच सकते हैं:

  1. इनपुट डेटा से सीधे ID उत्पन्न किसी भी बिट्स दूर फेंकने के बिना, और एक हैश तालिका का उपयोग करें जो सभी संभावित आईडी को पकड़ने के लिए पर्याप्त है। 64-बिट आईडी के साथ, उत्तरार्द्ध बेहद समस्याग्रस्त होगा: आपको एक ऐसी तालिका का उपयोग करना होगा जो आपकी आईडी की सीमा से छोटा है, इसलिए आपको टकराव से निपटना होगा। 32-बिट आईडी के साथ भी, टकराव के बिना इसे खींचने के लिए आपको 4 जीबी रैम से अधिक की आवश्यकता होगी।
  2. जैसे ही आप कोने में पढ़ते हैं, क्रमशः आईडी उत्पन्न करें। दुर्भाग्यवश, यह उनकी संभावनाओं को अद्यतन करने के लिए पहले पढ़ने वाले शीर्षकों की खोज करना बहुत महंगा बनाता है, क्योंकि अनुक्रमिक आईडी जेनरेटर हैश फ़ंक्शन नहीं है। यदि मार्कोव चेन बनाने के लिए उपयोग किए जाने वाले डेटा की मात्रा मार्कोव श्रृंखला उत्पन्न करने के लिए उपयोग की जाने वाली डेटा की मात्रा से काफी छोटी है (या यदि वे दोनों छोटे हैं), तो यह कोई समस्या नहीं हो सकती है।

वैकल्पिक रूप से, आप एक हैश तालिका कार्यान्वयन है कि आप (जैसे unordered_map/hash_map) के लिए टकराव संभालती इस्तेमाल कर सकते हैं, और अपने आवेदन के बाकी पर ध्यान केंद्रित।