数据结构概述,List集合,Set集合,可变参数和Collections集合工具类

一、数据存储的常用结构
栈、队列、数组、链表和红黑树。
stack,又称堆栈,它是运算受限的线性表,其限制是仅允许在标的一端进行插入和删除操作,不允许在其他任何位置进行添加、查找、删除等操作。
对元素的存取有以下的特点:先进后出,栈的入口、出口都是栈的顶端位置。

压栈:就是存元素。即,把元素存储到栈的顶端位置,栈中已有元素依次向栈底方向移动一个位置。
弹栈:就是取元素。即,把栈的顶端位置元素取出,栈中已有元素依次向栈顶方向移动一个位置。

队列queue,简称队,它同堆栈一样,也是一种运算受限的线性表,其限制是仅允许在表的一端进行插入,而在表的另一端进行删除。

简单的说,采用该结构的集合,对元素的存取有如下的特点:先进先出。
数组:Array,是有序的元素序列,数组是在内存中开辟一段连续的空间,并在此空间存放元素。
对元素的存取有如下的特点:

  • 查找元素快:通过索引,可以快速访问指定位置的元素
  • 增删元素慢
  • 指定索引位置增加元素:需要创建一个新数组,将指定新元素存储在指定索引位置,再把原数组元素根据索引,复制到新数组对应索引的位置。
  • 指定索引位置删除元素:需要创建一个新数组,把原数组元素根据索引,复制到新数组对应索引的位置,原数组中指定索引位置元素不复制到新数组中。

链表:linked list,由一系列结点node(链表中每一个元素称为结点)组成,结点可以在运行时i动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。我们常说的链表结构有单向链表与双向链表,那么这里给大家介绍的是单向链表
简单的说,采用该结构的集合,对元素的存取有如下的特点:

  • 多个结点之间,通过地址进行连接。

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

  • 增删元素快:

    • 增加元素:只需要修改连接下个元素的地址即可。

    • 删除元素:只需要修改连接下个元素的地址即可。

红黑树
  二叉树是每个节点最多有两个子树的树结构。顶上的叫根结点,两边被称作“左子树”和“右子树”。
  红黑树本身就是一颗二叉查找树,将节点插入后,该树仍然是一颗二叉查找树。也就意味着,树的键值仍然是有序的。
红黑树的约束:

  1. 节点可以是红色的或者黑色的
  2. 根节点是黑色的
  3. 叶子节点(特指空节点)是黑色的
  4. 每个红色节点的子节点都是黑色的
  5. 任何一个节点到其每一个叶子节点的所有路径上黑色节点数相同

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

二、 List集合
List接口特点:

  1. 它是一个元素存取有序的集合。例如,存元素的顺序是a、b、c。那么集合中,元素的存储就是按照a、b、c的顺序完成的)。
  2. 它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素(与数组的索引是一个道理)。
  3. 集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素。
    List接口的子类java.util.ArrayList类,该类中的方法都是来自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):用指定元素替换集合中指定位置的元素,返回值的更新前的元素。

练习一

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class test1 {
public static void main(String[] args) {
    List<String> l1 = new ArrayList<>();
    //往尾部添加指定元素
    l1.add("你好");
    l1.add("我好");
    l1.add("大家好");

    System.out.println(l1);
    //add(int incex,String s)往指定位置添加
    l1.add(1,"我不好");
    System.out.println(l1);
    //往指定位置删除
    l1.remove(2);
    System.out.println(l1);
    //set修改指定位置的元素
    l1.set(1,"我很好");
    System.out.println(l1);
    //get获取指定位置的元素
    String s = l1.get(1);
    System.out.println(s);
    //三种遍历。
    System.out.println("for增强");
    for (String s1 : l1) {
        System.out.println(s1);
    }
    System.out.println("普通for循环");
    for (int i = 0; i < l1.size(); i++) {
        System.out.println(l1.get(i));
    }
    System.out.println("Iterator遍历");
    Iterator<String> it = l1.iterator();
    while(it.hasNext()){
        String s1 = it.next();
        System.out.print(s1);
 	   }
  }
}

1. ArrayList集合

java.util.ArrayList集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据、遍历数据,所以ArrayList是最常用的集合。
list接口大小可变数组的实现。底层是一个数组。此实现不是同步的,也就是说这是多线程。效率高。
2.LinkedList
java.util.LinkedList 集合 implements List接口
LinkedList集合的特点
1.底层是一个链表结构:查询慢,增删快。
2.里边包含了大量操作首尾元素的方法。

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 E pop():从此列表所表示的堆栈处弹出一个元素。
  • public void push(E e):将元素推入此列表所表示的堆栈。
  • public boolean isEmpty():如果列表不包含元素,则返回true。

