集合基础(二)

1.LinkedList

List的实现类,有序可重复。

底层结构:双向链表,链表中数据以节点为单位;

链表结构的特点:增删效率高;根据索引查询遍历修改效率低;

应用场景:在大量做增删,少量做查询的位置适合使用LinkedList;

public class LinkedListDemo {
    public static void main(String[] args) {
        //新建学生对象
        Student s1 = new Student("aaa",15);
        Student s2 = new Student("bbb",20);
        Student s3 = new Student("ccc",20);
        //创建LinkedList对象
        LinkedList<Student> ll = new LinkedList<Student>();
        //增加Student对象元素
        ll.add(s1);
        ll.add(s2);
        ll.add(s3);
        System.out.println(ll);
        //在首位增加元素
        ll.addFirst(new Student("rrr",15));
        //在末尾增加元素
        ll.addLast(new Student("fff",18));
        System.out.println(ll);
        //获取第一个元素
        System.out.println(ll.element());
        //获取第一个元素
        System.out.println(ll.getFirst());
        //根据索引获取元素
        System.out.println(ll.get(0));
        System.out.println(ll.get(1));
        System.out.println(ll.get(2));
    }
}
class Student{
    private String name;
    private int age;

    public Student() {
    }
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

当方法|构造器参数为接口类型的时候,实参可以考虑是否通过一个Lambda表达式进行传递,lambda可以让行为作为参数|数据传递,配合函数式接口可以让定义与实现变得更灵活。

public class ArrayListDemo {
    public static void main(String[] args) {
        User u1 = new User(100,3000);
        User u2 = new User(101,5000);
        User u3 = new User(102,2000);
        User u4 = new User(103,4000);
        //lambda表达式作为参数传递给TreeSet的构造器
        TreeSet<User> aru = new TreeSet<User>((User o1, User o2)->{return o1.getUno()-o2.getUno();});
        aru.add(u1);
        aru.add(u2);
        aru.add(u3);
        aru.add(u4);
        System.out.println(aru);
        System.out.println("=====================");
        User[] user = new User[4];
        user[0] = u1;
        user[1] = u2;
        user[2] = u3;
        user[3] = u4;
        //使用Array.sort给数组排序,排序规则按照lambuda表达式
        Arrays.sort(user,(User o1, User o2)->{return o1.getUno()-o2.getUno();});
        System.out.println(Arrays.toString(user));
    }
}
class User{
    private int uno;
    private int num;

    public User(){
    }
    public User(int uno,int num){
        this.num = num;
        this.uno = uno;
    }

    public int getUno() {
        return uno;
    }

    public void setUno(int uno) {
        this.uno = uno;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    @Override
    public String toString() {
        return "User{" +
                "uno=" + uno +
                ", num=" + num +
                '}';
    }
}

2.HashSet

Set接口的实现类,无序去重;

底层实现原理:哈希表(数组+链表+红黑树)

特点:查询即增删效率高

HashSet与TreeSet之间,如果想要数据存储的时候默认升序或降序推荐使用TreeSet;否则建议选择HashSet。

初始容量:16

扩容因子:0.75,当增加元素的索引达到初始容量的0.75时就会扩容。

哈希表:

  • 数组+链表+红黑树——>jdk8;
  • 数组+链表jdk7之前;

1、把数据计算hashcode()方法的返回值

​ int code = 数据.hashcode();

2、通过hash算法对code计算运算,结果就决定数据存在数组中桶的位置——>索引位置

​ in hash = code%数组长度;

​ hash是通过hash算法得到的结果,作为数组中桶的索引,数据存放的桶的位置

3、确定了数组中对应的索引位置(桶的位置),存储数据之前先判断,桶中是否已经存在当前这个数据值了,如果相等就不存储去重,如果没有相等,第一个数据就可以直接存储进去,以链表的形式连接到最后,或者作为链表头的存在;

确定两个数据值相等的方式:equals方法的返回值是true或者false,true就是相等,去重;false就是不相等,继续判断,当前数据与链表中所有的数据都不相等就能够存储。

public class HashSetPractice {
    public static void main(String[] args) {
        //创建HashSet对象
        HashSet<String> hash = new HashSet<String>();
        //增加元素
        hash.add("abc");
        hash.add("bcd");
        hash.add("cde");
        hash.add("def");
        System.out.println(hash);
        //使用迭代器进行遍历
        Iterator<String> it = hash.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
        //使用增强for循环遍历
        for(String s:hash){
            System.out.println(s);
        }
        System.out.println("============");
        HashSet<Person> hash2 = new HashSet<Person>();
        Person p1 = new Person("小白",15);
        Person p2 = new Person("小新",18);
        Person p3 = new Person("小葵",14);
        Person p4 = new Person("花轮",10);
        Person p5 = new Person("花轮",10);
        Person p6 = new Person("花轮",10);
        //类中的hash.code进行重写后,去重
        hash2.add(p1);
        hash2.add(p2);
        hash2.add(p3);
        hash2.add(p4);
        hash2.add(p5);
        hash2.add(p6);
        System.out.println(hash2);

    }
}
class Person {
    private String name;
    private int age;
    public Person(){}

