鍵值表
阿新 • • 發佈:2017-07-25
scrip ride pac else data -s code == spl
什麽是鍵值表
鍵值表是鍵值對集合,相似字典,支持存入鍵值對,按鍵查值等操作。
對外接口
public void put(Key key, Value val);
public Value get(Key key);
public boolean contains(Key key);
public Value remove(Key key);
public int size();
public boolean isEmpty();
接口代碼
public interface IMap<Key, Value> {
/**
* 存入鍵值對
*
* @param key
* 鍵
* @param value
* 值
*/
public void put(Key key, Value value);
/**
* 按鍵查值
*
* @param key
* 鍵
* @return 值
*/
public Value get(Key key);
/**
* 推斷是否包括某鍵
*
* @param key
* 鍵
* @return <code>true</code> 若包括;否則,<code>false</code>
*/
public boolean contains(Key key);
/**
* 刪除鍵為key的鍵值對
*
* @param key
* 鍵
*/
public Value remove(Key key);
/**
* 返回鍵值對個數
*
* @return 鍵值對個數
*/
public int size();
/**
* 推斷鍵值表是否為空
*
* @return <code>true</code> 假設鍵值表為空;否則,<code>false</code>。
*/
public boolean isEmpty();
}
0基礎實現
package com.gmail.dailyefforts.ds;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class SimpleLinkedMap<Key, Value> implements IMap<Key, Value>{
private class Node {
private Node prev;
private Key key;
private Value val;
private Node next;
public Node(Node prev, Key key, Value val, Node next) {
this.prev = prev;
this.key = key;
this.val = val;
this.next = next;
}
@Override
public String toString() {
return String.format("%s=%s", String.valueOf(key),
String.valueOf(val));
}
}
private int size;
private Node first;
private Node last;
@Override
public void put(Key key, Value val) {
for (Node x = first; x != null; x = x.next) {
if (key.equals(x.key)) {
x.val = val;
return;
}
}
Node oldLast = last;
last = new Node(last, key, val, null);
if (oldLast != null) {
oldLast.next = last;
}
size++;
if (first == null) {
first = last;
}
}
@Override
public Value remove(Key key) {
for (Node x = first; x != null; x = x.next) {
if (key.equals(x.key)) {
if (x.prev == null) {
first = x.next;
} else {
x.prev.next = x.next;
}
if (x.next == null) {
last = x.prev;
} else {
x.next.prev = x.prev;
}
size--;
return x.val;
}
}
return null;
}
@Override
public boolean contains(Key key) {
return get(key) != null;
}
@Override
public Value get(Key key) {
for (Node x = first; x != null; x = x.next) {
if (key.equals(x.key)) {
return x.val;
}
}
return null;
}
@Override
public int size() {
return size;
}
@Override
public boolean isEmpty() {
return size() == 0;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(‘{‘);
for (Node x = first; x != null; x = x.next) {
builder.append(x);
if (x.next != null) {
builder.append(", ");
}
}
builder.append(‘}‘);
return builder.toString();
}
public static void main(String[] args) {
final int N = 100 * 100;
SimpleLinkedMap<Integer, String> map = new SimpleLinkedMap<>();
Map<Integer, String> map2 = new HashMap<>();
for (int i = 0; i < N; i++) {
Integer key = Integer.valueOf(i);
String value = "item-" + i;
map2.put(key, value);
map.put(key, value);
}
// System.out.println(map2);
// System.out.println(map);
Random random = new Random(System.currentTimeMillis());
for (int i = 0; i < N / 2; i++) {
final int key = random.nextInt(N);
final String a = map.remove(key);
final String b = map2.remove(key);
if (a == null) {
assert (b == null);
} else {
assert (a.equals(b));
}
}
assert(map.size() == map2.size());
for (int i = 0; i < N; i++) {
final String a = map.get(i);
final String b = map2.get(i);
if (a == null) {
assert (b == null);
} else {
assert (a.equals(b));
}
}
}
}
Hash實現
在上面的0基礎實現中。每次查詢都要遍歷了整個字典。效率為O(n)。現實中,我們從字典中查詢某個單詞時。我們借助索引來提高效率。而不是從該字典收錄的第一個詞開始逐個遍歷整個字典。
我們能夠利用hash來建立索引,遇到索引同樣時再用鏈表存儲。
package com.gmail.dailyefforts.ds;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class MyHashMap<Key, Value> implements IMap<Key, Value> {
private int size;
private static final int M = 100 * 100;
private SimpleLinkedMap<Key, Value>[] a = (SimpleLinkedMap<Key, Value>[]) new SimpleLinkedMap[M];
@Override
public void put(Key key, Value value) {
SimpleLinkedMap<Key, Value> map = map(key);
if (!map.contains(key)) {
size++;
}
map.put(key, value);
}
private int hash(Key key) {
// [0, M]
return key.hashCode() & 0x7fffffff % M;
}
private SimpleLinkedMap<Key, Value> map(Key key) {
int index = hash(key);
if (a[index] == null) {
a[index] = new SimpleLinkedMap<Key, Value>();
}
return a[index];
}
@Override
public Value get(Key key) {
return map(key).get(key);
}
@Override
public boolean contains(Key key) {
return map(key).contains(key);
}
@Override
public Value remove(Key key) {
Value value = map(key).remove(key);
if (value != null) {
size--;
}
return value;
}
@Override
public int size() {
return this.size;
}
@Override
public String toString() {
return super.toString();
}
@Override
public boolean isEmpty() {
return size() == 0;
}
public static void main(String[] args) {
final int N = 100 * 100 * 100;
MyHashMap<Integer, String> map = new MyHashMap<>();
Map<Integer, String> mapRef = new HashMap<>();
for (int i = 0; i < N; i++) {
Integer key = Integer.valueOf(i);
String value = "item-" + i;
map.put(key, value);
mapRef.put(key, value);
}
assert(map.size() == mapRef.size());
Random random = new Random(System.currentTimeMillis());
for (int i = 0; i < N / 2; i++) {
final int key = random.nextInt(N);
assert (map.contains(key) == mapRef.containsKey(key));
final String a = map.remove(key);
final String b = mapRef.remove(key);
if (a == null) {
assert (b == null);
} else {
assert (a.equals(b));
}
}
assert (map.size() == mapRef.size());
for (int i = 0; i < N; i++) {
final int key = random.nextInt(N);
final String a = map.get(key);
final String b = mapRef.get(key);
if (a == null) {
assert (b == null);
} else {
assert (a.equals(b));
}
}
System.out.println("test passed");
}
}
鍵值表