跟我一起学JAVAEE吧——JAVA_SE篇——day12上课笔记(简单的数据结构,List和Set集合分不清?可变参数还不会用?comparable和comparator的区别)

day 12

数据结构

  • 栈:

    • stack,又称为堆栈,它是运算受限的线性表,其限制是仅允许在标的一端进行插入和删除操作,不允许在其他任何位置进行添加,查找,删除等操作
    • 先进后出,如子弹压进弹夹,先压进的子弹在下面,后面压进去的子弹在上面,开枪时,先用上面的子弹,最后用下面的子弹
    • 压栈:就是存入元素
    • 弹栈:就是取出元素
  • 队列

    • queue:简称队,和堆栈一样,也是一种运算受限的线性表,其限制是仅允许在表的一端进行插入,而在表的另一端进行删除。
    • 先进新出:如隧道,先进去隧道的车先出来,后进去的车后出来
  • 数组

    • Array:是有序的元素序列,数组是在内存中开辟一段连续的空间,并在此空间存放元素。就像是一排出租屋,有100个房间,从001到100每个房间都有固定编号,通过编号就可以快速找到租房子的人
    • 优点 : 查询快
      • 数组的地址是连续的,我们通过数组的首地址可以找到数组,通过数组的索引可以快速查找到某一个元素
    • 缺点 : 增删慢
      • 数组的长度是固定的,我们想要增加或者删除一个元素必须创建一个新的数组,把源数组的内容复制过来
  • 链表

    • Link list 链表中每一个元素叫做一个节点,一个节点包括一个数据源,两个指针域(存储地址)
    • 分类
      • 单向链表:链表中只要一条链子,不能保证元素的顺序(存取和取出元素的顺序可能不同)
      • 双向链表:链表中只有两条链子,其中一条链子是专门记录元素顺序的,是个有序的结构
    • 优点:
      • 增删快:链表结构,增加或者删除元素,对链表的整体结构没有任何影响,所以增删快
    • 缺点:
      • 查询慢:链表中的地址不是连续的,每次查询的时候都需要从头开始
    • 二叉树:分支不能超过两个
      • 一种类似于我们生活中树的结构,只不过每个结点上最多只能有两个子结点
      • 二叉树是每个节点最多有两个子树的树结构。顶上的叫根节点,两边被称作左子树和右子树
    • 排序树/查找树:在二叉树的基础上,元素大小有顺序,左子树小,右子树大
    • 平衡树:左孩子和右孩子的树数目相等
    • 不平衡树:左孩子和右孩子的树数目不相等
    • 红黑树
      • 特点:趋近于平衡树,查询速度非常快
      • 约束
        • 节点可以是红色或者黑色的
        • 根节点是黑色的
        • 叶子节点(空节点)是黑色的
        • 每个红色节点的子节点必须都是黑色的
        • 任何一个节点到其每个叶子节点的所有路径上的黑色节点数相同

List集合

  • List接口

    • 它是一个元素存取有序的集合,例如,存元素的顺序是11,22,33,那么集合中,元素的存储就是按照11,22,33的顺序完成的。

    • 它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素(与数组的索引是一个道理)

    • 集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素。

    • 常用方法:

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

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

      • remove(int index):移除列表中指定位置元素

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

        public class ListDemo {
        	public static void main(String[] args) {
        		// 创建List集合对象
        		List<String> list = new ArrayList<String>();
        		// 往尾部添加指定元素
        		list.add("图图");
        		list.add("小美");
        		list.add("不高兴");
        		System.out.println(list);
        		//add(int index,String s)往指定位置添加
        		list.add(1,"没头脑");
        		System.out.println(list);
        		// String remove(int index) 删除指定位置元素 返回被删除元素
        		// 删除索引位置为2的元素
        		System.out.println("删除索引位置为2的元素");
        		System.out.println(list.remove(2)); 
           		System.out.println(list);
        		// String set(int index,String s)
        		// 在指定位置 进行 元素替代(改)
        		// 修改指定位置元素
        		list.set(0, "三毛");
        		System.out.println(list);
        		// String get(int index) 获取指定位置元素
        		// 跟size() 方法一起用 来 遍历的
        		for(int i = 0;i<list.size();i++){ 
            	    System.out.println(list.get(i));
        		}
        		//还可以使用增强for
        		for(String string :list){
              	  System.out.println(String);
         	   }
            }
        }
        

