List、Set、数据结构、Collections常用方法

第一章 List集合

1.List集合介绍

List接口继承自Collection接口,是单列集合的一个重要分支。习惯把所有实现list接口的对象称之为list集合。在list集合中允许出现重复的元素,所有元素是以一种线性方式进行存储的,在程序中可以通过索引来访问集合指定元素,List集合是有序的,也就是说存入的顺序和取出的顺序是一致的。

2.List集合常用方法

List作为Collection集合的子接口,继承了Collection中的全部方法,而且还增加了一些特有方法:

  • public void add(int index ,E element): 将指定的元素,添加到该集合中的指定位置上。

  • public E get(int index): 返回集合中指定位置的元素

  • public E remove(int index): 移除列表中指定位置的元素,返回的是被移除的元素。

  • public E set(int index ,E element): 用来指定元素替换集合中指定位置的元素,返回的是更新前的元素

List集合的特有方法都跟索引有关。

其实List接口下有很多集合 ,他们有什么区别呢? 其实就是数据结构不同。

第二章 数据结构

1.数据结构介绍

数据结构: 数据用什么样的方式组合在一起的。

2.常见数据结构

数据存储的常见结构有:栈、队列、数组、链表、红黑树.....

  • 栈:stack,也可以叫堆栈,它是运算受限的线性表,限制的是仅允许在一端进行插入和删除操作,不允许在其他位置进行添加、查找、删除等操作。

用该结构的集合 有以下特点。

  • 先进后出(存进去的元素,要在它后面的元素依次取出后才能取出该元素)。例如子弹压进弹夹。

  • 栈的入口和出口都是栈的顶端位置。

  • 压栈:就是存元素。也就是说把元素存储到栈的顶端,栈中已经有的元素依次向栈底移动一个位置。

  • 弹栈:就是取元素。也就是把栈的顶端位置元素取出,栈中已有的元素依次向栈顶端移动一个位置。

队列

  • 队列:queue,简称队,也是一种运算受限的线性表,限制的是仅允许在表的一端进行插入,另一端进行删除。

  • 先进先出(存进去的元素,要在后它前面的元素依次取出后,才能取出该元素)火车过隧道。

  • 队列的入口、出口各占一侧。例如 左侧为入口、右侧为出口

数组

  • 数组:array,是有序的元素序列,数组是在内存中开辟一段连续的空间,并在此存放元素。例如 有100个出租房,001 到100 每个房间固定编号,通过编号可以快速找到对应的人。

特点:

  • 查找元素快:存储元素的地址值是连续的,数组长度固定,可以通过索引,快速的访问到指定位置的元素。(数据地址=首元素地址+偏移量)

  • 增删元素慢

  • 在指定位置增加元素:需要创建一个新的数组,将指定新元素存储在指定索引位置,再把原数组元素根据索引 复制到新数组对应索引位置。

  • 指定索引位置删除元素:需要创建一个新数组,把原数组的元素根据索引,复制到新数组对应索引位置,原数组中指定索引位置元素不复制。

链表

  • 链表:linked list,由一系列结点node(链表中每一个元素称之为结点)组成,结点可以在运行时动态生成。每个结点包含两个部分:一个部分存储数据元素的数据域,另一个存储下一个结点地址值的指针域。我们常说的链表结构有单向链表与双向链表。

  • 链表结构:

  • 多个结点之间,通过地址进行链接。例如手拉手,每个人的右手连着下一个人的左手,依次类推 多个人就连接到一起了。

  • 查找元素慢: 想要查找某个元素,需要通过连接的结点,依次向后查找指定元素。

  • 增删元素快:                                                                                                                           红线表示添加节点,蓝线表示删除节点过程:

红黑树

  • 二叉树:binary tree ,就是每个结点不超过2的有序树。

二叉树是每个结点最多有两个子树的树结构。顶上的叫根节点,两边分别称作左子树和右子树。

红黑树是二叉树的一种,可以通过黑红结点尽可能的保证二叉树的平衡,从而提高效率。

红黑树的约束:

1.节点可以是红色或者黑色的。

2.根节点必须是黑色的。

3.叶子节点(特指空节点)是黑色的。

4.每个红色节点的子节点都是黑色的。

