0
点赞
收藏
分享

微信扫一扫

网络安全(黑客)—-2024自学手册

一、二叉搜索树

1、概念

2、实现一棵二叉搜索树

public class MyBinarySearchTree {
    static class TreeNode{
        private int val;
        private TreeNode left;
        private TreeNode right;
        public TreeNode(int val){
            this.val = val;
        }
    }
    public TreeNode root = null;
    //1、查找:时间复杂度 O(logn)
    public TreeNode search(int data){
        TreeNode cur = root;
        while(cur != null){
            if(data < cur.val){
                cur = cur.left;
            }else if(data > cur.val){
                cur = cur.right;
            }else{
                return cur;
            }
        }
        return null;
    }
    //2、插入
    public boolean add(int data){
        TreeNode node = new TreeNode(data);
        if(root == null){
            root = node;
            return true;
        }
        TreeNode prev = null;
        TreeNode cur = root;
        while(cur != null){
            if(data < cur.val){
                prev = cur;
                cur = cur.left;
            }else if(data > cur.val){
                prev = cur;
                cur = cur.right;
            }else{
                return false;
            }
        }
        if(data < prev.val){
            prev.left = node;
        }else{
            prev.right = node;
        }
        return true;
    }
    //3、删除
    //替罪羊法
    public void remove(int data){
        TreeNode prev = null;
        TreeNode cur = root;
        while(cur != null){
            if(data < cur.val){
                prev = cur;
                cur = cur.left;
            }else if(data > cur.val){
                prev = cur;
                cur = cur.right;
            }else{
                //找到了,进行删除,cur就是要删除的节点
                removeNode(prev,cur);
            }
        }
    }
    public void removeNode(TreeNode prev,TreeNode cur){
        //分为3种情况:要删除的节点没有左子树,要删除的节点没有右子树,要删除的节点左右子树都有
        if(cur.left == null){
            if(cur == root){
                root = root.right;
            }else if(cur == prev.left){
                prev.left = cur.right;
            }else{
                prev.right = cur.right;
            }
        }else if(cur.right == null){
            if(cur == root){
                root = root.left;
            }else if(cur == prev.left){
                prev.left = cur.left;
            }else{
                prev.right = cur.left;
            }
        }else{
            //cur 的左树和右树都不为空
            //找右树的最小值的节点(即右树的最左边),将值赋给data,替换成删除这个节点
            TreeNode mPrev = cur;
            TreeNode mCur = cur.right;
            while(mCur.left != null){
                mPrev = mCur;
                mCur = mCur.left;
            }
            //mCur就是右树的最左边,mCur要么没有子树,要么只有右树
            cur.val = mCur.val;
            if(mCur == mPrev.left){
                mPrev.left = mCur.right;
            }else{
               mPrev.right = mCur.right;
            }
        }
    }
}

 

二、Map 和 Set

1、Map


 Map.Entry<K,V>:键值对的类型

Map.Entry<K,V> 接口中的方法:

Map中的方法: 

public static void main(String[] args) {
        TreeMap<String,Integer> map = new TreeMap<>();
        //1、设置 key 对应的 value
        map.put("hello",6);
        map.put("abc",6);
        map.put("world",3);//hello 左边是 abc,右边是 world
        System.out.println(map);
        //2、返回 key 对应的 value,key 不存在,返回 null
        Integer value = map.get("hello");
        System.out.println("hello = "+value);
        //3、返回 key 对应的 value,key 不存在,返回 默认值
        Integer v = map.getOrDefault("h",0);
        System.out.println("h = "+v);
        //4、删除 key 对应的映射关系,即删除这对键值对
        map.remove("world");
        System.out.println(map);
        //5、判断是否包含 key
        boolean flag = map.containsKey("world");
        System.out.println("key中是否包含world呢:"+flag);
        //6、判断是否包含 value
        boolean flag2 = map.containsValue(6);
        System.out.println("value中是否包含6呢:"+flag2);
        //7、返回所有 key 的不重复集合
        Set<String> set = map.keySet();
        System.out.println("所有 key 的不重复集合:"+set);
        //8、返回所有 value 的集合
        Collection<Integer> collection = map.values();
        System.out.println("所有 value 的集合:"+collection);
        //9、返回所有的 key-value 映射关系
        // 相当于把key-value看成一个整体,放进 Set 这个集合里
        Set<Map.Entry<String,Integer>> entrySet = map.entrySet();
        //entry 是 key-value这个整体,entrySet是装 键值对的 集合
        System.out.println("输出所有的键值对:");
        for (Map.Entry<String,Integer> entry:entrySet) {
            //遍历集合,拿到的每个元素都是一对键值对
            System.out.println(entry.getKey()+"="+entry.getValue());
        }
}

 

