[英]Why does my hashtable not work at bigger range?
我正在研究一個使用線性地址的開放式地址的哈希表。 我正在使用標准功能,例如獲取,插入和刪除。 我的問題是,盡管這些功能對於較小的哈希表非常有效,但是當哈希表變大時,似乎出錯了。 size()沒有返回正確的值,get()也沒有返回正確的值。 對於我如何解決這些問題的任何投入,我將不勝感激。
public class SymbolTable {
private static final int INIT_CAPACITY = 7;
/* Number of key-value pairs in the symbol table */
private int N;
/* Size of linear probing table */
private int M;
/* The keys */
private String[] keys;
/* The values */
private Character[] vals;
/**
* Create an empty hash table - use 7 as default size
*/
public SymbolTable() {
this(INIT_CAPACITY);
}
/**
* Create linear probing hash table of given capacity
*/
public SymbolTable(int capacity) {
N = 0;
M = capacity;
keys = new String[M];
vals = new Character[M];
}
/**
* Return the number of key-value pairs in the symbol table
*/
public int size() {
return N;
}
/**
* Is the symbol table empty?
*/
public boolean isEmpty() {
return size() == 0;
}
/**
* Does a key-value pair with the given key exist in the symbol table?
*/
public boolean contains(String key) {
return get(key) != null;
}
/**
* Hash function for keys - returns value between 0 and M-1
*/
public int hash(String key) {
int i;
int v = 0;
for (i = 0; i < key.length(); i++) {
v += key.charAt(i);
}
return v % M;
}
/**
* Insert the key-value pair into the symbol table
*/
public void put(String key, Character val) {
int z = hash(key);
if(keys[z] == null){ //Ökar endast om platsen redan är null. lösning för att omplaceringarna från delete inte ska öka värdet
N++;
// System.out.println("stlk "+N);
}
if(key.equals(keys[z])){
vals[z]= val;
}
else
if (keys[z]!=null){
if(z == M -1){
z = 0;
}
for (int i = z; i < M; i++){
if (keys[z]!=null){
if(i == M - 1){
if(keys[i] == null){
z=i;
N++;
// System.out.println("strlk " + N);
break;
}else{
i=0;
}
}}
if(key.equals(keys[i])){
vals[i]= val;
break;
}
if(keys[i] == null){
z = i;
N++;
// System.out.println("stlk "+N);
break;
}
}
}
keys[z]=key;
vals[z]=val;
}
// dummy code
/**
* Return the value associated with the given key, null if no such value
*/
public Character get(String key) {
int index = hash(key);
while (keys[index] != null && !keys[index].equals(key)) {
index++;
if (index == M) {
index = 0;
}
}
return vals[index];
} // dummy code
/**
* Delete the key (and associated value) from the symbol table
*/
public void delete(String key) {
if (keys[hash(key)] != null){ //Kollar så att strängen faktiskt finns, så att den inte deletar pga. HASHVÄRDET av strängen finns
if(key.equals(keys[hash(key)])){
keys[hash(key)] = null;
vals[hash(key)] = null;
N --;
for (int i = 0; i < M; i++){
if(keys[i] != null && hash(keys[i]) != i){
N--;
// System.out.println("strlk "+N);
put(keys[i], vals[i]);
keys[i] = null;
vals[i] = null;
}}
} else {
for (int i = 0; i < M; i++){
if(keys[i] != null && hash(keys[i]) != i){
N--;
// System.out.println("strlk "+N);
put(keys[i], vals[i]);
keys[i] = null;
vals[i] = null;
}
if(key.equals(keys[i])){
keys[hash(key)] = null;
N --;
}
}
}
}
}
// dummy code
/**
* Print the contents of the symbol table
*/
// dummy code
/**
* Print the contents of the symbol table
*/
public void dump() {
String str = "";
for (int i = 0; i < M; i++) {
str = str + i + ". " + vals[i];
if (keys[i] != null) {
str = str + " " + keys[i] + " (";
str = str + hash(keys[i]) + ")";
} else {
str = str + " -";
}
System.out.println(str);
str = "";
}
}
}
這是測試程序用來運行它的程序。
import java.io.*;
public class SymbolTableTest2 {
public static void main(final String[] args){
final SymbolTable st = new SymbolTable(733);
final int nums = 730;
final int gap = 37;
final char[] tests = new char[nums];
int i;
System.out.println("Checking... (no more output means success)");
// Associate i (as a string) with a random printable character
for (i = gap; i != 0; i = (i + gap) % nums) {
final char ch = (char) (32 + (int) (Math.random() * ((127 - 32) + 1)));
st.put(Integer.toString(i), ch);
tests[i] = ch;
}
// Check that size() is correct
if (st.size() != nums - 1) {
System.out.println("size was() " + st.size()
+ ", should have been " + (nums - 1));
}
// Delete some entries
for (i = 1; i < nums; i += 2) {
st.delete(Integer.toString(i));
}
// Check that size is correct
if (st.size() != ((nums / 2) - 1)) {
System.out.println("size was() " + st.size()
+ ", should have been " + ((nums / 2) - 1));
}
// Delete same entries again
for (i = 1; i < nums; i += 2) {
st.delete(Integer.toString(i));
}
// Check that size is correct
if (st.size() != ((nums / 2) - 1)) {
System.out.println("size was() " + st.size()
+ ", should have been " + ((nums / 2) - 1));
}
// Check that correct entries are still in table
for (i = 2; i < nums; i += 2) {
if (st.get(Integer.toString(i)) == null
|| st.get(Integer.toString(i)) != tests[i]) {
System.out.println("get(" + i + ") was "
+ st.get(Integer.toString(i))
+ ", should have been " + tests[i]);
}
}
// Check that deleted entries really were deleted
for (i = 1; i < nums; i += 2) {
if (st.get(Integer.toString(i)) != null) {
System.out.println("get(" + i + ") was "
+ st.get(Integer.toString(i))
+ ", should have been null");
}
}
}}
您的刪除方法是錯誤的。
以下代碼片段顯示了該問題:
SymbolTable st = new SymbolTable(733);
st.put("12", 'A');
st.put("21", 'B');
st.put("13", 'C');
st.remove("13");
運行此代碼后, st
將包含兩個鍵“ 12”和“ 13”,而不是“ 12”和“ 21”。
一個問題是put
方法:如果您的密鑰已經在哈希表中,但是不在密鑰哈希碼標識的位置,則執行(put方法中第27行附近)
if(key.equals(keys[i])){
vals[i]= val;
break;
}
隨后(在put方法的末尾)
keys[z]=key;
vals[z]=val;
它會覆蓋其他隨機密鑰。
第二個問題是在delete
方法中。 您嘗試刪除並重新插入所有元素。
然而,
put(keys[i], vals[i]);
keys[i] = null;
vals[i] = null;
如果恰巧將它重新插入到同一位置,則會刪除該元素。 如果兩個元素具有相同的哈希碼,則很容易發生這種情況。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.