5.任何一个节点到每一个叶子节点的所有路径上的黑色节点数量相同。

速度特别快,趋近于平衡树,查找叶子元素最多和最少的次数不多于两倍。

如:

第三章 List的实现类

1.ArrayList集合

ArrayList是数组结构。元素增删慢、查找快。用于日常开发中使用最多的功能为查询数据、遍历数据。 所以ArrayList是最常用的集合。

实际开发中很多程序员都随意的使用ArrayList完成任何需求,这种做法是不提倡的。

2.LinkedList集合

java.util.LinkedList集合存储数据的结构是链表结构 ,方便元素的添加、删除的集合。

LinkedList是一个双向链表,如图;

实际开发中经常会对集合进行添加或者删除 ,最常涉及的就是首尾操作,Linkedlist提供了大量的首尾操作方法。

  • public void addFirst(E e): 将指定元素插入到列表的开头

  • public void addLast(E e):将指定元素添加到列表的结尾

  • public E getFirst(): 返回此列表的第一个元素

  • public E getLast(): 返回此列表的最后一个元素

  • public E removeFirst(): 移除并返回此列表的第一个元素

  • public E removeLast(): 移除并返回此列表的最后一个元素

  • public boolean isEmpty(): 如果列表不包含元素 则返回true

LinkedList是List的实现类。List中的方法LinkedList都可以使用。

第四章 Set接口

1.Set集合介绍

List接口和Set接口都继承于Collection接口 接口中方法基本一致,并没有对Collection接口进行功能上的扩充,只是比Collection更严格了。Set接口与List接口不同的是 Set接口中元素无序,并且都会以某种规则保证元素不出现重复。

Set集合有很多实现类,我们主要介绍其中的java.util.HashSet、java.util.LinkedHashSet这两个集合。

Set集合取出元素方式可以采用:迭代器、增强for

2.HashSet集合介绍

存储的元素是不重复的,并且元素都是无序的。

代码示例:

public class Demo01 {
    public static void main(String[] args) {
       //创建set集合
        HashSet<String> set=new HashSet<>();
        //添加元素
        set.add("abc1");
        set.add("abc2");
        set.add("abc3");
        set.add("abc4");
        set.add("abc");//直接添加
        set.add(new String("qqq"));//创建添加
        String str = "www";
        set.add(str);//引用添加
        set.add("qqq");//重复添加了但是不会被打印
        System.out.println("qqq".hashCode());
        System.out.println("abc".hashCode());
        //是根据hashCode()表排序,但不是大小顺序,有一定规律
        //遍历集合
        for (String s : set) {
            System.out.println("s = "+s);

        }
    }
}

3.HashSet集合存储数据的结构(哈希表)

什么是哈希表?

jdk1.8之前,哈希表底层采用数据+链表实现,也就是使用数组处理冲突,同一hash值的链表都存储在一个数组中。当链表长度不平衡或者过高查找效率就变低了,jdk1.8之后,哈希表采用数组+链表+红黑树的方式实现,也就是说当链表长度超过8时,将链表转换为红黑树,大大的减少了查询时间。

这个到底是怎么存储的?

HashSet存储原理----也就是HashMap底层

开始计算索引,做逻辑判断。

总结: 1.8引入了红黑树大程度的优化了hashMap的性能。

对于我们来说如何保证hashset集合元素的唯一性?其实就是根据对象的hashCode和equals方法来决定的 。如果我们往集合中存放自定义对象,那么保证唯一,就必须重写hashCode和equals方法建立属于当前对象的比较方式。

4.HashSet存储自定义类型元素

给HashSet中存放自定义类型的元素时,需要重写对象中的hashCode和equals方法,建立自己的比较方法,才能保证HashSet集合中的对象唯一性。

如用HashSet存储学生姓名和年龄并遍历打印成员信息:

import java.util.Objects;

public class Student {
    private String name;
    private int age;

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

