2フォーチュン構造設計RandomPool方法class5-左ベーストピック、添加してもよく、複雑さはO(1)であり、アクセス・キーを削除
1.タイトル:RandomPool構造設計は、追加することができ、複雑さはO(1)であり、アクセス・キーを削除
:RandomPool構造設計構造は、構造には、次の3つの機能を持っている
INSERT(キー):構造の鍵のほか、追加繰り返さないでください。
削除(キー):もともとAの構造にキーは削除;
getRandom():他のキー構造の確率を返します。
【要件】時間複雑挿入、削除およびgetRandom方法は、O(1)です。
簡単で2.Map
追加する要件に起因して、削除の複雑さは、地図の使用を検討して、O(1)です。
地図は、主にデータの場合、1つのマッピングのために、連想STLコンテナであります
- すべてのマップ要素はペアであります
- 最初の要素はペアのキー(キー)、インデックス内の役割を果たしている、2番目の要素は値(真の値)であります
- マップ<T1、T2>融点; //デフォルトコンストラクタをマップします。
#include<iostream>
#include<map>
#include<string>
int main()
{
//构造方式key为string类型,value为int类型
map<string,int> mm;
mm[string("www")] = 2;
mm[string("eee")] = 4;
mm.insert(pair<string,int>("rrr",7));
mm[string("ttt")] = 0;
return 0;
}
3.分析します
タイトル構造は、B、C、Dに格納されたキー値仮定 、Eのマップ構造を使用して、削除のみをO(1)の複雑さを追加し、他のリターン確率のために行うことは容易ではないが、検討以下に示すように、2つのマップと最初のマップの値のキー値を格納する第2のマップを追加同時に加えるときに、2つのマップ構造は、最初のキー値格納マップの値は、このオブジェクトによるものです値値は、MAP1の抗得キー値をMAP2。
26の総数は、値格納された値を0,1,2,3,4,5と仮定すると、等確率のリターンのために。。。図25は、ランド()関数は、0〜25の間の乱数であり、そしてあなたはMAP1のランダム鍵値を返すことができるように、MAP2から対応する値を見つけます。注ぐことが鍵であることを内部に別のものを選択する米国特許バレル、バケット、この値の値に、バレルはA.いいえeg.0あります しかし、時には削除した後、それがこの問題を解決するために、存在しないバレルのランダム外の結果である可能性があり、新たな問題の出現があった、我々は中断バレル数を確保する必要があります。削除すると、バレルバレルバレルの最大数は、削除する番号を変更します。もしBを削除するバケット番号がまだ0-24連続的であるので、実施例は、1バレル号、25 Zバレルバレル数の現在の最大数は、1に変更されます。
(1)プールの設計
上記の分析として、我々はあなたが、削除ランダムリターンで同じ増加を持つ2つのマップを削除すると、増加している、2を達成するためにマッピングする必要があり、使用することは、その値の値の目的を返すMAP2。また、サイズ記憶バケット番号が必要。
class Pool
{
public:
Pool()
{
this->size = 0;
}
void map_insert(string word);
void map_delete(string word);
void getRandom();
private:
map<string,int> keyValueMap;
map<int,string> valuekeyMap;
int size ;//桶号
};
(2)デザインを追加します
あなたがキーに存在しないMAP1キーを追加したいときMAP1の場合、通話が挿入機能が付属してマップを追加し、この時間値は、サイズのバレル、及びMAP2、キー値と値のMAP1は反対側の現在の数です。自分自身をマップ重複するキー値はイテレータが追加空で見つけた場合、加算する値を見つけるために()関数を見つけるここでは使用はできません。
void Pool::map_insert(string word)
{
//find(key)存在返回该键的元素的迭代器;不存在返回m.end();
//if(this->keyValueMap.end() != this->keyValueMap.find(word))
map<string,int>::iterator pos = keyValueMap.find(word);
if(pos == keyValueMap.end())
{
keyValueMap.insert(pair<string,int>(word,size));
valuekeyMap.insert(pair<int,string>(size++,word));
}
}
(3)削除のデザイン
マップはイテレータは、delete検索のイテレータの位置によって削除m.erase(pos)
、および削除するキーの値を指定するm.erase(key)
2種類。
下層の赤黒木マップ値のマップ値を修正することができる、及びキー値を変更することはできないからです。オリジナルのアイデアは、Cでカバーバレルの最大のグループのグループを削除する方法を出したので++作業、イテレータ最初の記録位置が削除MAP1使用を検討した後、別途、再び最終値として使用されているバレルの最大値を記録し、キー値を削除しません。 、追加、削除4つのセクションB、Z、そして最終的にはバレルの改訂番号Zの2つの部分を追加します。4つの位置決め部を削除する必要がBからMAP1ため、タイトルDELETEステートメントは、次に、delete(word)
直接ワード値を削除することができ、MAP2部に、反復子MAP1 MAP1による記録位置は、第二を識別することができますパラメータ値または1であり; Zルックアップ値はMAP2、すなわちキー値MAP1によってバケットの最大数の値をMAP1、および最終的にMAP2 25は、バレルの最大数によって直接得ることができます。
注、最初に私が直接、最後のグループ、MAP1、MAP2横必ずしも整列を削除されたリバースイテレータを使用して付与するための2つのグループを取ることができないカバーし、2つのグループを削除します。最も原始的な削除と最後の4二つの最も簡潔を追加するコード。
void Pool::map_delete(string word)
{
//map1需要删除的位置用pos记录
map<string,int> ::iterator pos = keyValueMap.find(word);
if(pos != keyValueMap.end())//表示需要删除的存在
{
//通过map2取出桶号最大的key值,再取出需要保存的桶号
string key = valuekeyMap.find(size - 1)->second;
int value = pos->second;
//删除四个map部分,分别通过迭代器、按值查找获得
keyValueMap.erase(word);
keyValueMap.erase(key);
valuekeyMap.erase(value);
valuekeyMap.erase(--size);//桶号减一
//删除的恰好是桶最大,就不需要添加,直接返回
if(word == key)
return;
this->keyValueMap.insert(pair<string,int>(key,value));
this->valuekeyMap.insert(pair<int,string>(value,key));
}
}
(4)等確率ランダム戻り設計
ランド()関数によってタブのシリアル番号を返し、次いでMAP1である第二MAP2パラメータ値キーの値を見つけます
void Pool::getRandom()
{
srand((unsigned)time(NULL));
int num = rand() % size; //0 到 size-1
cout<<valuekeyMap.find(num)->second;
}
4.完全なコード
#include<iostream>
#include<map>
#include<string>
#include<time.h>
using namespace std;
class Pool
{
public:
Pool()
{
this->size = 0;
}
void map_insert(string word);
void map_delete(string word);
void getRandom();
private:
map<string,int> keyValueMap;
map<int,string> valuekeyMap;
int size ;//桶号
};
void Pool::getRandom()
{
srand((unsigned)time(NULL));
int num = rand() % size; //0 到 size-1
cout<<valuekeyMap.find(num)->second;
}
void Pool::map_delete(string word)
{
//map1需要删除的位置用pos记录
map<string,int> ::iterator pos = keyValueMap.find(word);
if(pos != keyValueMap.end())//表示需要删除的存在
{
//通过map2取出桶号最大的key值,再取出需要保存的桶号
string key = valuekeyMap.find(size - 1)->second;//second是value值,first是key值
int value = pos->second;
//删除四个map部分,分别通过迭代器、按值查找获得
keyValueMap.erase(word);
keyValueMap.erase(key);
valuekeyMap.erase(value);
valuekeyMap.erase(--size);//桶号减一
//删除的恰好是桶最大,就不需要添加,直接返回
if(word == key)
return;
keyValueMap.insert(pair<string,int>(key,value));
valuekeyMap.insert(pair<int,string>(value,key));
}
}
void Pool::map_insert(string word)
{
//find(key)存在返回该键的元素的迭代器;不存在返回m.end();
//if(keyValueMap.end() != this->keyValueMap.find(word))
map<string,int>::iterator pos = keyValueMap.find(word);
if(pos == this->keyValueMap.end())
{
keyValueMap.insert(pair<string,int>(word,size));
valuekeyMap.insert(pair<int,string>(size++,word));
}
}
int main()
{
Pool m1;
m1.map_insert("aaa");
m1.map_insert("bbb");
m1.map_insert("ccc");
m1.map_insert("ddd");
m1.map_insert("eee");
m1.map_insert("fff");
m1.map_insert("ggg");
m1.map_insert("hhh");
m1.map_insert("iii");
m1.map_insert("jjj");
m1.map_delete("aaa");
//测试添加key相同的元素
m1.map_insert("hhh");
m1.map_delete("ggg");
//测试删除size最大数
m1.map_insert("kkk");
m1.map_delete("kkk");
m1.getRandom();
//test 使用[]可以修改value值,
map<string,int> mm;
mm[string("www")] = 2;
mm[string("www")] = 4;
mm.insert(pair<string,int>("www",7));
mm[string("www")] = 7;
system("pause");
return 0;
}