List的子类

  • Arraylist集合

    • Arraylist集合数据存储的结构是数组结构,元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据,遍历数据,所以Arraylist是最常用的集合
    • 注意:许多程序员开发时非常随意地使用ArrayList完成任何需求,并不严谨,这种用法是不提倡的。
  • LinkedList集合

    • linkedlist集合数据存储的结构是链表结构,方便元素添加,删除的集合。

      • Linked List是一个双向链表
    • 常用方法

      • addFirst(E e):将指定元素插入此列表的开头
      • addLast(E e):将指定元素添加到此列表的结尾
      • getFirst():返回此列表的第一个元素
      • getLast():返回此列表的最后一个元素
      • removeFirst():移除并返回此列表的第一个元素
      • removeLast():移除并返回此列表的最后一个元素
      • pop():从此列表所表示的堆栈处弹出一个元素,相当于removefirst()
      • push(E e):将元素推入此列表所表示的堆栈相当于add()和addlast()
      • isEmpty():如果列表不包含元素,则返回True
    • 在开发的时候,LinkedList集合也可以作为堆栈,队列的结构使用

      public class LinkedListDemo {
      	public static void main(String[] args) { 
              LinkedList<String> link = new LinkedList<String>();
      		//添加元素
      		link.addFirst("abc1"); 
              link.addFirst("abc2"); 
              link.addFirst("abc3"); 
              System.out.println(link);
      		// 获取元素
      		System.out.println(link.getFirst()); 
              System.out.println(link.getLast());
      		// 删除元素
      		System.out.println(link.removeFirst()); 
              System.out.println(link.removeLast());
      		while (!link.isEmpty()) { //判断集合是否为空
                  System.out.println(link.pop()); //弹出集合中的栈顶元素
      		}
      		System.out.println(link);
      	}
      }
      
      

Set接口

  • 和List接口一样,同样继承自Collection接口,它与Collection接口中的方法基本一致,并没有队Colloction接口进行功能上的扩充,只是比Collection接口更加严格了

  • 与List接口不同的是,Set接口中元素无序,并且都会以某种规则保证存入的元素不出现重复

  • HashSet集合

    • 是Set接口的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的

    • HashSet是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能,保证元素唯一性的方式依赖于:HashCode于equals方法

      public class HashSetDemo{
          public static void main(String[] args){
              //创建Set集合
              HashSet<String> set =new HashSet<String>();
              //添加元素
              set.add(new String("cba"));
              set.add("abc");
              set.add("bac");
              set.add("cba");
              //遍历
              for(String name : set){
                  System.out.println(name);
              }
          }
      }
      
      //说明集合中不能存储重复元素
      cba
      abc
      bac
      
    • Hash表

      • JDK1.8之前,哈希表底层采用数组+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而JDK1.8中,哈希表存储采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间

      • 哈希表是由数组+链表+红黑树实现的

      在这里插入图片描述

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

      package cn.javase.day12;
      import java.security.PrivateKey;
      import java.util.Objects;
      public class Student {
          private String name;
          private int age;
          @Override
          public boolean equals(Object o) {//重写equals方法
              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);
          }
          @Override
          public int hashCode() {//重写hashcode方法
              return Objects.hash(name, age);
          }
          public Student(String name,  int age) {
              this.name = name;
              this.age = age;
          }
          public Student() {
          }
          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 class HashSetDemo2 {
      	public static void main(String[] args) {
      		//创建集合对象	该集合中存储 Student类型对象				
              HashSet<Student> stuSet = new HashSet<Student>();
      		//存储
      		Student stu = new Student("于谦", 43);
      		stuSet.add(stu);
      		stuSet.add(new Student("郭德纲", 44));
      		stuSet.add(new Student("于谦", 43));
      		stuSet.add(new Student("郭麒麟", 23));
      		stuSet.add(stu);
      		for (Student stu2 : stuSet) {
      		  System.out.println(stu2);
      		}
      	}
      }
      

      执行结果:
      Student [name=郭德纲, age=44] Student [name=于谦, age=43] Student [name=郭麒麟, age=23]

  • LinkedHashSet

    • 元素存放保证唯一,有序

    • HashSet=Array+Linked+红黑树,LinkedHashSet=(Araay+Linked+红黑树)+链表(Linked)

      public class LinkedHashSetDemo {
      	public static void main(String[] args) { 		
              Set<String> set = new LinkedHashSet<String>(); 
              set.add("bbb");
              set.add("aaa");
              set.add("abc");
              set.add("bbc");
      		Iterator<String> it = set.iterator(); 
              while (it.hasNext()) {
                  System.out.println(it.next());
              }
          }
      }
      
      

      结果:bbb

      ​ aaa

      ​ abc

      ​ bbc

可变参数

  • JDK1.5之后,如果我们定义一个方法需要接受多个参数,并且多个参数类型一致

  • 格式

    • 修饰符 返回值类型 方法名 (参数类型…形参名){}
    • 等价于:修饰符 返回值类型 方法名(参数类型[] 形参名){}只是后面这种定义,在调用时必须传递数组,而前者可以直接传递数据即可。
  • 举例

    public class ChangeArgs {
    	public static void main(String[] args) { 
            int[] arr = { 1, 4, 62, 431, 2 };
    		int sum = getSum(arr); 
            System.out.println(sum);
    		// 6 7 2 12 2121
    		// 求 这几个元素和 6 7 2 12 2121
    		int sum2 = getSum(6, 7, 2, 12, 2121); 
            System.out.println(sum2);
    	}
    	 //完成数组 所有元素的求和 原始写法
    	public static int getSum(int[] arr){ 
    		int sum = 0;
    		for(int a : arr){ 
    			sum += a;
    		}
    		return sum;
    	}
    	//可变参数写法
    	public static int getSum(int... arr) { 
            int sum = 0;
    		for (int a : arr) { 
                sum += a;
    		}
    		return sum;
    	}
    }
    
    