在开发时,LinkedList集合也可以作为堆栈,队列的结构使用。(了解即可)

练习

 import java.util.LinkedList;

/*

 * `public void addFirst(E e)`:将指定元素插入此列表的开头。
 * `public void addLast(E e)`:将指定元素添加到此列表的结尾。
 * `public E getFirst()`:返回此列表的第一个元素。
 * `public E getLast()`:返回此列表的最后一个元素。
 * `public E removeFirst()`:移除并返回此列表的第一个元素。
 * `public E removeLast()`:移除并返回此列表的最后一个元素。
 * `public E pop()`:从此列表所表示的堆栈处弹出一个元素。
 * `public void push(E e)`:将元素推入此列表所表示的堆栈。
 * `public boolean isEmpty()`:如果列表不包含元素,则返回true。

 */
public class test1 {
	public static void main(String[] args) {
  	  LinkedList<String > L1 = new LinkedList<>();
    //将元素插入列表的开头
    L1.addFirst("AA1");
    L1.addFirst("AB1");
    L1.addFirst("AC1");
    System.out.println(L1);
    //获取元素
    System.out.println(L1.getFirst());
    System.out.println(L1.getLast());
   //删除元素
    System.out.println(L1.removeFirst());
    System.out.println(L1.removeLast());
    System.out.println(L1);
    //添加元素
    L1.add("ABC");
    System.out.println(L1);
    //弹出栈顶元素
    System.out.println("弹出栈顶元素");

   /* while(!L1.isEmpty()){
        System.out.println(L1.pop());//弹出栈顶元素
    }*/
    //压入栈
    L1.push("ccc");
    System.out.println(L1);
	}
}

三、Set接口

java.util.Set接口 extends Collection接口
Set接口的特点:
  1.不允许存储重复的元素。
  2.没有索引,没有带索引的方法,不能用普通的for循环遍历。
java.util.HashSet集合 implements Set接口
HashSet特点:

  1.不允许存储重复的元素,
 2.没有索引,没有带索引的方法,也不能使用普通的for循环遍历。
 3.是一个无序集合,存储和取出元素的顺序可能不一致。
 4.底层是一个哈希表结构(查询速度非常快)
Set集合有多个子类,这里介绍其中的java.util.HashSetjava.util.LinkedHashSet这两个集合。Set集合取出元素的方式可以采用:迭代器、增强for。
java.util.HashSet底层的实现其实是一个java.util.HashMap支持。

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

哈希表

JDK1.8之前,哈希表底层采用数组+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而JDK1.8中,哈希表存储采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。
简单的来说,哈希表是由数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的。
  如果往集合中存放自定义的对象,那么保证其唯一,就必须复写hashCode和equals方法建立属于当前对象的比较方式。

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

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

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

   public Student() {
 }

public Student(String name, int age) {
    this.name = name;
    this.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;
}
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);
}

@Override
public int hashCode() {
    return Objects.hash(name, age);
    }
}

练习

public class HashSetDemo {
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);
    }
}
}

2. LinkedHashSet

我们知道HashSet保证元素唯一,可是元素存放进去是没有顺序的,那么我们要保证有序,怎么办呢?
在HashSet下面有一个子类java.util.LinkedHashSet,它是链表和哈希表组合的一个数据存储结构。

import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;

public class test1 {
public static void main(String[] args) {
    HashSet<String> H1 = new HashSet<>();
    H1.add("bbb");
    H1.add("aaa");
    H1.add("abc");
    H1.add("bbc");
    System.out.println(H1);//无序的
    LinkedHashSet<String> set = new LinkedHashSet<String>();
    set.add("bbb");
    set.add("aaa");
    set.add("abc");
    set.add("bbc");
    System.out.println(set);//有序,存什么数据就输出什么数据
    Iterator<String> it = set.iterator();
    while (it.hasNext()) {
        System.out.println(it.next());
    }
	}
}

四、可变参数

JDK1.5之后,如果定义一个方法需要接受多个参数,并且多个参数类型一致,可以对其简化成如下格式:

修饰符 返回值类型 方法名(参数类型... 形参名){  }

…代表可以传递多个参数。

修饰符 返回值类型 方法名(参数类型[] 形参名){  }

只是后面这种定义,在调用时必须传递数组,而前者可以直接传递数据即可。

JDK1.5以后。出现了简化操作。 用在参数上,称之为可变参数。

同样是代表数组,但是在调用这个带有可变参数的方法时,不用创建数组(这就是简单之处),直接将数组中的元素作为实际参数进行传递,其实编译成的class文件,将这些元素先封装到一个数组中,在进行传递。这些动作都在编译.class文件时,自动完成了。
可变参数底层是一个数组,如

pubic static int add (int …arr){}
pubic static int add()
pubic static int method(String b,double c,int d ,int …a){}

可变参数得注意事项

  1. 一个方法的参数列表,只能有一个可变参数
  2. 如果方法的参数有多个,那么可变参数 必须写在参数列表的末尾。

可变参数终极写法

public static void method (Object…obj){ }

练习

public static int add(int …arr){
	System.out.println(arr);
	System.out.println(arr.length);
	return 0;
}

练习

public static int add(int...arr){
	int sum =0;
	for(itn I :arr){
	sum = i+sum;
}
	return sum;
}

五、Collections集合工具类

1. 常用功能

  • java.utils.Collections是集合工具类,用来对集合进行操作。部分方法如下:
  • public static <T> boolean addAll(Collection<T> c, T... elements):往集合中添加一些元素。
  • public static void shuffle(List<?> list) 打乱顺序:打乱集合顺序。
  • public static <T> void sort(List<T> list):将集合中元素按照默认规则排序。
  • public static <T> void sort(List<T> list,Comparator<? super T> ):将集合中元素按照指定规则排序。

2.Comparator比较器
排序,简单的说就是两个对象之间比较大小,那么在JAVA中提供了两种比较实现的方式,一种是比较死板的采用java.lang.Comparable接口去实现,一种是灵活的当我需要做排序的时候在去选择的java.util.Comparator接口完成。

那么采用的public static <T> void sort(List<T> list)这个方法完成的排序,实际上要求了被排序的类型需要实现Comparable接口完成比较的功能,在String类型上如下:

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {}

String类实现了这个接口,并完成了比较规则的定义,但是这样就把这种规则写死了,那比如我想要字符串按照第一个字符降序排列,那么这样就要修改String的源代码,这是不可能的了,那么这个时候我们可以使用

public static <T> void sort(List<T> list,Comparator<? super T> )方法灵活的完成,这个里面就涉及到了Comparator这个接口,位于位于java.util包下,排序是comparator能实现的功能之一,该接口代表一个比较器,比较器具有可比性!顾名思义就是做排序的,通俗地讲需要比较两个对象谁排在前谁排在后,那么比较的方法就是:

  • public int compare(String o1, String o2):比较其两个参数的顺序。

    两个对象比较的结果有三种:大于,等于,小于。
    如果要按照升序排序,
    则o1 小于o2,返回(负数),相等返回0,01大于02返回(正数)
    如果要按照降序排序
    则o1 小于o2,返回(正数),相等返回0,01大于02返回(负数)

简述Comparable和Comparator两个接口的区别。

Comparable:强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的compareTo方法被称为它的自然比较方法。只能在类中实现compareTo()一次,**不能经常修改类的代码实现自己想要的排序。**实现此接口的对象列表(和数组)可以通过Collections.sort(和Arrays.sort)进行自动排序,对象可以用作有序映射中的键或有序集合中的元素,无需指定比较器。自己(this)和别人(参数)比较,自己需要实现Comparable接口,重写比较规则compareTo方法

Comparator 强行对某个对象进行整体排序。可以将Comparator 传递给sort方法(如Collections.sort或 Arrays.sort),从而允许在排序顺序上实现精确控制。还可以使用Comparator来控制某些数据结构(如有序set或有序映射)的顺序,或者为那些没有自然顺序的对象collection提供排序。相当于找一个第三方的裁判,比较两个.数据。

练习

/*
- `public static <T> boolean addAll(Collection<T> c, T... elements)  `:往集合中添加一些元素。
- `public static void shuffle(List<?> list) 打乱顺序`:打乱集合顺序。
- `public static <T> void sort(List<T> list)`:将集合中元素按照默认规则排序。
- `public static <T> void sort(List<T> list,Comparator<? super T> )`:将集合中元素按照指定规则		排序。
 */
public class test {
 public static void main(String[] args) {
    //往集合中添加多个元素
    ArrayList<String> str = new ArrayList<>();
    /*str.add("小");
    str.add("明");
    str.add("和");
    str.add("小");
    str.add("花");*/
    Collections.addAll(str,"a","b","c","d","e");
    System.out.println(str);
    Collections.shuffle(str);
    //打乱集合中元素的顺序
    System.out.println(str);
    //排序方法  按照第一个单词的降序
    Collections.sort(str, new Comparator<String>() {
        @Override
        public int compare(String o1, String o2) {
            return o2.charAt(0) - o1.charAt(0);
        }
    });
    System.out.println(str);

   /* //按默认的规则排序
    Collections.sort(str);
    System.out.println(str);*/



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值