Java集合进阶——集合体系结构及各个集合的方法

        Java种的集合分为单列集合和双列集合,单列集合的最高层接口是Collection,双列集合的最高层是Map,这里先介绍单列集合

单列集合

体系结构:

注:红色框都为接口,蓝色框都为实现类(实现类Vector已经被淘汰)

Collection:

        Collection是一个接口,不能直接创建他的对象,所以学习他的方法时,只能创建他的实现类对象。例如ArrayList。

代码演示:
public class CollectionDemo {public static void main(String[] args) {/*public boolean add(E e)             添加public void clear()                 清空public boolean remove(E e)          删除public boolean contains(Object obj) 判断是否包含public boolean isEmpty()            判断是否为空public int size                     集合长度*/Collection<String> coll = new ArrayList<>();//1.添加//注:添加方法会返回一个布尔类型的值//如果我们往List系列集合中添加数据,一定会返回true,因为List系列集合是允许元素重复的//如果往Set系列集合中添加数据,当元素不存在时才会返回true,否则返回false,因为Set集合时不允许重复的coll.add("aa");coll.add("bb");coll.add("cc");System.out.println(coll);//2.清空coll.clear();System.out.println(coll);//再添加回来coll.add("aa");coll.add("bb");coll.add("cc");//3.删除coll.remove("bb");System.out.println(coll);//4.判断是否包含boolean result1 = coll.contains("bb");System.out.println(result1);//5.判断是否为空boolean result2 = coll.isEmpty();System.out.println(result2);//6.集合长度int size = coll.size();System.out.println(size);}
}
运行结果:

(1)contains方法的拓展:

        如果让contains方法判断自定义的类对象,需要重写equals方法才能得到正确结果,因为contains方法底层就调用了equals方法,如果没有重写,默认使用的就是Object类中的equals方法,比较的是地址值。

没有重写equals时
代码演示:
学生类Student:
public class Student {private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}/*** 获取* @return name*/public String getName() {return name;}/*** 设置* @param name*/public void setName(String name) {this.name = name;}/*** 获取* @return age*/public int getAge() {return age;}/*** 设置* @param age*/public void setAge(int age) {this.age = age;}public String toString() {return "Student{name = " + name + ", age = " + age + "}";}
}
测试类Test:
public class CollectionContainsDemo {public static void main(String[] args) {Collection<Student> coll = new ArrayList<>();Student s1 = new Student("xiaobai",21);Student s2 = new Student("xiaohei",22);Student s3 = new Student("xiaohei", 22);//与上面s2一样coll.add(s1);coll.add(s2);boolean result = coll.contains(s3);System.out.println(result);}
}
运行结果:

重写equals时
代码演示:
Student类:

加入下面这段代码

@Overridepublic 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);}

        测试类不改变

运行结果:

(2)Collection系列集合三种通用的遍历方式:

        ①迭代器遍历

        ②增强for遍历

        ③lambda表达式遍历

接下来进行代码演示:

①迭代器遍历:

迭代器遍历相关的三个方法:

        Iterator<E> iterator()        :        获取一个迭代器对象

        boolean hasNext()           :        判断当前指向的位置是否有元素

        E next()                            :        获取当前指向的元素并移动指针

代码演示:
public class ErgodicDemo {public static void main(String[] args) {//迭代器遍历相关的三个方法://Iterator<E> iterator():获取一个迭代器对象//boolean hasNext(): 判断当前指向的位置是否有元素//E next():获取当前指向的元素并移动指针//创建集合并添加元素Collection<String> coll = new ArrayList<>();coll.add("aa");coll.add("bb");coll.add("cc");//获取迭代器对象Iterator<String> it = coll.iterator();while(it.hasNext()) {String str = it.next();System.out.println(str);}}
}
运行结果:

迭代器注意点:

        1.指针指向没有元素的位置时再强行调用next方法,会报错NoSuchElementException

        2.迭代器遍历完毕,指针不会复位

        3.循环中只能用一次next方法

        4.迭代器遍历时,不能用集合的方法进行增加或者删除(可以使用迭代器的remove方法删除)

②增强for遍历:

        格式:

                for(数据类型 变量名 : 集合/数组){

                        方法体

                }

        快速生成方式:集合名字.for 再按回车

代码演示:
public class EnhancedFor {public static void main(String[] args) {//创建集合并存储元素Collection<String> coll = new ArrayList<>();coll.add("aa");coll.add("bb");coll.add("cc");//增强for遍历//循环遍历中,下面的第三方变量s会依次表示集合中的每一个元素for(String s : coll) {System.out.println(s);}}
}
运行结果:

增强for注意点:

        修改增强for中的变量,不会改变集合中原本的数据。因为增强for中使用了参数中设置的第三方变量存储,修改的是第三方变量的值。

③Lambda表达式:
代码演示:
public class LambdaDemo {public static void main(String[] args) {//default void forEach(Consumer<? super T> action)://1.创建集合并添加元素Collection<String> coll = new ArrayList<>();coll.add("aa");coll.add("bb");coll.add("cc");//2.使用匿名内部类遍历coll.forEach(new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}});System.out.println("----------------------");//3.使用Lambda表达式遍历coll.forEach(s -> System.out.println(s));}
}
运行结果:

④三种遍历方式适用情况:

        若在遍历过程中需要删除元素,则使用迭代器

        若仅仅想遍历,则使用增强for或Lambda表达式

1.List

        List系列集合特点:有序,可重复,有索引

        虽然Collection的方法List都继承了,但List集合因为有索引,所以多了很多索引操作的方法,下面介绍一下List系列集合独有的方法。

List系列集合独有的方法

代码演示:
public class ListDemo {public static void main(String[] args) {/*List系列集合独有的方法:void add(int index,E element)   在此集合中的指定位置插入指定的元素E remove(int index)             删除指定索引处的元素,返回被删除的元素E set(int index,E element)      修改指定索引处的元素,返回被修改的元素E get(int index)                返回指定索引处的元素*///1.创建一个集合并添加元素List<String> list = new ArrayList<>();list.add("aa");list.add("bb");list.add("cc");//2.void add(int index,E element)   在此集合中的指定位置插入指定的元素list.add(1,"ee");System.out.println(list);System.out.println("----------------");//3.E remove(int index)   删除指定索引处的元素,返回被删除的元素/*remove注意点:当集合中存储的是int类型的数据,删除时输入int类型整数,会首先认为是删除索引,但是输入一个Integer类型的变量,则会认为是删除元素*/String remove = list.remove(1);System.out.println("被删除的元素:" + remove);System.out.println(list);System.out.println("----------------");//4.E set(int index,E element)  修改指定索引处的元素,返回被修改的元素String result = list.set(1, "ee");System.out.println("被修改的元素:" + result);System.out.println(list);System.out.println("----------------");//5.E get(int index)    返回指定索引处的元素System.out.println(list.get(0));}
}
运行结果:

List集合的遍历方式

        List继承了Collection,所以Collection中的遍历方式在List中都可以使用,即:

  ①迭代器遍历
  ②增强for遍历
  ③Lambda表达式遍历

此外List系列集合还有自己的遍历方式,即:

  ④普通for遍历
     代码演示:
public class OrdinaryFor {public static void main(String[] args) {//创建集合并添加元素List<String> list = new ArrayList<>();list.add("aa");list.add("bb");list.add("cc");//遍历for (int i = 0; i < list.size(); i++) {String str = list.get(i);System.out.println(str);}}
}
运行结果:

⑤列表迭代器遍历

        它可以在遍历时添加和删除元素

    代码演示:
public class ListIteraterDemo {public static void main(String[] args) {//创建集合并添加元素List<String> list = new ArrayList<>();list.add("aa");list.add("bb");list.add("cc");//创建列表迭代器ListIterator<String> it1 = list.listIterator();//遍历while(it1.hasNext()) {String str = it1.next();System.out.println(str);}//它可以在遍历中添加或删除元素ListIterator<String> it2 = list.listIterator();while(it2.hasNext()) {String str = it2.next();if("aa".equals(str)) {it2.add("ee");}if("cc".equals(str)) {it2.remove();}}System.out.println(list);}
}
运行结果:

五种遍历方式总结:

        在遍历过程中需要删除元素时,使用迭代器

        在遍历过程中需要添加元素时,使用列表迭代器

        如果仅仅想遍历,使用增强for或者Lambda表达式

        如果遍历时想操作索引,可以使用普通for

(1)ArrayList

        ArrayList底层是数组结构

底层原理:

        ①利用空参创建的集合,在底层创建一个默认长度为0的数组

        ②添加第一个元素时,底层会创建一个新的长度为10的数组

        如图(elementDate是数组名,size是指针)

        ③存满时,会扩容1.5倍(即第一次存满后数组大小扩容到15)

        ④如果一次添加多个元素,扩容到1.5倍放不下,则新建数组的长度以实际为准(即一开始十             个数据存满数组的情况下,再一次性添加100个元素,那么新数组长度就为110)

 迭代器底层原理图解:

(2)LinkedList

        LinkedList底层数据结构是双向链表,查询慢,增删快,但是如果操作的是首尾元素,速度也是极快的

双向链表模型:

        由于上述特点,LinkedList中多了很多首尾操作的特有API,例如:

public void addFirst(E e)在该列表开头插入指定的元素
public void addLast(E e)将指定的元素追加到此列表的末尾
public E getFirst()返回此列表中的第一个元素
public E getLast()返回此列表中的最后一个元素
public E removeFirst()从此列表中删除并返回第一个元素
public E removeLast()从此列表中删除并返回最后一个元素
添加元素原理图解:

2.Set

        Set系列集合特点:无序,不可重复,无索引

Set中的方法:

        Set是一个接口,这个接口中的方法基本上与Collection中的API一致,方法如下

        public boolean add(E e)             添加
        public void clear()                 清空
        public boolean remove(E e)          删除
        public boolean contains(Object obj) 判断是否包含
        public boolean isEmpty()            判断是否为空
        public int size                     集合长度

        这部分方法在前文Collection模块中已经演示,这里不再演示。

Set的遍历方法:

        也可以使用Collection中的遍历方法,如:

        ①迭代器遍历

        ②增强for遍历

        ③Lambda表达式遍历

        这三种方法前文已经演示,注意因为Set系列集合没有索引,所以不能使用普通for遍历

(1)HashSet

特点:

        无序,不可重复,无索引

HashSet底层原理概要:

        HashSet集合底层采取哈希表存储数据

        哈希表是一种对于增删查改数据性能都较好的结构

接下来我们先介绍一下哈希表

哈希表:
        组成:

                JDK8之前:数组 + 链表

                JDK8开始:数组 + 链表 + 红黑树

        哈希表中有一个非常重要的值:哈希值

        哈希值:

                可以理解为对象的整数表现形式

                ·根据hashCode方法算出来的int类型的整数

                ·该方法定义在Object类中,所有对象都可以调用,默认使用地址值进行计算

                ·一般情况下,会重写hashCode方法,利用对象内部的属性值计算哈希值

        对象哈希值的特点:

                ·如果没有重写hashCode方法,不同对象计算出的哈希值是不同的

                ·如果已经重写hashCode方法,不同的对象只要属性值相同,计算出的哈希值也一样

                ·在小部分情况下,不同的属性值或者地址值计算出来的哈希值有可能一样(哈希碰撞)

       
未重写hashCode情况代码演示

        编写学生类来创建对象

        Student:

public class Student {private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}/*** 获取* @return name*/public String getName() {return name;}/*** 设置* @param name*/public void setName(String name) {this.name = name;}/*** 获取* @return age*/public int getAge() {return age;}/*** 设置* @param age*/public void setAge(int age) {this.age = age;}public String toString() {return "Student{name = " + name + ", age = " + age + "}";}
}

        编写测试类:

        HashSetDemo1:

public class HashSetDemo1 {public static void main(String[] args) {//创建两个属性一样的学生对象Student s1 = new Student("xiaobai", 21);Student s2 = new Student("xiaobai", 21);System.out.println(s1.hashCode());System.out.println(s2.hashCode());}
}
运行结果

未重写hashCode情况代码演示

        在Student类中加入了重写的hashCode方法

        Student:

public class Student {private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}/*** 获取* @return name*/public String getName() {return name;}/*** 设置* @param name*/public void setName(String name) {this.name = name;}/*** 获取* @return age*/public int getAge() {return age;}/*** 设置* @param age*/public void setAge(int age) {this.age = age;}@Overridepublic int hashCode() {return Objects.hash(name, age);}public String toString() {return "Student{name = " + name + ", age = " + age + "}";}
}

        HashSetDemo1中的代码不变

运行结果

HashSet的底层原理

注意:

        1.如果元素应存入位置已经有多个元素形成链表,需要调用equals方法比较每个元素,若都不一样,则挂在链表最后。

        2.默认加载因子:默认加载因子为0.75表示当数组里面存了16 * 0.75 = 12个元素时,数组就会扩容成原来的两倍。

        3.当链表长度大于8而且数组长度大于等于64时,这个链表将会自动转成红黑树,从而提高查找效率。

        4.如果集合中存储的是自定义对象,必须要重写hashCode和equals方法。

HashSet小练习:

需求:创建一个存储学生对象的集合,存储多个学生对象 使用程序实现在控制台遍历该集合
要求:学生对象的成员变量值相同,我们就认为是同一个对象

代码演示:
Student类:
public class Student {private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}/*** 获取* @return name*/public String getName() {return name;}/*** 设置* @param name*/public void setName(String name) {this.name = name;}/*** 获取* @return age*/public int getAge() {return age;}/*** 设置* @param age*/public void setAge(int age) {this.age = age;}@Overridepublic 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);}@Overridepublic int hashCode() {return Objects.hash(name, age);}public String toString() {return "Student{name = " + name + ", age = " + age + "}";}
}
测试类HashSetTest1:
public class HashSetTest1 {public static void main(String[] args) {/*需求:创建一个存储学生对象的集合,存储多个学生对象使用程序实现在控制台遍历该集合要求:学生对象的成员变量值相同,我们就认为是同一个对象*/HashSet<Student> hashSet = new HashSet<>();//创建学习对象    三个xiaobai 两个xiaohei 一个xiaohuangStudent s1 = new Student("xiaobai",21);Student s2 = new Student("xiaobai",21);Student s3 = new Student("xiaobai",21);Student s4 = new Student("xiaohei",20);Student s5 = new Student("xiaohei",20);Student s6 = new Student("xiaohuang",20);//添加到集合中hashSet.add(s1);hashSet.add(s2);hashSet.add(s3);hashSet.add(s4);hashSet.add(s5);hashSet.add(s6);//遍历Iterator<Student> it = hashSet.iterator();while(it.hasNext()) {Student str = it.next();System.out.println(str);}}
}
运行结果:

注意:

