Java day16——队列Queue、二叉树优化(递归)、Set(I)、Map(I)

队列Queue

  • Queue(I): - 队列(offer/peek/poll)
    • Deque(I) - 双端队列(offerFirst/offerLast…)
      - 栈(push/pop)
      • LinkedList

API

  1. offer("")进队列
  2. peek()获取队列头元素
  3. poll()获取队列头元素,并将元素从队列中移除
		// 1.创建队列 - 先进先出
        Queue<String> qu = new LinkedList<>();
        // 2.进队列的方法
        qu.offer("哈哈哈");
        qu.offer("嘻嘻嘻");
        System.out.println(qu);//[哈哈哈, 嘻嘻嘻]
        // 3.获取队列头元素的方法
        String s1 = qu.peek(); // -- 只是查看访问
        System.out.println("队列头: " + s1);
        System.out.println("队列: " + qu);
        s1 = qu.poll(); // -- 获取队列头元素,并将元素从队列中移除
        System.out.println("队列头2: " + s1);//哈哈哈
        System.out.println("队列2: " + qu);//[嘻嘻嘻]
遍历
forEach
System.out.println(qu.poll())

Deque双端队列

拥有队列相关的所有方法 offer peek poll
offerFirst、offerLast:从队列头和尾加元素
pollFirst()、pollLast():从队列头和尾取元素

		// 1.创建一个双端队列的方法
        Deque<String> dq = new LinkedList<>();
        // 2.拥有队列相关的所有方法 offer peek poll
        dq.offer("哈哈哈");
        dq.offer("嘻嘻嘻");
        // 3.可以从队列头和尾加元素
        dq.offerFirst("hahaha");
        dq.offerLast("heihei"); // 等同于offer方法
        System.out.println(dq);
        // 4.可以从队列头和尾取元素
        String s1 = dq.pollFirst(); // 等同于poll
        System.out.println("队列头: " + s1);
        System.out.println("队列: " + dq);

        s1 = dq.pollLast();
        System.out.println("队列尾: " + s1);
        System.out.println("队列: " + dq);

LinkedList

Deque双端队列,当你使用它的 push压栈 和 pop 弹栈方法时, 他就变成了栈

		// 链表栈
        Deque<String> stack = new LinkedList<>();
        stack.push("a");
        stack.push("b");
        stack.push("c");
        System.out.println(stack);
        String s = stack.pop();
        System.out.println("栈顶元素: " + s);
        System.out.println("栈: " + stack);
        //[c, b, a]
		//栈顶元素: c
		//栈: [b, a]
		//[h, i]
		//stack2的栈顶: i

        // 栈: 数组栈
        Stack<String> stack2 = new Stack<>();
        stack2.push("h");
        stack2.push("i");
        System.out.println(stack2);

        String s2 = stack2.pop();
        System.out.println("stack2的栈顶: " + s2);

二叉树优化(递归)

左 < 中 < 右
中序遍历

public class SortedTree<T> {
    private class Node<T> {
        private T data;
        private Node left;
        private Node right;
        public Node(T data) {
            this.data = data;
        }
    }
    private Node<T> root; // 二叉树中的根节点

    private void addToNode(Node node, T t) {
        // 1.比较 node.data 和 t的大小
        if (((Comparable) t).compareTo(node.data) < 0) {
            // 加到node的左边
            if (node.left == null) {
                node.left = new Node<T>(t);
                return;
            }
            addToNode(node.left, t);
        } else if (((Comparable) t).compareTo(node.data) > 0) {
            // 加到node的右边
            if (node.right == null) {
                node.right = new Node<T>(t);
                return;
            }
            addToNode(node.right, t);
        }
    }
    public void add(T t) {
        // 1.判断根节点是否为空 -> 其实就是判断二叉树是否为空
        if (root == null) {
            root = new Node<T>(t);
            return;
        }
        addToNode(root, t);
    }
    private void travelNode(Node node) {
        if (node.left != null) {
            travelNode(node.left);
        }
        System.out.println(node.data);
        if (node.right != null) {
            travelNode(node.right);
        }
    }
    public void travel() {
        travelNode(root);
    }
    //改泛型
    /*public void add(T t) {
        // 1.判断根节点是否为空 -> 其实就是判断二叉树是否为空
        if (root == null) {
            root = new Node<T>(t);
            return;
        }
        Node node = root;
        Node parentNode ;
        // 2.判断 t 和 根节点.data 大小关系
        while (true) {
            parentNode = node;
            if (((Comparable) t).compareTo(node.data) < 0) {
                // 将t加入到node的左边
                node = node.left;
                if (node == null) {
                    parentNode.left = new Node<T>(t);
                }
            } else if (((Comparable) t).compareTo(node.data) > 0) {
                // 将t加入到node的右边
                node = node.right;
                if (node == null) {
                    parentNode.right = new Node<T>(t);
                }
            }
        }
    }*/

public class Demo01Tree {
    public static void main(String[] args) {
        SortedTree<String> tree = new SortedTree<>();
        tree.add("tom");
        tree.add("hi");
        tree.add("hehe");
        tree.add("lucy");
        tree.add("jack");

        tree.travel();
    }

Set(I)

API 和 Collection 的API 一样