2、Set

Set中的方法:  

3、Map 和 Set 的区别和联系

三、TreeSet 和 TreeMap

TreeSet 和 TreeMap 的区别和联系:

四、HashSet 和 HashMap

1、哈希表(或散列表)

如果想从一组元素中查找某个元素,我们可能会想到以下方法:

1、将元素存储数组,然后遍历数组进行查找,时间复杂度O(n)

2、如果元素是有序的,使用二分查找,时间复杂度是O(logn)

3、利用搜索树进行查找,时间复杂度是O(logn)

有一种数据结构,查找元素的时间复杂度可以达到O(1),它就是哈希表。

但是,可能会出现不同的key通过哈希函数计算得到相同的哈希地址,就会出现哈希冲突/哈希碰撞

2、哈希冲突/哈希碰撞 

由于哈希表底层数组的容量往往是小于实际要存储的key的数量的,所以哈希冲突/哈希碰撞是必然存在的。但我们可以降低哈希冲突发生的概率。

上述两种方式只能降低哈希冲突发生的概率,那么如何解决哈希冲突呢? 

3、解决哈希冲突 —— 开散列(哈希桶)

解决哈希冲突的两种常见的方法是:闭散列和开散列

闭散列:也叫开放定址法,当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空

位置,那么可以 把key存放到冲突位置中的下一个空位置中去。寻找空位置的方法有两种:线性

探测和二次探测。

在Java中,我们使用的是开散列的方法,也叫做哈希桶。

开散列(哈希桶):开散列法又叫链地址法(开链法),首先对key集合用散列函数计算散列地址,

具有相同地址的key归于同一子集合,每一个子集合称为一个桶,各个桶中的元素通过一个单链表

链接起来,各链表的头结点存在哈希表中。开散列中每个桶中放的都是发生哈希冲突的元素。

哈希桶是数组+链表的结构,把冲突的放到对应的一个链表里面。在合适的情况下,链表会变成红

黑树。jdk1.7及以前,采用的是头插法;jdk1.8开始采用的是尾插法。

4、HashSet 和 HashMap 的区别和联系:

5、HashMap的一些说明

五、TreeMap(或TreeSet) 和 HashMap(或HashSet) 的区别和联系

六、题目

1、统计10w个数据当中,不重复的数据 Set

 public static void func(int[] array){
        //去重,Set是天然去重的,把数据放到Set里
        HashSet<Integer> set = new HashSet<>();
        for (int i = 0; i < array.length; i++) {
            set.add(array[i]);
        }
        System.out.println(set);
 }

2、统计10w个数据当中,第一个重复的数据 Set

public static void func2(int[] array){
        HashSet<Integer> set = new HashSet<>();
        for (int i = 0; i < array.length; i++) {
            if(!set.contains(array[i])){
                set.add(array[i]);
            }else{
                System.out.println(array[i]);
                return;
            }
        }
}

3、统计10w个数据当中,每个数据出现的次数 Map

public static void func3(int[] array){
        HashMap<Integer,Integer> map = new HashMap<>();
        //使用map,遍历数组,如果map中没有此数据,就放进去,如果已经有此数据了,value就+1
        for (int i = 0; i < array.length; i++) {
            if(!map.containsKey(array[i])){
                map.put(array[i],1);
            }else{
                int value = map.get(array[i]);
                map.put(array[i], value+1);
            }
        }
        //走到这,map中存的就是每个数据,以及对应出现的次数
        Set<Map.Entry<Integer,Integer>> entrySet = map.entrySet();
        for (Map.Entry<Integer,Integer> entry:entrySet) {
            System.out.println("key:"+ entry.getKey()+" 出现了:"+entry.getValue()+"次!");
        }
}

4、字符串中第一个只出现一次的字符 Map

