返回
数据结构与映射:构建自己的Map及其底层实现
Android
2024-01-25 00:29:05
概述:数据结构与映射
在计算机科学中,数据结构是指组织和存储数据的形式。数据结构是计算机程序处理和存储数据的基础。映射是一种重要的数据结构,它允许我们根据键来检索数据。在Java中,Map接口是映射的标准实现,提供了诸如put、get、remove等基本操作。
Java中的Map接口
Java中的Map接口定义了映射的标准操作,包括put、get、remove等。Map接口有许多实现,例如HashMap、TreeMap、LinkedHashMap等。HashMap是Java中最常用的Map实现,它使用哈希表作为底层数据结构。TreeMap使用红黑树作为底层数据结构。LinkedHashMap使用链表作为底层数据结构。
自定义Map接口
我们可以定义自己的Map接口,并使用不同的数据结构作为底层实现。这让我们可以更好地理解Map接口的原理,也可以根据自己的需求定制Map的实现。
public interface MyMap<K, V> {
V put(K key, V value);
V get(K key);
V remove(K key);
boolean containsKey(K key);
int size();
void clear();
}
使用链表实现Map
链表是一种最简单的线性数据结构。我们可以使用链表实现Map接口。
public class LinkedListMap<K, V> implements MyMap<K, V> {
private Node<K, V> head;
private int size;
private static class Node<K, V> {
K key;
V value;
Node<K, V> next;
public Node(K key, V value) {
this.key = key;
this.value = value;
}
}
@Override
public V put(K key, V value) {
Node<K, V> newNode = new Node<>(key, value);
if (head == null) {
head = newNode;
} else {
Node<K, V> curr = head;
while (curr.next != null) {
curr = curr.next;
}
curr.next = newNode;
}
size++;
return value;
}
@Override
public V get(K key) {
Node<K, V> curr = head;
while (curr != null) {
if (curr.key.equals(key)) {
return curr.value;
}
curr = curr.next;
}
return null;
}
@Override
public V remove(K key) {
Node<K, V> curr = head;
Node<K, V> prev = null;
while (curr != null) {
if (curr.key.equals(key)) {
if (prev == null) {
head = curr.next;
} else {
prev.next = curr.next;
}
size--;
return curr.value;
}
prev = curr;
curr = curr.next;
}
return null;
}
@Override
public boolean containsKey(K key) {
Node<K, V> curr = head;
while (curr != null) {
if (curr.key.equals(key)) {
return true;
}
curr = curr.next;
}
return false;
}
@Override
public int size() {
return size;
}
@Override
public void clear() {
head = null;
size = 0;
}
}
使用二分搜索树实现Map
二分搜索树是一种二叉树,其中每个节点的值都大于其左子树的所有值,并且小于其右子树的所有值。我们可以使用二分搜索树实现Map接口。
public class BinarySearchTreeMap<K extends Comparable<K>, V> implements MyMap<K, V> {
private Node<K, V> root;
private int size;
private static class Node<K, V> {
K key;
V value;
Node<K, V> left;
Node<K, V> right;
public Node(K key, V value) {
this.key = key;
this.value = value;
}
}
@Override
public V put(K key, V value) {
if (root == null) {
root = new Node<>(key, value);
size++;
return value;
}
Node<K, V> curr = root;
while (true) {
if (key.compareTo(curr.key) < 0) {
if (curr.left == null) {
curr.left = new Node<>(key, value);
size++;
return value;
}
curr = curr.left;
} else if (key.compareTo(curr.key) > 0) {
if (curr.right == null) {
curr.right = new Node<>(key, value);
size++;
return value;
}
curr = curr.right;
} else {
curr.value = value;
return value;
}
}
}
@Override
public V get(K key) {
Node<K, V> curr = root;
while (curr != null) {
if (key.compareTo(curr.key) < 0) {
curr = curr.left;
} else if (key.compareTo(curr.key) > 0) {
curr = curr.right;
} else {
return curr.value;
}
}
return null;
}
@Override
public V remove(K key) {
Node<K, V> curr = root;
Node<K, V> prev = null;
while (curr != null) {
if (key.compareTo(curr.key) < 0) {
prev = curr;
curr = curr.left;
} else if (key.compareTo(curr.key) > 0) {
prev = curr;
curr = curr.right;
} else {
if (curr.left == null) {
if (prev == null) {
root = curr.right;
} else if (curr == prev.left) {
prev.left = curr.right;
} else {
prev.right = curr.right;
}
} else if (curr.right == null) {
if (prev == null) {
root = curr.left;
} else if (curr == prev.left) {
prev.left = curr.left;
} else {
prev.right = curr.left;
}
} else {
Node<K, V> minNode = curr.right;
Node<K, V> minNodePrev = curr;
while (minNode.left != null) {
minNodePrev = minNode;
minNode = minNode.left;
}
curr.key = minNode.key;
curr.value = minNode.value;
if (minNodePrev == curr) {
minNodePrev.right = minNode.right;
} else {
minNodePrev.left = minNode.right;
}
}
size--;
return curr.value;
}
}
return null;
}
@Override
public boolean containsKey(K key) {
Node<K, V> curr = root;
while (curr != null) {
if (key.compareTo(curr.key) < 0) {
curr = curr.left;
} else if (key.compareTo(curr.key) > 0) {
curr = curr.right;
} else {
return true;
}
}
return false;
}
@Override
public int size() {
return size;
}
@Override
public void clear() {
root = null;
size = 0;
}
}