        如果未在Student类中重写hashCode和equals方法,属性值相等的对象也是会存入集合的。

LinkedHashSet:
特点:

        LinkedHashSet是有序(存储和取出的元素顺序一致),无重复,无索引的

代码演示:
public class LinkedHashSetDemo1 {public static void main(String[] args) {LinkedHashSet<Student> lhs = new LinkedHashSet<>();Student s1 = new Student("xiaobai", 20);Student s2 = new Student("xiaohei", 21);Student s3 = new Student("xiaohuang", 22);Student s4 = new Student("xiaohei", 21);lhs.add(s1);lhs.add(s2);lhs.add(s3);lhs.add(s4);System.out.println(lhs);}}
运行结果:
原理:

        底层数据结构依然是哈希表,只是每个元素又额外多了一个双链表的机制记录存储的顺序

        如下图红色双线表示双链表存储

适用情况:

        如果只需要数据去重,那么默认使用HashSet

        如果要求去重且存取有序,就使用LinkedHashSet

(2)TreeSet
特点:

        不重复,无索引,可排序(按照元素的默认规则从小到大排序)

        TreeSet集合底层是基于红黑树的数据结构(不了解红黑树可以查看作者的另一篇文章《Java基合进阶——数据结构》)实现排序的,增删改查性能都较好

代码演示:
public class TreeSetDemo1 {public static void main(String[] args) {TreeSet<Integer> ts = new TreeSet<>();ts.add(3);ts.add(5);ts.add(2);ts.add(1);ts.add(4);System.out.println(ts);}
}
运行结果:

若使用Collection中的那三种遍历方式遍历,也会得到这个顺序的结果

排序规则:

        对于数值类型:Integer,Double,默认按照从小到大的顺序进行排序

        对于字符、字符串类型:按照字符在ASCII码表中的数字升序进行排序

        (字符串中从第一个字母挨个比较,并且若前若干个字母一样,后面没有字母的那个字符串排在后边还有字母的字符串前面,例如:aaa,ab,aba 这样排序)

TreeSet的两种比较方式

        TreeSet有两种比较方式,为默认排序/自然排序和比较器排序

使用原则:

        默认使用第一种,如果第一种不能满足当前需求(比如字符串中默认的规则需要修改,或者Integer默认排序规则为从小到大若不是用这个规则则使用第二种),就使用第二种

1.默认排序/自然排序:

        对数据类型可直接使用,对自定义对象使用需要先在自定义的JavaBean中实现Comparable接口,并重写其中的compareTo方法,在这个方法中可以定义根据什么排序。

下面举例一个重写后的compareTo方法,它的作用是只看年龄,按照年龄的升序进行排列

@Override
public int compareTo(Student o){return this.getAge() - o.getAge();
}

this:表示当前要添加的元素        o:表示已经在红黑树存在的元素

返回值:

        负数:认为要添加的元素是小的,存左边

        正数:认为要添加的元素是大的,存右边

        0     :认为要添加的元素已经存在,舍弃

当添加某元素后TreeSet的数据结构不满足红黑树的规则了,它就会自己通过调整节点颜色或左旋右旋调整来满足红黑树的规则(想要详细了解可以看作者的另一篇文章《Java集合进阶——数据结构》)

2.比较器排序

        创建TreeSet对象时候,传递比较器Comparator指定规则

比较器排序小练习1:

        需求:存入四个字符串:"c","ab","df","qwer"

        按照长度排序,如果一样长则按照首字母排序

代码演示:
public class TreeSetTest1 {public static void main(String[] args) {//需求:存入四个字符串:"c","ab","df","qwer"//按照长度排序,如果一样长则按照首字母排序//创建TreeSet对象TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {//o1为要添加的元素//o2为已经在红黑树中存在的元素//返回值的规则跟之前一样@Overridepublic int compare(String o1, String o2) {//根据长度排序int i = o1.length() - o2.length();//根据字母排序//如果i == 0即长度相等,那么就使用默认的比较规则,按字母排序,//如果长度不相等,那么直接根据长度排序i = i == 0 ? o1.compareTo(o2) : i;return i;}});//添加元素ts.add("c");ts.add("ad");ts.add("df");ts.add("qwer");//输出System.out.println(ts);}}
运行结果:

 比较器排序小练习2:

        需求:创建5个学生对象

        属性:姓名,年龄,语文成绩,数学成绩,英语成绩

        按照总分从高到低输出到控制台

        如果总分一样,按照语文成绩排

        如果语文成绩一样,按照数学成绩排

        如果数学成绩一样,按照英语成绩排

        如果英语成绩一样,按照年龄排

        如果年龄一样,按照姓名的字母顺序排

