簡體   English   中英

為類的每個實例分配唯一ID

[英]Assigning Unique ID's to each instance of a class

我正在從XML文件導入項目。 每個XML元素( FoodItemPersonOrderCoffeeRun )都是一個類,並且每個元素都有唯一的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的速度嗎?

  • 使用一個靜態類布爾vector ,其中的每一個元素vector對應的ID(因此vector[1]將對應於對象ID為1)。 我通過if ( v[nID] == true ) { // this ID is already taken }來檢查vector中的元素是否為真,從而檢查if ( v[nID] == true ) { // this ID is already taken } 這似乎效率低下,因為這意味着我的vector將占用很多內存,對嗎?

  • 我不熟悉在C ++中使用地圖,但也許我應該在這里使用地圖?

關於有效算法的任何建議將非常有幫助:

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

vector<bool>的實現是每個bool一位,因此不會浪費您想象的那么多空間。

set<unsigned int>是對此的簡單解決方案。 vector<bool>更快。 兩者都可能會占用一點內存。 根據您的使用方式,還有其他一些解決方案:

  • 一個unsigned int all_taken_upto_this; set<int>組合,該set<int>覆蓋所有高於all_taken_upto_this從集合中刪除並在可能的情況下增加計數器。

  • map<unsigned int, unsigned int>在邏輯上被視為采用或可用序列的begin,end 這需要花些時間才能正確實現(例如,當您在兩個元素之間添加最后一個ID時,合並連續的地圖元素)

您可能會使用預制的“稀疏位集”類型的數據結構-我不知道OTOH的任何實現。

根據元素的數量和其他一些問題,您可以考慮將它們(或至少指向它們的指針)實際存儲在地圖中。 這將很容易實現,但是會占用一些空間。 另一方面,它將為您提供按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!!!
} 

如果未鎖定使用整數,則可以查看GUID(全局唯一ID)。 根據所使用的平台,通常可以找到幾個實用程序函數來動態生成GUID。 如果使用Visual Studio,我已經使用了CoCreateGuid函數。

如果您被鎖定為32位整數,則另一個選項是哈希表。 如果每個XML元素都是唯一的,則哈希函數可以生成唯一的哈希值。 根據數據集的大小,沖突的可能性仍然很小。 我使用的那個與我處理過的數據集的碰撞率似乎很低,稱為Jenkins哈希函數

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM