数据结构之集合和映射

简介: 数据结构之集合和映射

集合set


集合的特点


集合中的元素都是不重复的,所以,我们就可以通过二分搜索树来设计集合这种数据结构。


集合的实现


网络异常,图片无法展示
|


通过二分搜索树实现set


二分搜索树相关实现请看这里


public class BSTSet<E extends Comparable<E>> implements SetInterface<E>{
        private BST<E> bst = null;
        public BSTSet() {
            bst = new BST();
        }
        @Override
        public int getSize() {
            return bst.getSize();
        }
        @Override
        public void add(E e) {
            bst.add(e);
        }
        @Override
        public void remove(E e) {
            bst.remove(e);
        }
        @Override
        public boolean isEmpty() {
            return bst.isEmpty();
        }
        @Override
        public boolean contains(E e) {
            return bst.contains(e);
        }
    }


通过链表实现set


自定义的链表请访问该专栏


package com.zh.set13;
    import com.zh.linkedlist07.LinkedList;
    /**
     * @author zhanghao
     * @create 2022-05-29 14:48
     */
    public class LinkedListSet<E> implements SetInterface<E> {
        private LinkedList<E> list = null;
        public LinkedListSet() {
            list = new LinkedList<>();
        }
        @Override
        public int getSize() {
            return list.getSize();
        }
        @Override
        public void add(E e) {
            if(!list.contains(e)) {
                list.addFirst(e); // 首部添加,时间复杂度为o(1)
            }
        }
        @Override
        public void remove(E e) {
            list.removeElement(e);
        }
        @Override
        public boolean isEmpty() {
            return list.isEmpty();
        }
        @Override
        public boolean contains(E e) {
            return list.contains(e);
        }
    }


复杂度分析


网络异常,图片无法展示
|


网络异常,图片无法展示
|


网络异常,图片无法展示
|


网络异常,图片无法展示
|


LeetCode相关习题


LeetCode 804


通过set存储的是不重复的值的特性。


import java.util.TreeSet;
    class Solution {
        public int uniqueMorseRepresentations(String[] words) {
            String[] chars = {".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--.."};
            TreeSet set = new TreeSet();
            for(String word : words) {
                StringBuffer res = new StringBuffer();  
                for(int i = 0; i < word.length(); i++) {
                    String code = chars[word.charAt(i) - 'a'];
                    res.append(code);
                }
                set.add(res.toString());
            }
            return set.size();
        }
    }


映射Map


map特征


网络异常,图片无法展示
|


map的设计


网络异常,图片无法展示
|


网络异常,图片无法展示
|


通过链表实现Map


接口


public interface MapInterface<K, V> {
    void add(K key, V value);
    V remove(K key);
    void set(K key, V value);
    V get(K key);
    int getSize();
    boolean contains(K key);
    boolean isEmpty();
}


map实现


public class LinkedListMap<K, V> implements MapInterface<K, V> {
    private class Node {
        public K key;
        public V value;
        public Node next;
        public Node(K key, V value, Node next) {
            this.next = next;
            this.key = key;
            this.value = value;
        }
        public Node(K key, V value) {
            this.key = key;
            this.value = value;
        }
        public Node() {
            this(null, null, null);
        }
        @Override
        public String toString() {
            return key.toString() + "=>" + value.toString();
        }
    }
    private int size;
    private Node dummyHead;
    public LinkedListMap() {
        size = 0;
        dummyHead = new Node();
    }
    private Node getNode(K key) {
        Node cur = dummyHead.next; // 当前是头节点
        while(cur != null) {
            if(key.equals(cur.key)) {
                return cur;
            }
            cur = cur.next;
        }
        return null;
    }
    @Override
    public void add(K key, V value) {
        if(getNode(key) != null) return; // 如果添加相同的元素,那么将不做处理
        // 创建一个新节点, 并将头结点作为该节点的下一个节点
        Node node = new Node(key, value, dummyHead.next);
        // 将dummyHead指向改新节点
        dummyHead.next = node;
        size++;
    }
    @Override
    public V remove(K key) {
        Node prev = dummyHead;
        while(prev.next != null) {
            if(key.equals(prev.next.key)) { // 查找到
                Node cur = prev.next;
                prev.next = cur.next;
                cur.next = null;
                size--;
                return cur.value;
            }
            prev = prev.next;
        }
        return null;
    }
    @Override
    public void set(K key, V value) {
        Node cur = getNode(key);
        if(cur != null) { // 有就修改
            cur.value = value;
        }else { // 没有就新增
            add(key, value);
        }
    }
    @Override
    public V get(K key) {
        return getNode(key).value;
    }
    @Override
    public int getSize() {
        return size;
    }
    @Override
    public boolean contains(K key) {
        return getNode(key) != null;
    }
    @Override
    public boolean isEmpty() {
        return size == 0;
    }
    // toString方法
    @Override
    public String toString() {
        StringBuilder res = new StringBuilder();
        res.append("[");
        Node cur = dummyHead.next;
        while(cur != null) {
            res.append(cur);
            if(cur.next != null) {
                res.append(",");
            }
            cur = cur.next;
        }
        res.append("]");
        return res.toString();
    }
}