    public Person(String name,int age){
        this.age = age;
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age &&
                Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {

        return Objects.hash(name, age);
    }
}

hashcode与equals:

  • equals相等hashcode值肯定相等;
  • hashcode相等,equals不一定相等;

3.Map

存储键值对的数据;

k-v一个映射关系——key——>value;

key与value可以为任意类型的一个数据;

一个key只能对应一个value;

key是唯一的,无序的 ———>Set集合

value是可重复的 ————>Collection无序可重复

遍历方式:

  • keySet
  • entrySet
  • values

3.1HashMap

底层结构:哈希表(数组+链表+红黑树)

特点:

  • 存储键值对类型数据;
  • 无序,根据key做去重
  • 查询,修改,删除,增加效率较高

Hash表存储原理:

哈希表:Node节点数组,存储节点数据,节点:key,value,hash,next;

1.put(key,value)存储键值对类型的数据,根据key计算hash值,确定桶的位置

2.找到Node数组中的指定索引位置,判断当前位置中是否存在数据,没有存在直接构建一个Node节点对象 new Node(key,value,hash,null),放入数组如果已经存在值,就比较每一个Node的key与我当前要存储的key是否相等,相等value覆盖,不相等继续判断,最后数据放入链表的最后

默认初始容量:1<<4即16,数组的长度;

加载因子:0.75

最大容量:1<<30

扩容:新数组的容量为原容量的2倍,当添加的数据个数>=原数组长度*0.75的时候就扩容,扩容的是数组的大小。

HashMap存储key如果为自定义引用类型数据时,key类型中要求重写hashcode与equals方法。

1、根据key的值计算hash值

调用hashcode——>hash算法——>得到位桶的索引

2、存放数据

找到对应的节点数组中位桶的位置,先比较缺点是否存在相同的key,然后再决定是否存储这个Node;

拿要存储的新节点的key与原链表中的数据比较,如果原数组中指定位置没有节点数据,新节点放入数组的对应位置,如果存在数据,依次拿key与每一链表中的节点的key比较equals是否相等,相等value覆盖,不相等则加入链表的最后。

值得注意的是:当链表中的数据个数超过8个,并且总容量超过64,则会把链表转为红黑树。

public class HashMapDemo {
    public static void main(String[] args) {
        HashMap<Integer,String> hmp = new HashMap<Integer, String>();
        hmp.put(100,"a");
        hmp.put(103,"b");
        hmp.put(101,"c");
        hmp.put(102,"d");
        System.out.println(hmp);
        System.out.println("============");
        //keyset遍历
        Set<Integer> set = hmp.keySet();
        Iterator<Integer> it = set.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
        System.out.println("============");
        //entryset遍历
        Set<Map.Entry<Integer, String>> set2 = hmp.entrySet();
        for(Map.Entry<Integer, String> entrys :set2){
            System.out.println(entrys.getKey()+"-----》"+entrys.getValue());
        }
        System.out.println("============");
        //values遍历
        Collection<String> cl = hmp.values();
        for(String s:cl){
            System.out.println(s);
        }
        //替换  返回值boolean 替换成功返回true,失败返回false
        System.out.println(hmp.replace(101,"c","haha"));
        System.out.println(hmp);
        //返回值:被替换的value值,
        System.out.println(hmp.replace(102,"e"));
        System.out.println(hmp);
        System.out.println("=============");
        Actor a1 = new Actor("aaa",15);
        Actor a2 = new Actor("abc",16);
        Actor a3 = new Actor("bbb",17);
        Actor a4 = new Actor("ccc",15);
        HashMap<Actor,Integer> hmp2 = new HashMap<Actor,Integer>();
        System.out.println("===========");
        //添加元素
        System.out.println(hmp2.put(a1,15));
        System.out.println(hmp2.put(a2,16));
        System.out.println(hmp2.put(a3,17));
        System.out.println(hmp2.put(a4,15));
        //获取每一个元素的hashcode
        System.out.println(hmp2.get(a1).hashCode());
        System.out.println(hmp2.get(a2).hashCode());
        System.out.println(hmp2.get(a3).hashCode());
        System.out.println(hmp2.get(a4).hashCode());
        //输出打印集合
        System.out.println(hmp2);
    }
}
class Actor{
    private String name;
    private int age;
    
    public Actor(){}
    public Actor(String name,int age){
        this.age = age;
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Actor{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Actor actor = (Actor) o;
        return age == actor.age &&
                Objects.equals(name, actor.name);
    }
    @Override
    public int hashCode() {

        return Objects.hash(name, age);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值