        如果都一样,认为是同一个学生,不存

代码演示:

Student2:

public class Student2 implements Comparable<Student2>{private String name;private int age;private int chineseGrade;private int mathGrade;private int englishGrade;public Student2() {}public Student2(String name, int age, int chineseGrade, int mathGrade, int englishGrade) {this.name = name;this.age = age;this.chineseGrade = chineseGrade;this.mathGrade = mathGrade;this.englishGrade = englishGrade;}/*** 获取* @return name*/public String getName() {return name;}/*** 设置* @param name*/public void setName(String name) {this.name = name;}/*** 获取* @return age*/public int getAge() {return age;}/*** 设置* @param age*/public void setAge(int age) {this.age = age;}/*** 获取* @return chineseGrade*/public int getChineseGrade() {return chineseGrade;}/*** 设置* @param chineseGrade*/public void setChineseGrade(int chineseGrade) {this.chineseGrade = chineseGrade;}/*** 获取* @return mathGrade*/public int getMathGrade() {return mathGrade;}/*** 设置* @param mathGrade*/public void setMathGrade(int mathGrade) {this.mathGrade = mathGrade;}/*** 获取* @return englishGrade*/public int getEnglishGrade() {return englishGrade;}/*** 设置* @param englishGrade*/public void setEnglishGrade(int englishGrade) {this.englishGrade = englishGrade;}public String toString() {int sum = chineseGrade + mathGrade + englishGrade;return "Student2{name = " + name + ", age = " + age + ", chineseGrade = " + chineseGrade + ", mathGrade = " + mathGrade + ", englishGrade = " + englishGrade + ", sum = " + sum + "}";}@Overridepublic int compareTo(Student2 o) {int score1 = this.getChineseGrade() + this.getMathGrade() + this.getEnglishGrade();int score2 = o.getChineseGrade() + o.getMathGrade() + o.getEnglishGrade();int i = score1 - score2;i = i == 0 ? this.getChineseGrade() - o.getChineseGrade() : i;i = i == 0 ? this.getMathGrade() - o.getMathGrade() : i;i = i == 0 ? this.getEnglishGrade() - o.getEnglishGrade() : i;i = i == 0 ? this.getAge() - o.getAge() : i;i = i == 0 ? this.getName().compareTo(o.getName()) : i;return i;}
}

测试类TreeSetTest2:

public class TreeSetTest2 {public static void main(String[] args) {//需求:创建5个学生对象//属性:姓名,年龄,语文成绩,数学成绩,英语成绩//按照总分从高到低输出到控制台//如果总分一样,按照语文成绩排//如果语文成绩一样,按照数学成绩排//如果数学成绩一样,按照英语成绩排//如果英语成绩一样,按照年龄排//如果年龄一样,按照姓名的字母顺序排//如果都一样,认为是同一个学生,不存//创建集合并定义排序规则TreeSet<Student2> ts = new TreeSet<>();//创建对象Student2 s1 = new Student2("laoda",20,65,66,67);Student2 s2 = new Student2("laoer",21,67,66,67);Student2 s3 = new Student2("laosan",22,65,66,67);Student2 s4 = new Student2("laosi",21,65,68,67);Student2 s5 = new Student2("laowu",22,65,80,69);//添加对象ts.add(s1);ts.add(s2);ts.add(s3);ts.add(s4);ts.add(s5);for (Student2 stu : ts) {System.out.println(stu);}}
}
运行结果:

集合工具类Collections

常用API:
public static <T> boolean addAll(Collection<T> c, T...elements) 批量添加元素
public static void shuffle(List<?> list)                        打乱List集合元素的顺序
public static <T> void sort(List<T> list, T key)                排序
public static <T> void sort(List<T> list, Comparator<T> c)      根据指定的规则进行排序
public static <T> int binarySearch(List<T> list, T key)         以二分查找法查找元素
public static <T> void copy(List<T> dest, List<T> src)          拷贝集合中的元素
public static <T> int fill(List<T> list, T obj)                 使用指定的元素填充集合
public static <T> void max/min(Collection<T> coll)              根据默认的自然排序获取最                                                                       大/最小值
public static <T> void swap(List<?> list, int i, int j)         交换集合中指定位置的元素
代码演示:
public class CollectionsDemo1 {public static void main(String[] args){/*public static <T> boolean addAll(Collection<T> c, T...elements) 批量添加元素public static void shuffle(List<?> list)                        打乱List集合元素的顺序public static <T> void sort(List<T> list, T key)                排序public static <T> void sort(List<T> list, Comparator<T> c)      根据指定的规则进行排序public static <T> int binarySearch(List<T> list, T key)         以二分查找法查找元素public static <T> void copy(List<T> dest, List<T> src)          拷贝集合中的元素public static <T> int fill(List<T> list, T obj)                 使用指定的元素填充集合public static <T> void max/min(Collection<T> coll)              根据默认的自然排序获取最大/最小值public static <T> void swap(List<?> list, int i, int j)         交换集合中指定位置的元素*///创建集合ArrayList<String> list = new ArrayList<>();//1.public static <T> boolean addAll(Collection<T> c, T...elements) 批量添加元素System.out.println("----------批量添加元素----------");//注意只能添加Collection下的类Collections.addAll(list,"aaa","bbb","ccc","123");System.out.println(list);//2.public static void shuffle(List<?> list)                        打乱List集合元素的顺序System.out.println("----------打乱List集合元素的顺序----------");Collections.shuffle(list);System.out.println(list);//3.public static <T> void sort(List<T> list, T key)                以二分查找法查找元素System.out.println("----------排序----------");Collections.sort(list);System.out.println(list);//4.public static <T> void sort(List<T> list, Comparator<T> c)      根据指定的规则进行排序System.out.println("----------根据指定的规则进行排序----------");Collections.sort(list, new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {//按默认字符串比较规则排序return o1.compareTo(o2);}});System.out.println(list);//5.public static <T> int binarySearch(List<T> list, T key)         以二分查找法查找元素System.out.println("----------以二分查找法查找元素----------");System.out.println(list);int i = Collections.binarySearch(list, "bbb");System.out.println(i);//6.public static <T> void copy(List<T> dest, List<T> src)          拷贝集合中的元素System.out.println("----------拷贝集合中的元素----------");//新建一个集合ArrayList<String> listCopy = new ArrayList<>();//注意被拷贝的集合长度要与拷贝集合长度一致Collections.addAll(listCopy,"","","","");Collections.copy(listCopy,list);System.out.println(listCopy);//7.public static <T> int fill(List<T> list, T obj)                 使用指定的元素填充集合System.out.println("----------使用指定的元素填充集合----------");Collections.fill(list,"666");System.out.println(list);//8.public static <T> void max/min(Collection<T> coll)              根据默认的自然排序获取最大/最小值System.out.println("----------根据默认的自然排序获取最大/最小值----------");String max = Collections.max(listCopy);String min = Collections.min(listCopy);System.out.println(max);System.out.println(min);//9.public static <T> void swap(List<?> list, int i, int j)         交换集合中指定位置的元素System.out.println("----------交换集合中指定位置的元素----------");System.out.println(listCopy);Collections.swap(listCopy,1,2);System.out.println(listCopy);}
}
运行结果:

单列集合使用场景

1.ArrayList

        如果想要集合中的元素可重复,(用的最多)用ArrayLst集合,基于数组的。

2.LinkedList

        如果想要集合中的元素可重复,而且当前的增删操作明显多于查询,用LinkedList,基于链表的

3.HashSet

        如果想对集合中的元素去重,(用的最多)用HashSet,基于哈希表的

4.LinkedHashSet

        如果相对集合中的元素去重,而且保证存取顺序,用LinkedHashSet,基于哈希表和双链表,效率低于HashSet

5.TreeSet

        如果相对集合中的元素进行排序,用TreeSet,基于红黑树。后续也可使用List集合实现排序

双列集合

介绍:

        双列集合每次添加添加两个(或者说一对)元素

        如图:

        左边这列称为键,不可以重复,右边这列称为值,可以重复,键跟值是一一对应的,每一个键只能找到自己的值。

        一对一一对应的键和值统称为一个键值对或者键值对对象,Java中也叫Entry对象。

体系结构