Collections常用功能

  • Collections是个集合工具类

    • addAll(Collectionc,T…elements):往集合中添加一些元素

    • shuffle(List<?>list):打乱集合顺序

    • sort(List list):将集合中元素按照默认规则排序

    • sort(Listlist,Comparator<? super T>):将集合中元素按照指定规则排序

      public class CollectionsDemo {
      	public static void main(String[] args) { 
         	 	ArrayList<Integer> list = new ArrayList<Integer>();
      		//原来写法
      		//list.add(12);
      		//list.add(14);
      		//list.add(15);
      		//list.add(1000);
      		//采用工具类 完成 往集合中添加元素
              Collections.addAll(list, 5, 222, 12); 
              System.out.println(list);
      		//排序方法
              Collections.sort(list); 
              System.out.println(list);
      	}
      }
      结果:
      [5, 222, 1, 2]
      [1, 2, 5, 222]
      
      

Comparator比较器

  • sort(Listlist,Comparator<? super T>):将集合中元素按照指定规则排序

    public class CollectionsDemo2 {
    	public static void main(String[] args) { 		
            ArrayList<String> list = new ArrayList<String>(); 
            list.add("cba");
    		list.add("aba");
    		list.add("sba");
    		list.add("nba");
    		//排序方法
            Collections.sort(list); 
            System.out.println(list);
    	}
    }
    结果:
      [aba, cba, nba, sba]  
    
  • 我们使用的是默认的规则完成字符串的排序,那么默认规则是怎么定义出来的呢?

  • 说到排序了,简单的说就是两个对象之间比较大小,那么在JAVA中提供了两种比较实现的方式

    • 一种是比较死板的采用 java.lang.Comparable 接口去实现,

    • 一种是灵活的当我需要做排序的时候在去选择的java.util.Comparator 接口完成。

    • 上面的sort()方法实际上要求了被排序的类型需要实现Comparable接口完成比较的功能

      public final class String implements java.io.Serializable, Comparable<String>, CharSequence {}
      
    • String类实现了这个接口,并完成了比较规则的定义,但是这样就把这种规则写死了,那比如我想要字符串按照第一个字符降序排列,那么这样就要修改String的源代码,这是不可能的了,那么这个时候我们可以使用匿名内部类使用Comparator的方法灵活完成

      public class CollectionsDemo3 {
      	public static void main(String[] args) { 
              ArrayList<String> list = new ArrayList<String>(); 
              list.add("cba");
      		list.add("aba");
      		list.add("sba");
      		list.add("nba");
      		//排序方法 按照第一个单词的降序
      		Collections.sort(list, new Comparator<String>() {
      		@Override
      		public int compare(String o1, String o2) { 
                  return o2.charAt(0) ‐ o1.charAt(0);
      
              }
              });
      		System.out.println(list);
          }
      }
      
      

      两个对象比较的结果有三种:大于,等于,小于

      如果要按照升序排序, 则o1 小于o2,返回(负数),相等返回0,01大于02返回(正数) 如果要按照

      降序排序 则o1 小于o2,返回(正数),相等返回0,01大于02返回(负数)

    • 继承Comparable接口重写compareTo(Object o1,Object o2)方法比较两个参数的顺序

      package cn.javase.day12;
      import java.security.PrivateKey;
      import java.util.Objects;
      public class Student implements Comparable<Student> {//实现Comparable接口
          private String name;
          private String sex;
          private int 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) &&
                      Objects.equals(sex, student.sex);
          }
          @Override
          public int hashCode() {
              return Objects.hash(name, sex, age);
          }
          public Student(String name, String sex, int age) {
              this.name = name;
              this.sex = sex;
              this.age = age;
          }
          public Student() {
          }
          public String getName() {
              return name;
          }
          public void setName(String name) {
              this.name = name;
          }
          public String getSex() {
              return sex;
          }
          public void setSex(String sex) {
              this.sex = sex;
          }
          public int getAge() {
              return age;
          }
          public void setAge(int age) {
              this.age = age;
          }
          //重写compareTo方法,完成相应的要求排序
          @Override
          public int compareTo(Student o) {
              return this.getAge()-o.getAge();
          }
      }
      
      
  • Comparable和Comparator两个接口的区别

    • Comparable:强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的compareTo方法被称为它的自然比较方法。只能在类中实现compareTo()一次,不能经常修改类的代码实现自己想要的排序。实现此接口的对象列表(和数组)可以通过Collections.sort(和Arrays.sort)进行自动排序,对象可以用作有序映射中 的键或有序集合中的元素,无需指定比较器。
    • Comparator:强行对某个对象进行整体排序。可以将Comparator 传递给sort方法(如Collections.sort或Arrays.sort),从而允许在排序顺序上实现精确控制。还可以使用Comparator来控制某些数据结构(如有序set或 有序映射)的顺序,或者为那些没有自然顺序的对象collection提供排序。
    • 简而言之就是able需要在你的JavaBean里实现接口重写方法,只能重写一次,功能单一。tor可以在你想用的时候就通过匿名内部类实现重写,然后实现定制功能,并多次重写
©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页