数据结构结尾部分

二叉搜索树

二叉搜索树可以是一个空树,或者就是具备以下性质的树:若其左子树不为空时,则左子树上所有节点的值都小于根节点的值;若其右子树不为空时,则右子树上所有节点的值都小于根节点的值;而且它的左右子树也满足这种性质。

 查找key是否在二叉搜索树中

public TreeNode search(int key){
            TreeNode cur=root;
            while (cur!=null){
                if (cur.val<key){
                    cur=cur.right;
                }else if (cur.val>key){
                    cur=cur.left;
                }else {
                    return cur;
                }
            }
            return null;
        }

插入元素

public boolean insert(int key){
        TreeNode node=new TreeNode(key);
        if (root==null){
            root=node;
            return true;
        }
        TreeNode cur=root;
        TreeNode parent=null;
        if (cur.val>key){
            parent=cur;
            cur=cur.left;
        }else if (cur.val<key){
            parent=cur;
            cur=cur.right;
        }else {
            return false;
        }
        if (parent.val<key){
            parent.right=node;
        }else {
            parent.left=node;
        }
        return true;
    }

删除关键字为key的节点

public void remove(int key) {
        TreeNode cur = root;
        TreeNode parent = null;
        while (cur != null) {
            if(cur.val < key) {
                parent = cur;
                cur = cur.right;
            }else if(cur.val > key) {
                parent = cur;
                cur = cur.left;
            }else {
                //找到了 就要开始删除了
                removeNode(cur,parent);
                return;
            }
        }
    }

    
    private void removeNode(TreeNode cur, TreeNode parent) {
        if(cur.left == null) {
            if(cur == root) {
                root = root.right;
            }else if(cur == parent.left) {
                parent.left = cur.right;
            }else {
                parent.right = cur.right;
            }
        }else if(cur.right == null) {
            if(cur == root) {
                root = root.left;
            }else if(cur == parent.left){
                parent.left = cur.left;
            }else {
                parent.right = cur.left;
            }
        }else {
            TreeNode targetParent = cur;
            TreeNode target = cur.right;
            while (target.left != null) {
                targetParent = target;
                target = target.left;
            }
            cur.val = target.val;
            //分两种情况
            if(targetParent.left == target) {
                targetParent.left = target.right;
            }else {
                targetParent.right = target.right;
            }
        }
    }

Map和Set

 Map中存储的就是key-value的键值对,Set中只存储了Key。

Map是一个接口类,该类没有继承自Collection,该类中存储的是<K,V>结构的键值对,并且K一定是唯一的,不能重复,也不能为null。

Map的底层结构是TreeMap的时候

        Map<String,Integer> map=new TreeMap<>();
        map.put("do",12);
        map.put("baekhyun",5);
        map.put("krystal",2);
        System.out.println(map);
        Set<Map.Entry<String,Integer>> entrySet=map.entrySet();
        for (Map.Entry<String,Integer> entry:entrySet) {
            System.out.println("key:"+entry.getKey()+" value:"+entry.getValue());
        }
        //返回 key 对应的 value
        System.out.println(map.get("baekhyun"));
        //返回 key 对应的 value,key 不存在,返回默认值
        System.out.println(map.getOrDefault("baekhyunkrystal", 521));
        //返回所有 key 的不重复集合
        Set<String> set=map.keySet();
        System.out.println(set);
        //返回所有 value 的可重复集合
        Collection<Integer> collection=map.values();
        System.out.println(collection);
Map底层结构TreeMap

HashMap

