玩转数据结构之Java基于链表和二分搜索树实现Map映射

前言

前面我们分别实现了链表以及二分搜索树数据结构,在这里我们将基于之前实现的链表以及二分搜索树来实现Map数据结构;

代码实现

  • 定义Map通用接口;
/**
 * @author Map接口
 * on 2023/2/7
 */
public interface Map<K, V> {
    /**
     * 添加键值对
     *
     * @param key
     * @param value
     */
    void add(K key, V value);

    /**
     * 根据key删除对应的value
     *
     * @param key
     */
    V remove(K key);

    /**
     * 判断是否包含某个key
     *
     * @param key
     * @return
     */
    boolean contains(K key);

    /**
     * 根据key获取对应的value
     *
     * @param key
     * @return
     */
    V get(K key);

    /**
     * 根据key覆盖对应的value
     *
     * @param key
     * @param newValue
     */
    void set(K key, V newValue);

    /**
     * 获取Map集合大小
     *
     * @return
     */
    int getSize();

    /**
     * 判断当前Map集合是否为空
     *
     * @return
     */
    boolean isEmpty();
}

  • 基于链表实现Map映射;
package com.sjgd.map;

import androidx.annotation.NonNull;

/**
 * @author 基于链表结构的Map
 * on 2023/2/7
 */
public class LinkedListMap<K, V> implements Map<K, V> {


    private class Node {
        K key;
        V value;
        private Node next;

        public Node() {
        }

        public Node(K key, V value) {
            this.key = key;
            this.value = value;
        }

        public Node(K key, V value, Node next) {
            this.key = key;
            this.value = value;
            this.next = next;
        }

        public Node(K key) {
            this.key = key;
        }

        @NonNull
        @Override
        public String toString() {
            return key.toString() + ":" + value.toString();
        }
    }

    private Node dummyHead;
    private int size;

    public LinkedListMap() {
        dummyHead = new Node();
    }


    private Node getNode(K key) {
        Node current = dummyHead.next;
        while (current != null) {
            if (current.key.equals(key)) {
                return current;
            }
            current = current.next;
        }
        return null;
    }

    @Override
    public void add(K key, V value) {
        Node queryNode = getNode(key);
        if (queryNode == null) {
            // 根据key没有查到有对应的键值对,直接插入到链表头部
            dummyHead.next = new Node(key, value, dummyHead.next);
            size++;
        } else {
            queryNode.value = value;
        }

    }

    @Override
    public V remove(K key) {
        Node prev = dummyHead;
        while (prev.next != null) {
            if (prev.next.key.equals(key)) {
                break;
            }
            prev = prev.next;
        }
        if (prev.next != null) {
            Node delNode = prev.next;
            prev.next = delNode.next;
            delNode.next = null;
            size--;
            return delNode.value;
        }
        return null;
    }

    @Override
    public boolean contains(K key) {
        return getNode(key) != null;
    }

    @Override
    public V get(K key) {
        return getNode(key) == null ? null : getNode(key).value;
    }

    @Override
    public void set(K key, V newValue) {
        Node node = getNode(key);
        if (node == null) {
            throw new IllegalArgumentException("The Key is not exist!");
        }
        node.value = newValue;
    }

    @Override
    public int getSize() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

}

  • 基于二分搜索树实现Map映射;
package com.sjgd.map;

/**
 * @author 基于二分搜索树实现的Map集合
 * on 2023/2/7
 */
public class BSTMap<K extends Comparable<K>, V> implements Map<K, V> {


    private class Node {
        private K key;
        private V value;
        private Node left;
        private Node right;

        public Node(K key, V value) {
            this.key = key;
            this.value = value;
        }

        public Node(K key, V value, Node left, Node right) {
            this.key = key;
            this.value = value;
            this.left = left;
            this.right = right;
        }
    }

    private Node root;
    private int size;

    /**
     * 向二分搜索树中添加新元素
     *
     * @param key
     * @param value
     */
    @Override
    public void add(K key, V value) {
        root = add(root, key, value);
    }

    private Node add(Node node, K key, V value) {
        if (node == null) {
            size++;
            return new Node(key, value);
        }
        if (node.key.compareTo(key) > 0) {
            add(node.left, key, value);
        } else if (node.key.compareTo(key) < 0) {
            add(node.right, key, value);
        } else {
            node.value = value;
        }

        return node;
    }


    /**
     * 返回以Node为根节点的二分搜索树中,key所在的节点
     *
     * @param node
     * @param key
     * @return
     */
    private Node getNode(Node node, K key) {
        if (node == null) {
            return null;
        }
        if (node.key.compareTo(key) == 0) {
            return node;
        } else if (node.key.compareTo(key) > 0) {
            return getNode(node.left, key);
        } else {
            return getNode(node.right, key);
        }
    }

    @Override
    public V remove(K key) {
        Node node = getNode(root, key);
        if (node == null) {
            return null;
        }
        root = remove(root, key);
        return node.value;
    }

    private Node remove(Node node, K key) {
        if (node == null) {
            return null;
        }
        if (node.key.compareTo(key) > 0) {
            node.left = remove(node.left, key);
            return node;
        } else if (node.key.compareTo(key) < 0) {
            node.right = remove(node.right, key);
            return node;
        } else {
            //相等的情况
            //待删除节点左子树为空的情况
            if (node.left == null) {
                Node rightNode = node.right;
                node.right = null;
                size--;
                return rightNode;
            }
            if (node.right == null) {
                Node leftNode = node.left;
                node.left = null;
                size--;
                return leftNode;
            }
            //当左右子树都存在的时候,找到当前node节点的后继节点【右子树中最小值】
            Node successor = getMin(node.right);
            //先把右子树添加上,因为当前successor为右子树中最小node,如果先挂左子树,会改变右子树最小node的值
            successor.right = removeMin(node.right);
            successor.left = node.left;
            node.left = node.right = null;
            return successor;
        }
    }

    private Node removeMin(Node node) {
        if (node.left == null) {
            //记录其右子树
            Node rightNode = node.right;
            //将右子树删除
            node.right = null;
            size--;
            return rightNode;
        }
        //把删除的右子树添加到上一层的左子树上
        node.left = removeMin(node.left);
        return node;
    }
    private Node getMin(Node node) {
        if (node.left == null) {
            return node;
        }
        return getMin(node.left);
    }

    @Override
    public boolean contains(K key) {
        return getNode(root, key) != null;
    }

    @Override
    public V get(K key) {
        Node node = getNode(root, key);
        if (node == null) {
            return null;
        }
        return node.value;
    }

    @Override
    public void set(K key, V newValue) {
        Node node = getNode(root, key);
        if (node == null) {
            throw new IllegalArgumentException("This key is not exist!");
        }
        node.value = newValue;
    }

    @Override
    public int getSize() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }
}

时间复杂度比较

  • 基于链表实现的Map映射:O(n);
  • 基于二分搜索树实现的Map映射:平均为O(logn),最坏情况【退化为链表】为O(n);

结语

如果以上文章对您有一点点帮助,希望您不要吝啬的点个赞加个关注,您每一次小小的举动都是我坚持写作的不懈动力!ღ( ´・ᴗ・` )

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值