        由于Hashtable和Properties与IO有关,所以先不讲解

MAP

常用API

V put(K key,V value)                    添加/覆盖元素
V remove(Object key)                    根据键删除键值对元素
void clear()                            移除所有的键值对元素
boolean containsKey(Object key)         判断集合是否包含指定的键
boolean containsValue(Object value)     判断集合是否包含指定的值
boolean isEmpty()                       判断集合是否为空
int size()                              集合的长度,即集合中键值对的个数
        代码演示:
public class MapDemo1 {public static void main(String[] args) {/*V put(K key,V value)                    添加/覆盖元素V remove(Object key)                    根据键删除键值对元素void clear()                            移除所有的键值对元素boolean containsKey(Object key)         判断集合是否包含指定的键boolean containsValue(Object value)     判断集合是否包含指定的值boolean isEmpty()                       判断集合是否为空int size()                              集合的长度,即集合中键值对的个数*///创建集合对象//因为Map为接口,所以利用HashMap创建对象Map<String,String> m1 = new HashMap<>();//添加/覆盖元素System.out.println("----------添加/覆盖元素----------");//若要添加的键不存在,则直接添加到集合中并返回null//若要添加的键存在,则将原来的键值对对象覆盖,并返回被覆盖的值String result1 = m1.put("灰太狼", "红太狼");m1.put("美羊羊","沸羊羊");m1.put("懒羊羊","小灰灰");System.out.println(m1);System.out.println(result1);//新添加一个已经存在的键String result2 = m1.put("美羊羊","喜羊羊");System.out.println(result2);System.out.println(m1);//根据键删除键值对元素System.out.println("----------根据键删除键值对元素----------");String result3 = m1.remove("灰太狼");System.out.println(result3);System.out.println(m1);//移除所有的键值对元素System.out.println("----------移除所有的键值对元素----------");m1.clear();System.out.println(m1);//重新添加元素m1.put("灰太狼", "红太狼");m1.put("懒羊羊","小灰灰");m1.put("美羊羊","喜羊羊");//判断集合是否包含指定的键System.out.println("----------判断集合是否包含指定的键----------");boolean result4 = m1.containsKey("懒羊羊");boolean result5 = m1.containsKey("烤全羊");System.out.println(result4);System.out.println(result5);//判断集合是否包含指定的值System.out.println("----------判断集合是否包含指定的值----------");boolean result6 = m1.containsValue("小灰灰");boolean result7 = m1.containsValue("烤全羊");System.out.println(result6);System.out.println(result7);//判断集合是否为空System.out.println("----------判断集合是否为空----------");boolean result8 = m1.isEmpty();System.out.println(result8);//集合的长度,即集合中键值对的个数System.out.println("----------集合的长度,即集合中键值对的个数----------");int size = m1.size();System.out.println(size);}
}
运行结果:

三种遍历方式:

1.通过键找值遍历

        下面我来使用键找值遍历方式,通过迭代器、增强for、Lambda表达式遍历集合。

        代码演示:
public class MapDemo2 {public static void main(String[] args) {//创建集合对象Map<String,String> m = new HashMap<>();//添加对象m.put("喜羊羊","灰太狼");m.put("沸羊羊","美羊羊");m.put("懒羊羊","小灰灰");//通过键找值遍历//将双列集合中的键提另出来放入一个单列集合Set<String> keys = m.keySet();//1.迭代器System.out.println("----------迭代器----------");//创建迭代器对象Iterator<String> it = keys.iterator();//使用迭代器遍历while(it.hasNext()) {String key = it.next();//键找值String value = m.get(key);System.out.println(key + " = " + value);}//2.增强forSystem.out.println("----------增强for----------");for (String key : keys) {String value = m.get(key);System.out.println(key + " = " + value);}//3.Lambda表达式System.out.println("----------Lambda表达式----------");keys.forEach(key -> {String value = m.get(key);System.out.println(key + " = " + value);});}
}
运行结果:

        2.通过键值对遍历

        下面我来使用键值对遍历方式,通过迭代器、增强for、Lambda表达式遍历集合。

        代码演示
public class MapDemo3 {public static void main(String[] args) {//创建集合对象Map<String,String> m = new HashMap<>();//添加元素m.put("喜羊羊","灰太狼");m.put("沸羊羊","美羊羊");m.put("懒羊羊","小灰灰");//通过键值对遍历//将键值对对象放到一个单列集合中Set<Map.Entry<String, String>> entries = m.entrySet();//1.迭代器System.out.println("----------增强for----------");Iterator<Map.Entry<String, String>> it = entries.iterator();while(it.hasNext()) {Map.Entry<String, String> entry = it.next();String key = entry.getKey();String value = entry.getValue();System.out.println(key + " = " + value);}//2.增强forSystem.out.println("----------增强for----------");for (Map.Entry<String, String> entry : entries) {String key = entry.getKey();String value = entry.getValue();System.out.println(key + " = " + value);}//3.Lambda表达式System.out.println("----------Lambda表达式----------");entries.forEach(entry -> {String key = entry.getKey();String value = entry.getValue();System.out.println(key + " = " + value);});}
}
运行结果:

        3.Lambda表达式

   default void forEach(BiConsumer<? super K, ? super V> action)        结合Lambda遍历Map集合

        代码演示:
public class MapDemo4 {public static void main(String[] args) {//创建集合对象Map<String,String> m = new HashMap<>();//添加元素m.put("喜羊羊","灰太狼");m.put("沸羊羊","美羊羊");m.put("懒羊羊","小灰灰");//使用Lambda表达式遍历//1.匿名内部类m.forEach(new BiConsumer<String, String>() {@Overridepublic void accept(String key, String value) {System.out.println(key + " = " + value);}});System.out.println("---------------------");//2.转换成Lambda表达式m.forEach((key, value) -> System.out.println(key + " = " + value));}
}
        运行结果:

1.HashMap

        特点:

                1.HashMap是Map里面的一个实现类

                2.没有额外需要学习的特有方法,直接使用Map里面的方法就可以了

                3.特点都是由键决定的:无序、不重复、无索引(都是指键)

                4.HashMap跟HashSet底层原理是一模一样的,都是哈希表结构(JDK8之前:数组+链                     表,JDK8之后:数组+链表+红黑树)计算哈希值时也是通过键计算

                5.存入元素时,以来hashCode方法和equals方法保证键的唯一

                6.如果键存储的是自定义对象,需要重写hashCode和equals方法,如果值存储自定义对                     象,不需要重写hashCode和equals方法

小练习1

需求:创建一个HashMap集合,
键是学生对象(Student),值是籍贯(String)
存储三个键值对元素,并遍历
要求:同姓名、同年龄认为是同一个学生

核心点:HashMap的键位置如果存储的是自定义对象,需要重写hashCode和equals方法。

代码演示:
public class HashMapTest1 {public static void main(String[] args) {/*需求:创建一个HashMap集合,键是学生对象(Student),值是籍贯(String)存储三个键值对元素,并遍历要求:同姓名、同年龄认为是同一个学生*///创建学生对象Student s1 = new Student("han",21);Student s2 = new Student("ma",22);Student s3 = new Student("zhao",21);Student s4 = new Student("zhao",21);//创建HashMap集合HashMap<Student,String> hm = new HashMap<>();//存储键值对元素hm.put(s1,"石家庄");hm.put(s2,"邯郸");hm.put(s3,"保定");hm.put(s4,"天津");//遍历//1.键找值遍历System.out.println("----------键找值遍历----------");Set<Student> keys = hm.keySet();for (Student key : keys) {String value = hm.get(key);System.out.println(key + " = " + value);}//2.键值对遍历System.out.println("----------键值对遍历----------");Set<Map.Entry<Student, String>> entries = hm.entrySet();for (Map.Entry<Student, String> entry : entries) {Student key = entry.getKey();String value = entry.getValue();System.out.println(key + " = " + value);}//3.Lambda表达式遍历System.out.println("----------Lambda表达式遍历----------");hm.forEach((student,  s) ->System.out.println(student + " = " + s));}
}
运行结果:

小练习2