通过二分搜索树实现map


public class BSTMap<K extends Comparable<K> , V> implements MapInterface<K, V> {
    private class Node {
        public K key;
        public V value;
        public Node left;
        public Node right;
        public Node(K key, V value) {
            this.key = key;
            this.value = value;
            this.left = null;
            this.right = null;
        }
    }
    private Node root;
    private int size;
    // 返回以node为根节点的二分搜索树中,key所在的节点
    private Node getNode(Node node, K key) {
        if(node == null) {
            return null;
        }
        if(key.compareTo(node.key) > 0) {
            return getNode(node.right, key);
        }else if(key.compareTo(node.key) < 0) {
            return getNode(node.left, key);
        }else {
            return node;
        }
    }
    @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(key.compareTo(node.key) < 0) { // 加在左子树
            node.left = add(node.left, key, value);
        }else if(key.compareTo(node.key) > 0){ // 加在右子树
            node.right = add(node.right, key, value);
        }
//        else { // 更新节点
//            node.value = value;
//        }
        return node;
    }
    @Override
    public V remove(K key) {
        Node node = getNode(root, key);
        if(node != null) {
            root = remove(root, key);
            return  node.value;
        }
        return null;
    }
    // 查找最小值节点
    public Node findMin(Node root) {
        if(root == null) {
            return null;
        }
        Node cur = root;
        while (cur.left != null) {
            cur = cur.left;
        }
        return cur;
    }
    private Node removeMin(Node node) {
        if(node.left == null) {
            Node currentItemRight = node.right;
            node.right = null;
            size--;
            // 返回当前元素的右子树
            return currentItemRight;
        }
        node.left = removeMin(node.left);
        return node;
    }
    private Node remove(Node node, K key) {
        if(node == null) {
            return null;
        }
        if(key.compareTo(node.key) > 0) {
            node.right = remove(node.right, key);
            return node;
        }else if(key.compareTo(node.key) < 0) {
            node.left = remove(node.left, key);
            return node;
        }else { // node.e = e;
            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 successor = findMin(node.right);
            // 改变该后继节点的left指向
            successor.left = node.left;
            // 改变该后继节点的right指向。即删除了该后继节点的子树
            successor.right = removeMin(node.right);
            node.left = node.right = null;
            return successor;
        }
    }
    @Override
    public void set(K key, V value) {
        Node node = getNode(root, key);
        if(node != null) {
            node.value = value;
        }else { // 不存在就添加
            add(key, value);
        }
    }
    @Override
    public V get(K key) {
        Node node = getNode(root, key);
        return node != null ? node.value : null;
    }
    @Override
    public int getSize() {
        return size;
    }
    @Override
    public boolean contains(K key) {
        Node node = getNode(root, key);
        return node != null;
    }
    @Override
    public boolean isEmpty() {
        return size == 0;
    }
    // 前序遍历
    public void preOrder() {
        preOrder(root);
    }
    private void preOrder(Node node) {
        if(node == null) {
//            System.out.println("null");
            return ;
        }
        System.out.println(node.key + "=>" + node.value);
        // 遍历该节点的左子树
        preOrder(node.left);
        // 遍历该节点的右子树
        preOrder(node.right);
    }
}


