【问题】
设计一个类似hashmap的结构,
3个功能
insert(key):将某个key加入到该结构,做到不重复,
delete(key):将原本在结构中的某个key去除
getRandom():等概率随机返回结构中的任何一个key
要求:
3个功能时间复杂度为O(1), 不能遍历
【原理】
----- 借用2个Hashmap,
第一个Hashmap:Str, index
第二个Hashmap:index, Str
----- Delete函数:
为了保证,等概率返回,必须保证0~size中间没有空缺,这才能保证Math.random()等概率找到的index内部有值,
如果每次,不把最后一行的值,填补在删除了那一行,0~size上面就不会有空缺。
【代码】
// 做一个结构,类似哈希表,3个功能,但是有要求,参见Hashmap_random_01
import java.util.HashMap;
public class Hashmap_random_02 {
// 使用泛型
// Java中泛型的两个主要好处是:
// 它与java中的泛型有关。如果我提到ArrayList<String>这意味着我只能向该ArrayList添加字符串类型对象。
// 减少程序中的强制转换数,从而减少程序中潜在的错误数。
// 提高代码清晰度
public static class RandomPool<K>{
private HashMap<K, Integer> map1; // Hashmap1, 第一列是外部输入的字符串,第二列是计数用的Integer
private HashMap<Integer, K> map2; // Hashmap2, 第一列是外部输入的Integer,第二列是计数用的字符串
public int size;
// 初始化
public RandomPool() {
this.map1 = new HashMap<K, Integer>();
this.map2 = new HashMap<Integer, K>();
size = 0;
}
// insert函数
public void insert(K key) {
// 1) 分别在map1,与map2中放入新的String与对应的index),size++
if (!this.map1.containsKey(key)) { // 如果当前Hashmap1中不包含需要放进去的String,判断条件
this.map1.put(key, this.size);
this.map2.put(this.size++, key); // 把size++ 集合写了
}
}
// delete函数
public void delete(K key) {
if (this.map1.containsKey(key)) { //如果需要删除的(字符串)在Hashmap1中
// 1)获取需要删除的哪一行的index
int deleteIndex = this.map1.get(key);
// 2)获取最后一个行,index 与 值
int lastIndex = --this.size;
K lastKey = this.map2.get(lastIndex); // 获取最后一行的值,通过哈希表2,String 字符串
// 3)把最后一行的key与value,放到需要删除的那一行,进行替换
this.map1.put(lastKey, deleteIndex); //在此映射中关联指定值与指定键。如果此映射以前包含了一个该键的映射关系,则旧值被替换。
this.map2.put(deleteIndex, lastKey);
// 4)删除原来的key&与对应的value,删除最后一行的值与values
this.map1.remove(key); // 删除Hashmap1 最后一行
this.map2.remove(lastIndex); //删除 Hashmap2 最后一行
}
}
// getRandom函数,随机取返回一个东西(不考虑删除的情况,0~size中间中间有洞)
public K getRandom() {
if (size == 0) {
return null;
}
int index = (int)(Math.random()*size); //0~size上是无序的,但是要保证中间没洞
return this.map2.get(index);
}
}
public static void main(String[] args) {
RandomPool<String> pool = new RandomPool<>();
pool.insert("Liu");
pool.insert("Ha");
pool.insert("XX");
System.out.println(pool.getRandom());
System.out.println(pool.getRandom());
System.out.println(pool.getRandom());
System.out.println(pool.getRandom());
System.out.println(pool.getRandom());
}
}