动态散列技术,也称为动态哈希或可扩展哈希,是一种自适应调整哈希表大小的技术。随着数据的增加或减少,动态散列技术能够自动调整哈希表的容量,以保持高效的操作性能。这种技术在处理大量动态数据时非常有用,因为它可以避免哈希冲突,并减少重新哈希的开销。
动态散列技术的特点:
- 动态调整大小:根据存储的数据量自动调整哈希表的大小。
- 负载因子:动态散列通常基于负载因子(表中元素数量与桶数量的比率)来决定何时扩展或收缩哈希表。
- 再散列:当哈希表决定扩展时,所有现有的键都需要通过新的散列函数重新散列到更大的表中。
- 性能稳定:通过动态调整大小,动态散列可以保持接近理想的平均查找时间复杂度。
动态散列技术的实现方法:
- 开放寻址法:当表中元素数量达到某个阈值时,增加哈希表的大小,并使用新的散列函数重新计算所有元素的位置。
- 链地址法:在链地址法中,哈希表的大小扩展后,只需要更新链表中节点的索引,因为链表的节点位置不依赖于哈希表的大小。
- 双重哈希法:使用两个散列函数,当第一个散列函数得到的位置上已经有元素时,使用第二个散列函数来寻找下一个空闲位置。
动态散列技术的Java实现(简单的开放寻址法):
import java.util.HashMap;
import java.util.Map;
public class DynamicHashing {
private static final int INITIAL_CAPACITY = 4;
private static final double LOAD_FACTOR_THRESHOLD = 0.75;
private int[] table;
private int size;
private double loadFactor;
public DynamicHashing() {
table = new int[INITIAL_CAPACITY];
size = 0;
loadFactor = 0.0;
}
public void insert(int key) {
int index = hash(key);
while (table[index] != 0 && table[index] != key) {
index = (index + 1) % table.length;
}
if (table[index] == 0) {
size++;
if (loadFactor >= LOAD_FACTOR_THRESHOLD) {
resize();
}
}
table[index] = key;
loadFactor = (double) size / table.length;
}
private int hash(int key) {
return key % table.length;
}
private void resize() {
int oldCapacity = table.length;
int newCapacity = oldCapacity * 2;
int[] oldTable = table;
table = new int[newCapacity];
size = 0;
loadFactor = 0.0;
for (int key : oldTable) {
if (key != 0) {
insert(key);
}
}
}
public static void main(String[] args) {
DynamicHashing dynamicHash = new DynamicHashing();
for (int i = 0; i < 10; i++) {
dynamicHash.insert(i);
}
System.out.println("Current load factor: " + dynamicHash.loadFactor);
}
}
在面试中,动态散列技术是一个重要的知识点,它考察应聘者对数据结构的理解和算法设计能力。通过实现动态散列技术,可以展示你对哈希表原理和动态数据结构的掌握程度。希望这些知识点和示例代码能够帮助你更好地准备面试!
题目 1:实现动态扩容的哈希表
描述:
设计一个哈希表,当哈希表的负载因子超过某个阈值时,自动扩容并重新散列所有元素。
示例:
插入一系列键值对,当负载因子超过0.75时,哈希表的容量加倍。
Java 源码:
import java.util.Arrays;
public class DynamicHashTable {
private static final int INITIAL_CAPACITY = 4;
private static final double LOAD_FACTOR_THRESHOLD = 0.75;
private int[] keys;
private Object[] values;
private int size;
private double loadFactor;
public DynamicHashTable() {
keys = new int[INITIAL_CAPACITY];
values = new Object[INITIAL_CAPACITY];
size = 0;
}
public void put(int key, String value) {
int index = hash(key);
for (int i = index; keys[i] != 0 && keys[i] != key; i = (i + 1) % keys.length) {
// Find empty slot or existing key
if (keys[i] == 0) {
break;
}
}
if (keys[i] == 0) {
keys[i] = key;
values[i] = value;
size++;
if (loadFactor > LOAD_FACTOR_THRESHOLD) {
resize();
}
} else {
values[i] = value; // Update existing key-value pair
}
}
private int hash(int key) {
return Math.abs(key % keys.length);
}
private void resize() {
int oldCapacity = keys.length;
int newCapacity = oldCapacity * 2;
int[] oldKeys = keys;
Object[] oldValues = values;
keys = new int[newCapacity];
values = new Object[newCapacity];
size = 0;
for (int i = 0; i < oldCapacity; i++) {
if (oldKeys[i] != 0) {
put(oldKeys[i], (String) oldValues[i]);
}
}
}
public static void main(String[] args) {
DynamicHashTable hashTable = new DynamicHashTable();
for (int i = 0; i < 12; i++) {
hashTable.put(i, "Value" + i);
}
System.out.println("Hash table size: " + hashTable.keys.length);
}
}
题目 2:解决散列冲突的链地址法
描述:
实现一个使用链地址法解决散列冲突的哈希表,并提供插入和查找操作。
示例:
插入键值对 (1, "a") 和 (1, "b"),查找键为 1 的所有值。
Java 源码:
import java.util.ArrayList;
import java.util.List;
public class ChainingHashTable {
private static final int INITIAL_CAPACITY = 4;
private List<Object>[] table;
public ChainingHashTable() {
table = new ArrayList[INITIAL_CAPACITY];
for (int i = 0; i < table.length; i++) {
table[i] = new ArrayList<>();
}
}
public void put(int key, String value) {
int index = Math.abs(key % table.length);
table[index].add(new KeyValue(key, value));
}
public List<String> get(int key) {
int index = Math.abs(key % table.length);
for (Object obj : table[index]) {
if (obj instanceof KeyValue && ((KeyValue) obj).key == key) {
return ((KeyValue) obj).value;
}
}
return null;
}
private static class KeyValue {
int key;
List<String> value;
KeyValue(int key, String value) {
this.key = key;
this.value = new ArrayList<>();
this.value.add(value);
}
}
public static void main(String[] args) {
ChainingHashTable hashTable = new ChainingHashTable();
hashTable.put(1, "a");
hashTable.put(1, "b");
System.out.println("Values for key 1: " + hashTable.get(1));
}
}
题目 3:实现哈希表的删除操作
描述:
设计一个哈希表,并提供删除操作。当删除元素时,如果该位置有多个元素,需要删除与给定键匹配的第一个元素。
示例:
哈希表中包含键值对 (1, "a") 和 (1, "b"),删除键为 1 的第一个值。
Java 源码:
import java.util.ArrayList;
import java.util.List;
public class HashTableDelete {
private static final int INITIAL_CAPACITY = 16;
private List<Object>[] table;
public HashTableDelete() {
table = (List<Object>[]) new List[INITIAL_CAPACITY];
for (int i = 0; i < table.length; i++) {
table[i] = new ArrayList<>();
}
}
public void put(int key, String value) {
int index = Math.abs(key.hashCode() % table.length);
table[index].add(new KeyValue(key, value));
}
public boolean delete(int key) {
int index = Math.abs(key.hashCode() % table.length);
for (int i = 0; i < table[index].size(); i++) {
KeyValue kv = (KeyValue) table[index].get(i);
if (kv.key == key) {
table[index].remove(i);
return true;
}
}
return false;
}
private static class KeyValue {
int key;
String value;
KeyValue(int key, String value) {
this.key = key;
this.value = value;
}
}
public static void main(String[] args) {
HashTableDelete hashTable = new HashTableDelete();
hashTable.put(1, "a");
hashTable.put(1, "b");
hashTable.put(2, "c");
hashTable.delete(1);
System.out.println("Hash table after deletion: " + Arrays.toString(hashTable.table));
}
}
这些题目和源码展示了动态散列技术在解决实际问题中的应用。在面试中,能够根据问题的特点选择合适的算法并实现其解决方案是非常重要的。希望这些示例能够帮助你更好地准备面试!