您的位置:首页 > 其它

键值表

2015-07-06 22:35 281 查看

什么是键值表

键值表是键值对集合,类似字典,支持存入键值对,按键查值等操作。

对外接口

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


初级实现

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实现

在上面的初级实现中,每次查询都要遍历了整个字典,效率为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");
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: