-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathHashmapImplement.java
More file actions
155 lines (133 loc) · 4.97 KB
/
HashmapImplement.java
File metadata and controls
155 lines (133 loc) · 4.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import java.util.*;
//LinkedHashMap<Key,Value> maintains insertion order(keys are in order of their insertion)->uses doubly linked list to maintain order->O(1) time complexity for put , get , remove operations
//TreeMap<Key,Value> maintains sorted order of keys(keys are in natural sorted order or custom comparator order)->uses Red-Black tree(Self Balancing bst) data structure->O(log n) time complexity for put , get , remove operations
//hashset is implemented using hashmap internally->stores only keys(no values)->no duplicate keys allowed->O(1) time complexity for add , remove , contains operations
public class HashmapImplement<K, V> {
// Node stored in each bucket (LinkedList)
private class Node {
K key;
V value;
Node(K k, V v) {
this.key = k;
this.value = v;
}
}
private LinkedList<Node>[] buckets; // array of buckets
private int N = 4; // number of buckets (small as in video)
private int size = 0; // number of key-value pairs
@SuppressWarnings("unchecked")
public HashmapImplement() {
buckets = new LinkedList[N];
for (int i = 0; i < N; i++) {
buckets[i] = new LinkedList<>();
}
}
// hash function -> bucket index
private int hashFunction(K key) {
if (key == null) return 0;
return Math.abs(key.hashCode()) % N;
}
// search key in bucket 'bi'. returns index inside linked list or -1 if not found
// comparison style matches the screenshot: node.key.equals(key) while safe for nulls
private int searchInLL(K key, int bi) {
LinkedList<Node> ll = buckets[bi];
for (int i = 0; i < ll.size(); i++) {
Node node = ll.get(i);
if (node.key == key || (node.key != null && node.key.equals(key))) {
return i;
}
}
return -1;
}
// put key -> value (if key exists, replace and return old value, else return null)
public V put(K key, V value) {
int bi = hashFunction(key);
int di = searchInLL(key, bi);
if (di != -1) {
// key exists -> replace
Node node = buckets[bi].get(di);
V old = node.value;
node.value = value;
return old;
} else {
// new key -> add
buckets[bi].add(new Node(key, value));
size++;
return null;
}
}
// get value for key (null if absent)
public V get(K key) {
int bi = hashFunction(key);
int di = searchInLL(key, bi);
if (di == -1) return null;
return buckets[bi].get(di).value;
}
// remove key, return removed value or null if absent
public V remove(K key) {
int bi = hashFunction(key);
int di = searchInLL(key, bi);
if (di == -1) return null;
Node node = buckets[bi].remove(di);
size--;
return node.value;
}
public boolean containsKey(K key) {
int bi = hashFunction(key);
return searchInLL(key, bi) != -1;
}
public int size() {
return size;
}
// debugging print
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("{");
boolean first = true;
for (LinkedList<Node> bucket : buckets) {
for (Node n : bucket) {
if (!first) sb.append(", ");
sb.append(String.valueOf(n.key)).append("=").append(String.valueOf(n.value));
first = false;
}
}
sb.append("}");
return sb.toString();
}
public ArrayList<K> keySet() {
ArrayList<K> keys = new ArrayList<>();
// go through each bucket
for (int i = 0; i < buckets.length; i++) {
LinkedList<Node> ll = buckets[i];
// go through each node inside the bucket
for (Node node : ll) {
keys.add(node.key);
}
}
return keys;
}
// small test
public static void main(String[] args) {
HashmapImplement<String, Integer> map = new HashmapImplement<>();
map.put("apple", 10);
map.put("banana", 20);
map.put("mango", 30);
map.put(null, 99); // null key supported (goes to bucket 0)
map.put("apple", 11); // replace value
System.out.println("Map: " + map);
System.out.println("get(mango): " + map.get("mango"));
System.out.println("get(null): " + map.get(null));
System.out.println("contains(banana): " + map.containsKey("banana"));
System.out.println("remove(banana): " + map.remove("banana"));
System.out.println("Map after remove: " + map);
System.out.println("size: " + map.size());
ArrayList<String> keys = map.keySet();
System.out.println("Keys: " + keys);
ArrayList<Integer> values = new ArrayList<>();
for (String key : keys) {
values.add(map.get(key));
}
System.out.println("Values: " + values);
}
}