        需求:某个班级30名学生,现在需要组成秋游活动,班长提供了四个景点依次是A、B、C、D,每个学生只能选择一个景点,请统计出最终哪个景点想去的人数最多

代码演示
public class HashMapTest2 {public static void main(String[] args) {/*需求:某个班级30名学生,现在需要组成秋游活动,班长提供了四个景点依次是A、B、C、D,每个学生只能选择一个景点,请统计出最终哪个景点想去的人数最多*///创建集合HashMap<String,Integer> hm = new HashMap<>();//生成三十个随机的景点表示学生选择的景点,并存入集合ArrayList<String> list = new ArrayList<>();String[] arr = {"A","B","C","D"};Random r = new Random();for (int i = 0; i < 30; i++) {int index = r.nextInt(4);String name = arr[index];list.add(name);}//要统计的东西较多,使用Map集合进行统计for (int i = 0; i < list.size(); i++) {//判断当前的元素在HashMap中是否存在if(hm.containsKey(list.get(i))) {//如果存在,这个key的value加1int newValue = hm.get(list.get(i)) + 1;hm.put(list.get(i),newValue);} else {//如果不存在,那么添加进去value置为1hm.put(list.get(i),1);}}//遍历System.out.println(hm);//找到选择次数的最大值int max = 0;Set<Map.Entry<String, Integer>> entries = hm.entrySet();for (Map.Entry<String, Integer> entry : entries) {int times = entry.getValue();if(max < times) {max = times;}}//输出次数等于最大次数的景点System.out.print("想去的人最多的景点为:");for (Map.Entry<String, Integer> entry : entries) {int times = entry.getValue();if(max == times) {System.out.print(entry.getKey() + " ");}}}}
运行结果:

2.LinkedHashMap

        特点:

                由键决定:有序、无重复、无索引

                这里的有序指的是保证存储和取出的元素顺序一致

        原理:

                底层数据结构依然是哈希表,只是每个键值对元素又额外多了一个双链表的机制记录存储的顺序(详细了解可通过前文LinkedHashSet内容)

3.TreeMap

        特点:

                由键决定:不重复、无索引、可排序

                这里的可排序是指对键进行排序(默认按照键的大小从小到大进行排序,也可以自己规定键的排序规则)

        原理:

                与TreeSet一样,底层数据结构都为红黑树,增删改查性能都较好

        代码书写两种排序规则(同TreeSet):

                1.实现Comparable接口,指定比较规则。

                2.创建集合时传递Comparator比较器对象,指定比较规则。

        小练习1:        

                需求:

                键:整数表示id

                值:字符串表示商品名称

                要求1:按照id的升序排列(默认情况下TreeMap对Integer类型的键值就从小到大排序)

                要求2:按照id的降序排列

        代码演示:
public class TreeMapDemo1 {public static void main(String[] args) {/*需求:键:整数表示id值:字符串表示商品名称要求1:按照id的升序排列要求2:按照id的降序排列*///要求1:升序//需要排序,创建TreeMap对象TreeMap<Integer,String> tm1 = new TreeMap<>((o1, o2) -> o1 - o2);//添加元素tm1.put(2,"phone");tm1.put(3,"computer");tm1.put(1,"pen");//输出结果System.out.println(tm1);//要求2:降序//创建TreeMap对象TreeMap<Integer,String> tm2 = new TreeMap<>((o1, o2) -> o2 - o1);//添加元素tm2.put(1,"pen");tm2.put(3,"computer");tm2.put(2,"phone");//输出结果System.out.println(tm2);}
}
        运行结果:

        小练习2:

                需求2:

                键:学生对象

                值:籍贯

                要求:按照学生年龄的升序排列,

                           年龄一样按照姓名的字母排列,

                           同姓名年龄视为同一个人

        代码演示:
                Student类:
public class Student implements Comparable<Student>{private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}/*** 获取* @return name*/public String getName() {return name;}/*** 设置* @param name*/public void setName(String name) {this.name = name;}/*** 获取* @return age*/public int getAge() {return age;}/*** 设置* @param age*/public void setAge(int age) {this.age = age;}public String toString() {return "Student{name = " + name + ", age = " + age + "}";}@Overridepublic int compareTo(Student o) {int i = this.getAge() - o.getAge();i = i == 0 ? this.getName().compareTo(o.getName()) : i;return i;}
}
                测试类TreeMapDemo2:
public class TreeMapDemo2 {public static void main(String[] args) {/*需求2:键:学生对象值:籍贯要求:按照学生年龄的升序排列,年龄一样按照姓名的字母排列,同姓名年龄视为同一个人*///创建学生对象Student s1 = new Student("zhao",21);Student s2 = new Student("han",21);Student s3 = new Student("ma",22);Student s4 = new Student("zhao",21);//创建TreeMap对象TreeMap<Student,String> tm = new TreeMap<>();//添加学习对象tm.put(s1,"bd");tm.put(s2,"sjz");tm.put(s3,"hd");tm.put(s4,"tj");//输出结果System.out.println(tm);}
}
        运行结果:

        小练习3:

                需求: 字符串“aababcabcdabcde”

                统计字符串中每一个字符出现的次数,

                并按照以下格式输出

                输出结果:a(5)b(4)c(3)d(2)e(1)

        代码演示:
public class TreeMapDemo3 {public static void main(String[] args) {/*需求:字符串“aababcabcdabcde”统计字符串中每一个字符出现的次数,并按照以下格式输出输出结果:a(5)b(4)c(3)d(2)e(1)*/String str = "aababcabcdabcde";//需要同时存储字符和其出现的次数,采用双列集合//需要按照次数从大到小排序,采用TreeMap//创建TreeMapTreeMap<Character,Integer> tm = new TreeMap<>();//添加元素for (int i = 0; i < str.length(); i++) {if(tm.containsKey(str.charAt(i))) {//若已存在 值+1tm.put(str.charAt(i),tm.get(str.charAt(i)) + 1);} else {//若不存在,put 值为1tm.put(str.charAt(i),1);}}//遍历StringBuilder sb = new StringBuilder();tm.forEach((key,  value) -> sb.append(key).append("(").append(value).append(")"));System.out.println(sb);}
}
        运行结果:

双列集合思考:

可变参数

        可变参数本质上是一个数组

作用:

        在形参中接收多个数据

格式:

        数据类型...参数名称(例如:int...args)

代码演示:

public class Args {public static void main(String[] args) {int sum1 = getSum();int sum2 = getSum(1,2,3,4);int sum3 = getSum(1,2,3,4,5);System.out.println(sum1);System.out.println(sum2);System.out.println(sum3);}public static int getSum(int...args) {int sum = 0;for (int i = 0; i < args.length; i++) {sum = sum + args[i];}return sum;}
}

运行结果:

注意:

        1.在方法的形参中最多只能写一个可变参数

        2.在方法中,如果除了可变参数以外,还有其他参数,那么可变参数要写最后

综合练习:

练习一:

        自动点名器1:

        班级里有N个学生,学生属性:姓名,年龄,性别。

        实现随机点名器

代码演示:
public class Test1 {public static void main(String[] args) {/*班级里有N个学生,学生属性:姓名,年龄,性别。实现随机点名器*///第一种方法System.out.println("第一种方法:");ArrayList<Student> list = new ArrayList<>();Collections.addAll(list,new Student("han",21,"m"),new Student("ma",22,"m"),new Student("zhao",21,"m"),new Student("wang",22,"m"),new Student("hu",22,"m"),new Student("wu",21,"f"));Random r = new Random();int index = r.nextInt(list.size());System.out.println(list.get(index).getName());//第二种方法System.out.println("第二种方法:");Collections.shuffle(list);System.out.println(list.get(0).getName());}
}
运行结果:

练习二:

        自动点名器2:

        班级里有N个学生,学生属性:姓名,年龄,性别。

        实现随机点名器

        要求:百分之70概率随机到男生,百分之30概率随机到女生

代码演示:
public class Test2 {public static void main(String[] args) {/*自动点名器2:班级里有N个学生,学生属性:姓名,年龄,性别。实现随机点名器要求:百分之70概率随机到男生,百分之30概率随机到女生*///存储学生信息ArrayList<Student> list = new ArrayList<>();Collections.addAll(list,new Student("han",21,"m"),new Student("ma",22,"m"),new Student("zhao",21,"m"),new Student("wang",22,"m"),new Student("hu",22,"m"),new Student("wu",21,"f"), new Student("xiaomei",21,"f"),new Student("xiaofang",22,"f"));//创建集合来控制概率ArrayList<Integer> probabilityList = new ArrayList<>();Collections.addAll(probabilityList,1,1,1,1,1,1,1);Collections.addAll(probabilityList,0,0,0);Collections.shuffle(probabilityList);int number = probabilityList.get(0);if(number == 1) {System.out.print("男生:");} else {System.out.print("女生:");}//创建集合分别存储男生和女生ArrayList<Student> boyList = new ArrayList<>();ArrayList<Student> girlList = new ArrayList<>();if(number == 1) {//如果要选男生//将所有男生存入一个集合中for (Student student : list) {if(student.getGender() == "m") {boyList.add(student);}}//并随机抽取Collections.shuffle(boyList);System.out.println(boyList.get(0).getName());} else {//如果要选女生//将所有女生存入一个集合中for (Student student : list) {if(student.getGender() == "f") {girlList.add(student);}}//并随机抽取Collections.shuffle(girlList);System.out.println(girlList.get(0).getName());}}
}
运行结果:

练习三:

        自动点名器3:

        班级里有N个学生,学生属性:姓名,年龄,性别。

        实现随机点名器

        要求:被点到的学生不会再被点到

        如果班级中所有的学生都点完了,需要重新开启第二轮点名

代码演示:
public class Test3 {public static void main(String[] args) {/*自动点名器3:班级里有N个学生,学生属性:姓名,年龄,性别。实现随机点名器要求:被点到的学生不会再被点到如果班级中所有的学生都点完了,需要重新开启第二轮点名*///存储学生信息ArrayList<Student> list = new ArrayList<>();Collections.addAll(list,new Student("han",21,"m"),new Student("ma",22,"m"),new Student("zhao",21,"m"),new Student("wang",22,"m"),new Student("hu",22,"m"),new Student("wu",21,"f"), new Student("xiaomei",21,"f"),new Student("xiaofang",22,"f"));//创建新集合存储数据ArrayList<Student> copyList = new ArrayList<>();copyList.addAll(list);Scanner sc = new Scanner(System.in);while (true) {//点名控制界面System.out.println("点名请输入:1,退出请输入:2");int num = sc.nextInt();//判断if(num == 1) {if(copyList.size() != 0){//新集合长度不为0时} else {//新数组长度为0copyList.addAll(list);}//打乱集合Collections.shuffle(copyList);//获取随机姓名System.out.println(copyList.get(0).getName());//删除被点到的学生对象copyList.remove(0);}else {//退出break;}}}
}
运行结果:

不可变集合

        不可改变的集合

      特点:

                不可添加、不可删除、不可修改、只能查询

      代码演示:

                (利用List、Set、Map接口创建不可变集合,并展示查询及遍历方法)

        List:(Set与List方法一致)

public class ImmutableDemo1 {public static void main(String[] args) {//创建集合List<String> list = List.of("han", "ma", "zhao", "hu", "wang", "wu");//遍历集合//逐个遍历System.out.println(list.get(0));System.out.println(list.get(1));System.out.println(list.get(2));System.out.println(list.get(3));System.out.println(list.get(4));System.out.println(list.get(5));//普通for遍历System.out.println("----------------------");for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i));}//迭代器System.out.println("----------------------");Iterator<String> it = list.listIterator();while(it.hasNext()) {String str = it.next();System.out.println(str);}//增强forSystem.out.println("----------------------");for (String str : list) {System.out.println(str);}//lambda表达式System.out.println("----------------------");list.forEach(str -> System.out.println(str));}
}
        运行结果:

                 

        Map:

public class ImmutableDemo2 {public static void main(String[] args) {//Map系列不可变集合//JDK10以上//先创建一个可变集合HashMap<String,String> hm = new HashMap<>();hm.put("111","aaa");hm.put("222","bbb");hm.put("333","ccc");hm.put("444","ddd");hm.put("555","eee");//转为不可变集合Map<String, String> map1 = Map.copyOf(hm);System.out.println(map1);//JDK10以下Map<Object, Object> map2 = Map.ofEntries(hm.entrySet().toArray(new Map.Entry[0]));System.out.println(map2);}
}
        运行结果:

注意:

        创建Set和Map的不可变集合时,要注意不能包含重复元素,并且按照各自集合的要求存储元素。

