返回

数据结构与映射:构建自己的Map及其底层实现

Android

概述:数据结构与映射

在计算机科学中,数据结构是指组织和存储数据的形式。数据结构是计算机程序处理和存储数据的基础。映射是一种重要的数据结构,它允许我们根据键来检索数据。在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;
    }

}