复杂度分析


网络异常,图片无法展示
|


二者的关系


其实java底层就是使用map实现的set。


网络异常,图片无法展示
|


LeetCode相关习题


LeetCode 349


  • 首先将一个数组元素放在set中,


  • 再根据另一个数组中元素判断是否存在


  • 存在就删除,防止下一次依旧有相同的加入到返回的数组中。


public int[] intersection(int[] nums1, int[] nums2) {
        TreeSet<Integer> set = new TreeSet<>();
        LinkedList<Integer> arr = new LinkedList<>();
        for (int item : nums1) {
            set.add(item); // 这里的item加入的是不重复的。
        }
        for(int item: nums2) {
            if(set.contains(item)) { // 返回true,则表示存在
                arr.add(item);
                // 加入后就删除, 防止下一次相同的再次加入。
                set.remove(item);
            }
        }
        int[] ints = new int[arr.size()];
       for(int i = 0; i < arr.size(); i++) {
           ints[i] = arr.get(i);
       }
       return ints;
    }


LeetCode 350


TreeMap<Integer, Integer> map = new TreeMap<>();
        LinkedList<Integer> arr = new LinkedList<>();
        for (int item : nums1) {
//            map.add(item); // 这里的item加入的是不重复的。
            if(map.containsKey(item)) { // 如果存在,就加一
                map.put(item, map.get(item) + 1);
            }else { // 如果没有就直接设置为一
                map.put(item, 1);
            }
        }
        for(int item: nums2) {
            if(map.containsKey(item)) { // 返回true,则表示存在
                arr.add(item);
                map.put(item, map.get(item) - 1); // 存在将value减一
                if(map.get(item) == 0) { // 当元素value为0时,删除该元素
                    map.remove(item);
                }
            }
        }
        int[] ints = new int[arr.size()];
        for(int i = 0; i < arr.size(); i++) {
            ints[i] = arr.get(i);
        }
        return ints;


相关文章
|
2月前
|
缓存 算法 安全
Java集合框架:深入探究数据结构与算法的精华
Java集合框架:深入探究数据结构与算法的精华
|
1月前
|
存储 程序员 索引
数据结构深度剖析:列表、元组、字典和集合
【4月更文挑战第8天】Python的四种基础数据结构——列表、元组、字典和集合,各自拥有独特的特性和应用场景。列表是可变序列,方便增删改元素;元组不可变,常用于保证数据不变性;字典是键值对容器,快速访问通过键;集合是无序不重复元素集,适合成员测试和去重。理解并灵活运用这些数据结构,能提升代码效率,有效处理和分析数据。
|
2月前
|
索引 Python
Python数据结构讲解集合
Python数据结构讲解集合
18 0
|
2月前
|
存储 算法 Java
【数据结构与算法】2、链表(简单模拟 Java 中的 LinkedList 集合,反转链表面试题)
【数据结构与算法】2、链表(简单模拟 Java 中的 LinkedList 集合,反转链表面试题)
43 0
|
3月前
|
存储 消息中间件 人工智能
数据结构与集合源码
数据结构与集合源码
28 0
|
4月前
|
存储 前端开发 Java
【Java】集合与数据结构
【Java】JavaSE集合
87 0
|
5月前
|
Serverless 数据库 索引
Python基础语法、内建数据结构列表、元组、字典、集合的讲解及应用(附源码 超详细必看)
Python基础语法、内建数据结构列表、元组、字典、集合的讲解及应用(附源码 超详细必看)
54 0
|
5月前
|
存储 算法 Java
java数据结构,列举并解释Java中的集合框架(Collection Framework)。
java数据结构,列举并解释Java中的集合框架(Collection Framework)。
26 0
|
5月前
|
存储 索引 Python
python数据结构,集合(set)和字典(dict)之间的主要区别是什么?
python数据结构,集合(set)和字典(dict)之间的主要区别是什么?
|
5月前
|
存储 算法 Java
Java实现—数据结构 1.初识集合框架
Java实现—数据结构 1.初识集合框架
33 0