public int first(String s){
        HashMap<Character,Integer> map = new HashMap<>();
        for (int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i);
            if(!map.containsKey(ch)){
                map.put(ch,1);
            }else{
                int value = map.get(ch);
                map.put(ch,value+1);
            }
        }
        //走到这,map里放的就是字符和对应的个数
        for (int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i);
            if(map.get(ch) == 1){
                return i;
            }
        }
        return -1;
}

5、数组中只出现一次的数字,其余数字都出现两次 Set

public int singleNumber(int[] nums) {
        HashSet<Integer> set = new HashSet<>();
        for(int i=0; i<nums.length;i++){
            if(!set.contains(nums[i])){
                set.add(nums[i]);
            }else{
                set.remove(nums[i]);
            }
        }
        //set中存的就是只出现一次的元素
        for (Integer x : set) {
            return x;
        }
        return -1;
}

6、随机链表的复制 Map

public Node copyRandomList(Node head) {
        //key是老节点,value是新节点
        HashMap<Node,Node> map = new HashMap<>();
        Node cur = head;
        while(cur != null){
            Node node = new Node(cur.val);
            map.put(cur,node);
            cur = cur.next;
        }
        cur = head;
        while(cur != null){
            map.get(cur).next = map.get(cur.next);
            map.get(cur).random = map.get(cur.random);
            cur = cur.next;
        }
        return map.get(head);
}

7、宝石与石头 Set

public int numJewelsInStones(String jewels, String stones) {
        HashSet<Character> set = new HashSet<>();
        int count = 0;
        for (int i = 0; i < jewels.length(); i++) {
            set.add(jewels.charAt(i));
        }
        for (int i = 0; i < stones.length(); i++) {
            char ch = stones.charAt(i);
            if(set.contains(ch)){
                count++;
            }
        }
        return count;
}

8、坏键盘打字 Set

public static void func(String s1,String s2){
        String str1 = s1.toUpperCase();
        String str2 = s2.toUpperCase();

        HashSet<Character> set = new HashSet<>();
        for (int i = 0; i < str2.length(); i++) {
            set.add(str2.charAt(i));
        }
        HashSet<Character> ret = new HashSet<>();

        for (int i = 0; i < str1.length(); i++) {
            char ch = str1.charAt(i);
            //应该输出的,实际输出的里没有
            if(!set.contains(ch) && !ret.contains(ch)){
                ret.add(ch);
                System.out.print(ch);
            }
        }
}

9、前K个高频单词 Map

(1)概括题目: 

(2)分析题目:

(3)需要用到的集合:

(4)代码:

public List<String> topKFrequent(String[] words, int k) {
        //1、统计单词出现的次数
        HashMap<String,Integer> map = new HashMap<>();
        for (String word : words) {
            if(!map.containsKey(word)){
                map.put(word,1);
            }else{
                Integer value = map.get(word);
                map.put(word,value+1);
            }
        }
        //2、建立小根堆,小根堆里每个元素是一个Entry
        PriorityQueue<Map.Entry<String,Integer>> minHeap = new PriorityQueue<>(k,
                new Comparator<Map.Entry<String, Integer>>() {
                    @Override
                    public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                        //次数小的靠进堆顶
                        //次数相等时,单词大的靠近堆顶
                        if(o1.getValue().equals(o2.getValue())){
                            return o2.getKey().compareTo(o1.getKey());
                        }
                        return o1.getValue().compareTo(o2.getValue());
                    }
                });
        for (Map.Entry<String,Integer> entry : map.entrySet()) {
            if(minHeap.size() < k){
                minHeap.offer(entry);
            }else{
                //和堆顶元素比,次数大的往里放,次数相等的,单词小的往里放
                Map.Entry<String,Integer> top = minHeap.peek();
                if(entry.getValue().compareTo(top.getValue()) > 0){
                    minHeap.poll();
                    minHeap.offer(entry);
                }else{
                    if(entry.getValue().compareTo(top.getValue()) == 0){
                        if(entry.getKey().compareTo(top.getKey()) < 0){
                            minHeap.poll();
                            minHeap.offer(entry);
                        }
                    }
                }
            }
        }
        //3、把单词放进ArrayList
        List<String> list = new ArrayList<>();
        while(!minHeap.isEmpty()){
            Map.Entry<String,Integer> entry = minHeap.poll();
            list.add(entry.getKey());
        }
        //4、翻转ArrayList
        Collections.reverse(list);
        return list;
    }
举报

相关推荐

0 条评论