        Map不可变集合中最多只能存储20个元素,即10个键值对,超过十个用ofEntries方法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/8386.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

地平线的花样年华

北京车展在这个喧闹的“五一”假期落幕了&#xff0c;它留给我们许多思考。 虽然社会面的传播焦点落在了“网红”两个字上&#xff0c;但技术的更新依然如暗流涌动&#xff0c;给这届北京车展写下注脚。整个过程前后&#xff0c;最重要和吸引了最多目光的&#xff0c;是智驾&a…

什么是驱动数字签名?如何获取驱动数字签名?

Windows 驱动程序承载着计算机实现的各种内核和用户模式功能。如果驱动程序被黑客攻击&#xff0c;可能会产生很多问题。Windows通过数字签名来验证驱动程序包的完整性及发布者的身份。2020年10月的安全更新中&#xff0c;微软加强了对驱动软件的验证&#xff0c;如果Windows无…

【数据可视化-01】Matplotlib图形实战宝典

在数据分析领域&#xff0c;图形化展示数据是非常重要的环节。Python中的matplotlib库是绘制各类图形的强大工具。本文将介绍如何使用matplotlib绘制折线图、直方图、饼图、散点图和柱状图等数据分析中常见的图形&#xff0c;并附上相应的代码示例&#xff0c;可以当初matplotl…

栈和队列的4道面试题【详细解析】【代码实现】

栈和队列的面试题 1.有效的括号&#xff08;栈实现&#xff09; 题目&#xff1a; 有效的括号 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必…

系统稳定性判定分析(二)----频域分析法相关辐角原理

文章目录 辐角原理&#xff08;即Cauchy原理&#xff09;引理分析辐角原理定义与证明补充知识 参考文献 为后续更好从频域层面分析控制系统的稳定性&#xff0c;本节首先介绍在后续分析中用到的辐角原理。 根据复变函数对数的定义&#xff0c;有 l n f ( z ) l n ∣ f ( z ) ∣…

rabbitmq集群搭建失败解决

1. 现象 1. 三台机器都已经修改hosts&#xff0c;各个节点ping节点名正常 2. erlang.cookie各节点值一样 执行下面步骤加入失败 rabbitmqctl stop_app # 停止rabbitmq服务 rabbitmqctl reset # 清空节点状态 rabbitmqctl join_cluster rabbitrabbitmq3 rabbitmqctl start_ap…

智能化采购管理系统助力光伏行业提高效率

光伏行业是指太阳能电池板的制造、安装和维护等相关产业&#xff0c;是新能源领域的重要组成部分。近年来&#xff0c;随着全球对于环保和可持续发展的重视&#xff0c;光伏行业进入全球化和智能化的新阶段。光伏企业开始加强国际合作&#xff0c;推广智能化技术&#xff0c;提…

【负载均衡在线OJ项目日记】编译与日志功能开发

目录 日志功能开发 常见的日志等级 日志功能代码 编译功能开发 创建子进程和程序替换 重定向 编译功能代码 日志功能开发 日志在软件开发和运维中起着至关重要的作用&#xff0c;目前我们不谈运维只谈软件开发&#xff1b;日志最大的作用就是用于故障排查和调试&#x…

【MM32F3270火龙果】keil安装MM32F3270

文章目录 前言一、下载pack包二、安装pack三、keil选择MM32F3270 cpu四、编译烧写总结 前言 在嵌入式系统开发中&#xff0c;选择适合的开发工具和微控制器平台至关重要。本文将介绍如何在Keil开发环境中安装和配置MM32F3270火龙果微控制器的开发环境。MM32F3270火龙果是一款功…

单链表式并查集

如果用暴力算法的话&#xff0c;那么会直接超时&#xff0c;我们要学会用并查集去记录下一个空闲的位置 #include<bits/stdc.h> using namespace std;const int N 100005;int n; int fa[N]; int a[N];int find(int x) {if (fa[x] x) {return x;}fa[x] find(fa[x]);re…

Etcd集群选举细节

日志级别 在 etcd 集群中&#xff0c;领导者选举是 Raft 协议的一部分&#xff0c;用于在当前领导者失败或无法与集群中的其他节点通信时选出新的领导者。以下是您提供的日志中与领导者选举相关的一些关键条目&#xff0c;以及对它们的详细说明&#xff1a; 节点失去领导者&am…

支付时,中国网联结算与中国银联结算的区别与联系

随着电子商务和互联网支付的快速发展&#xff0c;中国的支付清算市场也呈现出前所未有的繁荣景象。在这个大背景下&#xff0c;中国网联与中国银联作为两大支付清算机构&#xff0c;各自扮演着重要的角色。本文将对两者的区别和联系进行深入探讨&#xff0c;以期对读者有更全面…

网盘应用:桌面端界面欣赏,这个赛道容不下小玩家。

网盘&#xff08;Cloud Storage&#xff09;是一种云存储服务&#xff0c;允许用户在互联网上存储、管理和共享文件。它提供了一个在线的虚拟硬盘&#xff0c;用户可以通过网络将文件上传到云端&#xff0c;并随时随地访问和管理这些文件。 阿里云盘

办公类的Erp全流程管理系统有哪些靠谱的?

不知不觉&#xff0c;跟公司老板创业开始已经5年有余&#xff0c;感觉部门墙越来越厚。 财务跟业务经常开始漫长的对账过程&#xff0c;时不时HR也会牵涉进来&#xff0c;对销售团队进行考核结果确认&#xff0c;每个业务的催账任务也得最终落到实处。 老板早就对这样的状况深…

二、双fifo流水线操作——verilog练习与设计

文章目录 一、案例分析二、fifo_ctrl模块设计2.1 波形设计&#xff1a;2.2 代码实现2.2.1 fifo_ctrl2.2.2 顶层文件top_fifo_ctrl&#xff08;rx和tx模块省略&#xff09;2.2.3 仿真文件tb_fifo_ctrl 2.3波形仿真 一、案例分析 案例要求&#xff1a;写一个 fifo 控制器&#x…

我独自升级崛起加速器推荐 我独自升级免费加速器

近期&#xff0c;《我独自升级》这部动画凭借爆棚的人气&#xff0c;在各大平台上掀起了一阵观看热潮&#xff0c;其影响力不容小觑。借此时机&#xff0c;韩国游戏巨头网石集团敏捷响应&#xff0c;顺势推出了同名游戏《我独自升级&#xff1a;ARISE》&#xff0c;为粉丝们搭建…

【北京迅为】《iTOP-3588开发板快速烧写手册》-第9章ubuntu系统下升级固件

RK3588是一款低功耗、高性能的处理器&#xff0c;适用于基于arm的PC和Edge计算设备、个人移动互联网设备等数字多媒体应用&#xff0c;RK3588支持8K视频编解码&#xff0c;内置GPU可以完全兼容OpenGLES 1.1、2.0和3.2。RK3588引入了新一代完全基于硬件的最大4800万像素ISP&…

如何将pdf文件换成3d模型?---模大狮模型网

PDF文件是一种广泛用于文档传输和共享的格式&#xff0c;但在某些情况下&#xff0c;我们可能希望将其中的内容转换为更具交互性和视觉效果的3D模型。本文将介绍如何将PDF文件转换为3D模型&#xff0c;为您展示实现这一想象的步骤。 选择合适的PDF文件&#xff1a; 首先&#…

​「Python绘图」绘制五角星

python 绘制五角星 一、预期结果 二、核心代码 import turtle print("开始绘制五角星")# 设置画布尺寸 # screen turtle.Screen() # screen.setup(width500, height500)# 创建Turtle对象 pen turtle.Turtle() pen.shape("turtle")# 移动画笔到起始位置 …

为什么说RK3562可以碾压PX30?

在如今的科技市场中&#xff0c;处理器的性能直接决定了设备的运行速度和用户体验。今天&#xff0c;我们将对比瑞芯微旗下的两款处理器&#xff1a;PX30与RK3562。RK3562比PX30的性价比究竟高在哪里&#xff1f; PX30 瑞芯微PX30是一款高性能的四核应用处理器&#xff0c;专…