底层结构红黑树哈希桶
插入/删除/查找时间复杂度O( log₂NO(1)
是否有序关于Key有序无序
线程安全不安全不安全
插入/删除/查找区别需要进行元素比较通过哈希函数计算哈希地址
比较与覆写Key必须能够比较,否则会抛出ClassCastException异常
自定义类型需要覆写 equals 和hashCode方法
应用场景
需要 Key 有序场景下
Key 是否有序不关心,需要更高的时间性能

Set不存储重复的元素

Set最大的功能就是对集合中的元素进行去重;Set 中只存储了 key ,并且要求 key 一定要唯一

练习

//删除重复的元素
    public static void func1(int[] array){
        Set<Integer> set=new HashSet<>();
        for (int i = 0; i < array.length; i++) {
            set.add(array[i]);
        }
        System.out.println(set);
    }

    //找到第一个重复的数据
    public static int func2(int[] array){
        Set<Integer> set=new HashSet<>();
        for (int i = 0; i < array.length; i++) {
            if (!set.contains(array[i])){
                set.add(array[i]);
            }else {
                return array[i];
            }
        }
        return -1;
    }

    //每个数据重复的次数
    public static void func3(int[] array){
        Map<Integer,Integer> map=new HashMap<>();
        for (int i = 0; i < array.length; i++) {
            int key=array[i];
            if (map.get(key)==null){
                map.put(key,1);
            }else {
                int val=map.get(key);
                map.put(key,val+1);
            }
        }
        System.out.println(map);
    }

    public static void main(String[] args) {
        int[] array=new int[100000];
        Random random=new Random();
        for (int i = 0; i < array.length; i++) {
            array[i]=random.nextInt(5000);
        }
        //func1(array);
        System.out.println(func2(array));
        func3(array);
    }
Set 底层结构
TreeSet
HashSet
底层结构红黑树哈希桶
插入 / 删除 / 查找时间复杂度
O( log₂NO(1)
是否有序关于Key有序不一定有序
线程安全不安全buanq
插入 / 删除 / 查找区别
按照红黑树的特性来进行插入和删除
1. 先计算 key 哈希地址 2. 然后进行插入和删除
比较与覆写
key 必须能够比较,否则会抛出ClassCastException异常
自定义类型需要覆写 equals 和hashCode方法
应用场景
需要 Key 有序场景下
Key 是否有序不关心,需要更高的时间性能

哈希冲突的避免 

由于我们哈希表底层数组的容量往往是小于实际要存储的关键字的数量的,这就导致一 个问题,
冲突的发生是必然的,但我们能做的应该是尽量的降低冲突率。 

闭散列

当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空位置,那么可以  

把key 存放到冲突位置中的 下一个 ” 空位置中去
线性探测、二次探测

 

开散列

首先对关键码集合用散列函数计算散列地址,具有相同地址的关键码归于同一子集合,每一个子集
合称为一个桶,各个桶中的元素通过一个单链表链接起来,各链表的头结点存储在哈希表中。
public class HashBuck {
    static class Node{
        public int key;
        public int val;
        public Node next;

        public Node(int key, int val) {
            this.key = key;
            this.val = val;
        }
    }

    public Node[] array;
    public int usedSize;//记录 当前哈希桶当中 有效数据的个数
    //默认的负载因子
    public static final float DEFAULT_LOAD_FACTOR = 0.75F;

    public void put(int key, int val){
        Node node=new Node(key,val);
        int index=key%array.length;
        Node cur=array[index];
        while (cur!=null){
            if (cur.key==key){
                cur.val=val;
                return;
            }
            cur=cur.next;
        }
        //头插法
        node.next=array[index];
        array[index]=node;
        usedSize++;
        //检查负载因子
        if(loadFactor() >= DEFAULT_LOAD_FACTOR) {
            //进行 扩容
            grow();
        }

    }

    private float loadFactor() {
        return usedSize*1.0f / array.length;
    }

    private void grow() {
        Node[] newArray = new Node[2* array.length];
        //重新的哈希
        /**
         * 1. 遍历数组的每个元素的链表
         * 2. 每遍历到一个节点,就重新哈希  key % len
         * 3. 进行头插法
         */
        for (int i = 0; i < array.length; i++) {
            Node cur = array[i];
            while (cur != null) {
                Node curNext = cur.next;
                //找到新的位置
                int index = cur.key % newArray.length;
                cur.next = newArray[index];
                newArray[index] = cur;
                //这样写对吗?
                //cur = cur.next;
                cur = curNext;
            }
        }
        this.array = newArray;
    }

    public int get(int key){
        int index=key%array.length;
        Node cur=array[index];
        while (cur!=null){
            if (cur.key==key){
                return cur.val;
            }
            cur=cur.next;
        }
        return -1;
    }
}

反射、枚举以及lambda表达式

反射

在运行状态中,能动态的获取当前类或者当前对象的信息这样的机制。

获得Class对象有三种方式

//1.使用Class.forName(“类的全路径名);静态方法
Class<?> c1 = Class.forName("reflectdemo.Student");
//2.使用.class方法
Student student=new Student();
Class<?> c2=student.getClass();
//3.使用类对象的getClass()方法
Class<?> c3=Student.class;

枚举

将一个一个的具体固定的对象在类中实例化列举出来的类就叫作枚举类。这些在枚举类中实例化的

对象一定是具体固定的。枚举类是一种常量的集合,可以理解为:枚举属于一种特殊的类,里面只

包含一组特定的对象。

Enum 常用方法

1、对象.name 方法

该方法返回对象的名字

2、对象.ordinal 方法

该方法返回枚举对象在枚举类中定义的次序/编号,在枚举类中所有对象的编号从0开始

3、类名.values 方法

该方法以数组的形式返回枚举类中定义的所有枚举对象

public enum TestEnum {

    RED("red",2),BLACK("BLACK",3),
    GREEN("GREEN",4),WHITE("WHITE",5);
    public String color;
    public int ordinal;
    TestEnum(String color,int ordinal) {
        this.color = color;
        this.ordinal = ordinal;
    }

    public static void main(String[] args) {
        //拿到枚举实例BLACK
        TestEnum testEnum = TestEnum.BLACK;
        //拿到枚举实例RED
        TestEnum testEnum21 = TestEnum.RED;
        System.out.println(testEnum.compareTo(testEnum21));
        System.out.println(BLACK.compareTo(RED));
        System.out.println(RED.compareTo(BLACK));
    }

    public static void main2(String[] args) {
        TestEnum[] testEnums = TestEnum.values();
        for (int i = 0; i < testEnums.length; i++) {
            System.out.println(testEnums[i]+" 序号:"+testEnums[i].ordinal());
        }

        System.out.println("============");
        TestEnum testEnum = TestEnum.valueOf("GREEN");
        System.out.println(testEnum);



    }

    public static void main1(String[] args) {
        TestEnum testEnum2 = TestEnum.BLACK;
        switch (testEnum2) {
            case RED:
                System.out.println("red");
                break;
            case BLACK:
                System.out.println("black");
                break;
            case WHITE:
                System.out.println("WHITE");
                break;
            case GREEN:
                System.out.println("green");
                break;
            default:
                break;
        }
    }

Lambda表达式

//无返回值无参数
@FunctionalInterface
interface NoParameterNoReturn {
    void test();
}

//无返回值一个参数
@FunctionalInterface
interface OneParameterNoReturn {
    void test(int a);
}

//无返回值多个参数
@FunctionalInterface
interface MoreParameterNoReturn {
    void test(int a,int b);
}

//有返回值无参数
@FunctionalInterface
interface NoParameterReturn {
    int test();
}

//有返回值一个参数
@FunctionalInterface
interface OneParameterReturn {
    int test(int a);
}

//有返回值多参数
@FunctionalInterface
interface MoreParameterReturn {
    int test(int a,int b);
}

public class Test {
    public static void main(String[] args) {
        MoreParameterReturn moreParameterReturn=(x,y)->x+y;
        System.out.println(moreParameterReturn.test(12, 24));
    }

    public static void main5(String[] args) {
        OneParameterReturn oneParameterReturn=x->2*x;
        System.out.println(oneParameterReturn.test(12));
    }

    public static void main4(String[] args) {
        NoParameterReturn noParameterReturn=()->{
            return 10;
        };
        int ret= noParameterReturn.test();
        System.out.println(ret);

        NoParameterReturn noParameterReturn1=()->10;
        int ret1= noParameterReturn.test();
        System.out.println(ret1);
    }

    public static void main3(String[] args) {
        MoreParameterNoReturn moreParameterNoReturn=(a,b)->{
            System.out.println(a+b);
        };
        moreParameterNoReturn.test(12,54);

        MoreParameterNoReturn moreParameterNoReturn1=(a,b)-> System.out.println(a*b);
        moreParameterNoReturn1.test(2,3);
    }

    public static void main2(String[] args) {
        OneParameterNoReturn oneParameterNoReturn=(x)->{
            System.out.println(x);
        };
        oneParameterNoReturn.test(12);
        System.out.println("简化:");
        OneParameterNoReturn oneParameterNoReturn1=x-> System.out.println(x);
        oneParameterNoReturn1.test(54);
        //方法引用
        OneParameterNoReturn oneParameterNoReturn2=System.out::println;
        oneParameterNoReturn2.test(23);
    }

    public static void main1(String[] args) {
        NoParameterNoReturn noParameterNoReturn=new NoParameterNoReturn() {
            @Override
            public void test() {
                System.out.println("测试一下");
            }
        };
        noParameterNoReturn.test();

        NoParameterNoReturn noParameterNoReturn1=()->{
            System.out.println("测试一下1");
        };
        noParameterNoReturn1.test();

        NoParameterNoReturn noParameterNoReturn2=()->{
            System.out.println("测试一下1");
            System.out.println("测试一下2");
        };
        noParameterNoReturn2.test();
    }
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值