  • HashSet
  • SortedSet(I)

HashSet

散列表/无序的, 不是随机!! 不允许重复元素

 Set<String> set = new HashSet<>();
        set.add("hello");
        set.add("how");
        set.add("are");
        set.add("you");
        // 不允许重复
        set.add("you");
        // [how, are, hello, you]
        System.out.println(set);

add原理

详见图
在这里插入图片描述

remove移除

public static void main(String[] args){
        Student s1 = new Student("张三", 12);
        Student s2 = new Student("李四", 34);
        Set<Student> set = new HashSet<>();
        set.add(s1);
        set.add(s2);
        System.out.println(set.size());
        // 属性值发生了改变
        s1.setAge(21);
        // 移除的时候,重新计算位置,发现位置上找不到s1对象,不会移除
        set.remove(s1);
        System.out.println(set.size());
//2
//2

why重写hashCode和equals

		Set<Student> set = new HashSet<>();
        set.add(new Student("张三", 12));
        set.add(new Student("李四", 34));
        set.add(new Student("张三", 12));
        set.add(new Student("李四", 34));

        System.out.println(set);
        System.out.println(set.size());
        /**
         * 1.Student没有重写equals和hashCode, 添加进4个元素
         * 2.重写了equals方法, 但是没有重写hashCode, 添加进4个元素
         * 3.重写了hashCode方法, 但是没有重写equals, 添加进4个元素
         * 4.重写了equals和hashCode方法, 添加进2个元素
         */
  • 结论: hashCode和equals要一起重写
  • 注意: equals方法判断相同的两个对象, hashCode方法结果一定要一致
  • equals判断不相同的两个对象, hashCode结果要尽量不一样

SortedSet(I)

TreeSet: Comparable Comparator
特点: 不允许重复, 和equals方法无关
取决于 compare 或者 compareTo 方法

public static void main(String[] args){
        Set<String> set = new TreeSet<>();
        set.add("tom");
        set.add("jack");
        set.add("zhangsan");
        set.add("lisi");
        set.add("lisi");
        System.out.println(set);//[jack, lisi, tom, zhangsan]

    }


public static void main(String[] args){
        // 可以通过构造方法, 传入比较器
        Set<String> set = new TreeSet<>(new Comparator<String>(){
            @Override
            public int compare(String o1, String o2){
                return o1.length() - o2.length();
            }
        });
        set.add("zhangsan");
        set.add("tom");
        set.add("jack");
        set.add("lisi");
        set.add("lisi");
        System.out.println(set);//[tom, jack, zhangsan]

    }

总结

  • Comparable的已知实现类: Date String Integer…
  • Object中 hashCode() 方法默认得到的是 对象的物理地址
  • hashCode没有重写, 所有对象的哈希值都不一样
  • 哈希值不一样, 定位到的set中的位置, 可能相同

Map(I)

Map集合是有Key和Value的,Collection集合是只有Value。
映射表 key->value, 通过key 获得value
Map中的key, 单独的一部分, 就是Set
格式: xx = xxx, xx:xxx

常用API

put(key, value):添加(返回null), 替换(返回value)(被替换掉的value)
remove(key):通过key, 删除key-value, 返回被删掉的value值
get(key):通过key, 获得value

public static void main(String[] args){
        Map<Integer, String> map = new HashMap<>();
        // 1.向map集合中添加元素 key-value
        String s = map.put(3, "张三");
        map.put(4, "张三");
        map.put(1, "张三");
        map.put(2, "李四");

        System.out.println("put返回值: " + s); // null
        System.out.println(map);// {1=张三, 2=李四, 3=张三, 4=张三} -> toString重写过了

        // 2.从集合中移除元素 key-value, 返回移除掉的value
        String s2 = map.remove(1);
        System.out.println("remove返回值: " + s2);
        System.out.println(map);//{2=李四, 3=张三, 4=张三}

        // 3.将集合中的元素修改
        String s3 = map.put(3, "王五");
        System.out.println("put返回值: " + s3); // 张三
        System.out.println(map);//{2=李四, 3=王五, 4=张三}

        // 4.获得map集合中的元素 value, 不存在的key, 对应的null
        String s4 = map.get(5);
        System.out.println("get返回值: " + s4); // null
        System.out.println(map);//{2=李四, 3=王五, 4=张三}
    }

HashMap

HashMap: key无序, 并且不重复
HashSet 就是value一样的 HashMap

TreeMap

TreeMap: key排好序的

// 1.无参构造方法创建TreeMap, 没有指定比较器
        Map<String, Integer> map = new TreeMap<>();

        map.put("lucy", 23);
        map.put("tom", 18);
        map.put("jack", 20);
        map.put("zhangsan", 16);

        System.out.println(map);//{jack=20, lucy=23, tom=18, zhangsan=16}

 // 2.有参构造方法创建TreeMap, 传入比较器对象
        Map<String, Integer> map = new TreeMap<>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.length() - o2.length();
            }
        });

        map.put("lucy", 23);
        map.put("tom", 18);
        // 添加jack的时候, 比较器结果认定jack和lucy相等的, 所以将原来的value值替换
        map.put("jack", 20);
        map.put("zhangsan", 16);

        System.out.println(map);//{tom=18, lucy=20, zhangsan=16}