    @Override
    public boolean equals(Object o) {
        if (this == o) return true; //调用者与传入形参地址相同
        if (o == null || getClass() != o.getClass()) return false;//传入类型与当前类型不同
        Student student = (Student) o;
        return age == student.age &&  //地址不相同但类型相同情况下比较内容
                Objects.equals(name, student.name);//两个参数的equal对比
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, 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;
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
import java.util.HashSet;

public class Demo02 {
    public static void main(String[] args) {

        HashSet<Student> students=new HashSet<>();
        students.add(new Student("张飞",33));
        students.add(new Student("关羽",23));
        students.add(new Student("张飞",33));
        //两个张飞,因为new了两次,认为是两个不同地址所以不重写hashCode和equals方法也会打印两次
        //但我重写hashCode和equals方法后就只能保留一个了,没重写时只对比了地址。
        Student stu=new Student("刘备",22);
        students.add(stu);//因为只new了一次,认为两次添加同一地址元素,未重写也只保存一个刘备
        students.add(stu);
        for (Student student : students) {
            System.out.println("students = "+student);

        }
    }

}

5.LinkedHashSet

可以保证元素有序且唯一,HashSet下有一个子类,java.util.LinkedHashSet,它是链表和哈希表组合的一个数据结构。

代码演示:

public class Demo03 {
    public static void main(String[] args) {
        Set<String> set=new LinkedHashSet<>() ;//有序且唯一去重
        set.add("aaa");
        set.add("bbb");
        set.add("ccc");
        set.add("ddd");
        set.add("eee");
        set.add("aaa");
        set.add("aaa");
        Iterator<String> iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}

第五章Collections类

1.Collections常用功能

  • java.utils.Collections 是集合的工具类 用来提供对集合进行操作的方法。

  • public static void shuffle(List<E> list) :打乱集合顺序。

  • public static <T> void sort (List<T> list): 将集合中元素按照默认的规则进行排序(如果是基本数据类型会根据数字大小顺序排序;如果是String类型会根据首字母ASCII来排序);

  • public static <T> void sort(List<T> list,Comparator<? super T>): 将集合中的元素按照指定规则排序。(自定义类型按自己想要的要求排序时就不能只用Collections.sort(list1),还外加了一个比较器)

如学生类按年龄排序

ArrayList<Student> list2=new ArrayList<>();

        list2.add(new Student("张飞",33));
        list2.add(new Student("关羽",23));
        list2.add(new Student("刘备",35));
        Collections.sort(list2, new Comparator<Student>() {
            @Override
            public int compare(Student t1, Student t2) {
                return t1.getAge()-t2.getAge();//升序
            }
        });

如定义一个ArrayList类,用来存储1-10之间的数  1.打乱顺序输出  2.从小到大输出  3.从大到小输出

public class Demo04 {
    public static void main(String[] args) {
        ArrayList<Integer>list=new ArrayList<>();
        for (int i = 1; i <=10 ; i++) {
            list.add(i);
        }
        Collections.shuffle(list);
        System.out.println("打乱顺序后list = " + list);

        Collections.sort(list, new Comparator<Integer>() {
            @Override
            public int compare(Integer t1, Integer t2) {
                return t1-t2;
            }
        });
        System.out.println("从小到大list = " + list);
        //将本已排好正序的序列倒转成逆序
        Collections.sort(list,Collections.reverseOrder());
        System.out.println("从大到小list = " + list);

    }
}

回顾小练习:编写一个22选5的彩票选号系统,每次选出不同的五组号码,并输出到控制台中。

分析:方法1.删除集合中元素 删除到只剩下五个。

           方法2.采用随机数随机抽取五个不同的数放入新集合中,每次随机出来的需要判断新集合中是否包含 如果包含需要重新随机 直到新集合中够5个位置。

public class Demo05 {
    public static void main(String[] args) {
        List<Integer> numbers =new ArrayList<>();
        for (int i = 1; i <= 22 ; i++) {
            numbers.add(i);
        }
            Random random =new Random();

        //第一种,随机删元素,直到只剩5个
//            while(numbers. size ()>5) {
//                int index = random.nextInt(numbers.size());
//                numbers.remove(index);
//            }
//                System.out.println("numbers = " + numbers);

        //第二种,随机拿5个到新数组
        List<Integer> result =new ArrayList<>();
        while (result.size()<5){
            int index = random.nextInt(numbers.size());
            int number = numbers.get(index);
            if (!result.contains(number)){
                result.add(number);
                numbers.remove(index);
            }
        }
        System.out.println("result = " + result);
    }
}

  • 24
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值