2014-03-27 96 views
0

給定三個標識符,將它們組合成一個32位值。將三個32位標識符合併爲一個32位標識符?

衆所周知,第一個標識符可能有(2^8)-1個不同的值。類似地,第二個(2^8)-1和第​​三個(2^10)-1。因此,各種標識符的總數不會超過(2^32)-1。

實施例的解決方案可能是有地圖:

  • 鍵:32位,
  • 值:8(或10)個比特。

該值將從0開始並在每次提供新標識符時遞增。

它可以做得更好嗎? (而不是3張地圖)您是否看到這個解決方案的問題?


爲了澄清,標識符可以保存範圍爲< 0,2^32的任何值。唯一給出的信息是它們的總數不會超過(2^8)-1(或10)。

標識符可以具有相同的值(它是完全隨機的)。考慮操作系統給堆分配內存的隨機源內存地址(例如,使用指針作爲標識符)。我意識到這可能會在x64系統上有所不同,但是,我希望將軍的問題解決方案與這個特定的解決方案類似。

這意味着簡單的位移是不成問題的。

+0

爲什麼不使用三個位域? – harold

+0

難道你不能只是'編碼=((b10 * 256)+ b8_1)* 256 + b8_2'然後反向解碼?應該非常高效。 –

+1

這裏需要一些說明。 3個標識符號碼是?他們有區別嗎?你能否更詳細地描述他們可以採取的價值觀的範圍(參見MichaelS'答案中的討論)。你事先知道所有不同的價值嗎? – waTeim

回答

1

你可以嘗試這樣的事情: -

#include <map> 
#include <iostream> 

class CombinedIdentifier 
{ 
public: 
    CombinedIdentifier (unsigned id1, unsigned id2, unsigned id3) 
    { 
     m_id [0] = id1; 
     m_id [1] = id2; 
     m_id [2] = id3; 
    } 

    // version to throw exception on ID not found 
    static CombinedIdentifier GetIdentifier (unsigned int id) 
    { 
     // search m_store for a value = id 
     // if found, get key and return it 
     // else....throw an exception->id not found 
    } 

    // version to return found/not found instead of throwing an exception 
    static bool GetIdentifier (unsigned int id, CombinedIdentifier &out) 
    { 
     // search m_store for a value = id 
     // if found, get key and save it to 'out' and return true 
     // else....return false 
    } 

    int operator [] (int index) { return m_id [index]; } 

    bool operator < (const CombinedIdentifier &rhs) const 
    { 
     return m_id [0] < rhs.m_id [0] ? true : 
       m_id [1] < rhs.m_id [1] ? true : 
       m_id [2] < rhs.m_id [2]; 
    } 

    bool operator == (const CombinedIdentifier &rhs) const 
    { 
     return m_id [0] == rhs.m_id [0] && 
       m_id [1] == rhs.m_id [1] && 
       m_id [2] == rhs.m_id [2]; 
    } 

    bool operator != (const CombinedIdentifier &rhs) const 
    { 
     return !operator == (rhs); 
    } 

    int GetID() 
    { 
     int 
      id; 

     std::map <CombinedIdentifier, int>::iterator 
      item = m_store.find (*this); 

     if (item == m_store.end()) 
     { 
      id = m_store.size() + 1; 
      m_store [*this] = id; 
     } 
     else 
     { 
      id = item->second; 
     }   

     return id; 
    } 

private: 
    int 
     m_id [3]; 

    static std::map <CombinedIdentifier, int> 
     m_store; 
}; 

std::map <CombinedIdentifier, int> 
    CombinedIdentifier::m_store; 

int main() 
{ 
    CombinedIdentifier 
     id1 (2, 4, 10), 
     id2 (9, 14, 1230), 
     id3 (4, 1, 14560), 
     id4 (9, 14, 1230); 

    std::cout << "id1 = " << id1.GetID() << std::endl; 
    std::cout << "id2 = " << id2.GetID() << std::endl; 
    std::cout << "id3 = " << id3.GetID() << std::endl; 
    std::cout << "id4 = " << id4.GetID() << std::endl; 
} 
+0

明亮而乾淨(比三張獨立的地圖要乾淨得多),並且容易進入。謝謝你的回答。 – hauron

+0

所以基本上它將三個數字存儲爲一個數組(它是一個96位連續內存)? – justhalf

+0

@justhalf:是的,在基本的級別上,但是OP沒有指定對它們的數量以外的ID的約束,所以如果'max(ID)'更大,比特打包可能導致數據丟失比可用的位。這種方式保留了所有三個ID。更重要的是,這三個ID可以使用一個'int'索引,儘管我剛剛注意到應該有一個簡單的方法將單個ID轉換回三個ID(將編輯答案)。 – Skizz

1

你可以通過移位和不安全的代碼來獲得。

有SO上的一篇文章:What are bitwise shift (bit-shift) operators and how do they work?

然後你就可以使用全部32位範圍的三個值

---- 8位---- | ---- 8位---- | ---- 10位---- | ----未使用的6位----

int result = firstValue << (8 + 10 + 6); 
result += secondValue << (10 + 6); 
result += thirdValue << 6; 
+0

你誤解了這個問題。這不是關於組合2個8位數字和一個10位數字。它關於組合3 32位數可以有255,255,1023不同(可能是隨機)的值。 – waTeim

+0

這個問題似乎意味着只有每個字的較低'k'位被用來指定2^k-1個值中的一個。 – chepner

+1

不是真的,標題意味着相反。如果它是措辭2^8 - 1連續值,我同意。我認爲你讀得太多了。他在談論地圖,而不是數字。否則,這是微不足道的。 – waTeim

1

我想你可以利用a Perfect Hash Function。特別是,該條中提供的鏈接似乎適用於Pearson Hashing。您甚至可以在第二篇文章中剪切並粘貼包含的C程序,除了它的輸出是64位數字而不是32位數字。但是,如果你從

for (j=0; j<8; j++) { 
    // standard Pearson hash (output is h) 

修改它稍微

for (j=0; j<4; j++) { 
    // standard Pearson hash (output is h) 

你有你需要的東西。

+0

我喜歡這個,但是,我會用Skizz的簡單方法。唯一的原因是明確的(它將被編碼,並且我不會是唯一維護它的人)。感謝您的回答和鏈接。 – hauron

+0

另一件事。如果沒有事先了解可能的輸入信息,此解決方案將無法完美散列。碰撞不幸是一個問題。好的一面是沒有共享的代碼/變量 - >簡單的多線程。選擇的解決方案將需要某種類型的互斥體... – hauron

相關問題