LinkedHashMap

LinkedHashMap: key有序的

 public static void main(String[] args) {
        Map<String, String> map = new LinkedHashMap<>();
        map.put("lucy", "有点傻");
        map.put("jack", "有点呆");
        map.put("tom", "有点蠢");
        map.put("rose", "有点萌");
        // 结果: 按照插入顺序排列, 有序的
        System.out.println(map);//{lucy=有点傻, jack=有点呆, tom=有点蠢, rose=有点萌}

    }

迭代方式

keySet()

遍历key

// 遍历方式1: 将map中的key的部分, 单独取出, 成为set, 遍历这个set
public class Demo02HashMap{
    public static void main(String[] args){
        Map<String, String> map = new HashMap<>();
        map.put("张三","12334345");
        map.put("李四","3245345");
        map.put("王五","567890");
        map.put("赵六","98765432");
		
		// 遍历方式1: 将map中的key的部分, 单独取出, 成为set, 遍历这个set
        Set<String> set = map.keySet();
        // 遍历key
        for (String key:set) {
            // 通过key获得value
            String value = map.get(key);
            System.out.println(key + " = " + value);
        }
    }

entrySet()

Set<Entry<K,V>> entrySet(): key-value封装成Entry

// 遍历方式2: 键值对封装成一个整体-Entry, Set<Entry>
public class Demo03HashMap {
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();
        map.put("张三","12334345");
        map.put("李四","3245345");
        map.put("王五","567890");
        map.put("赵六","98765432");
        
		// 遍历方式2: 键值对封装成一个整体-Entry, Set<Entry>
        Set<Entry<String, String>> set = map.entrySet();
        for (Entry<String, String> en:set) {
            // 获得key
            String key = en.getKey();
            String value = en.getValue();
            System.out.println(key + " = " + value);
        }
    }
}

values()

Collection values(): 遍历value

// 遍历方式3: 将map中的value部分获取出来, 成为List, 遍历这个List
// 弊端: 就只能遍历值, 不能遍历键, 因为map不能反向映射
public class Demo04HashMap {
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();
        map.put("张三","12334345");
        map.put("李四","3245345");
        map.put("王五","567890");
        map.put("赵六","98765432");


		// 遍历方式3: 将map中的value部分获取出来, 成为List, 遍历这个List
		// 弊端: 就只能遍历值, 不能遍历键, 因为map不能反向映射
        Collection<String> values = map.values();
        for (String value : values) {
            System.out.println(value);
        }
    }

Hashtable和区别

  1. Hashtable 和 HashMap 有什么区别?
    存储内容-null, 线程安全, 效率, 底层实现结构

  2. LinkedHashMap 和 HashMap 有什么区别?
    底层实现结构

  3. ConcurrentHashMap 和 Hashtable 和 HashMap有什么区别
    底层实现结构

应用——统计个数

案例: 手动输入字符串 ewretyuyjytrerthy
统计这个字符串中每个字符出现的次数
e:3, w:1, r:3, t:3…

 public static void main(String[] args) {
        Scanner console = new Scanner(System.in);
        String str = console.nextLine();
        Map<Character, Integer> map = new HashMap<>();
        // 1.将字符串转换成字符数组
        char[] chars = str.toCharArray();
        // 2.遍历数组, 进行统计
        for (char c : chars) {
            // 判断c是不是第一次出现
            Integer ori = map.get(c);
            if (ori == null) {
                ori = 0;
            }
            map.put(c, ori + 1);
        }
        System.out.println(map);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值