Java集合
java根据存储元素以及取出元素的特点不同,提供不同存储容器,统称为集合
一、数据结构
1.1、栈
栈是一种特殊的线性表,只允许在栈的一段(栈顶)进行操作,其特点是先进后出、后进先出。
1.2、队列
队列和栈一样是一种线性表,其允许在栈的一端可以进行入队操作,在栈的另一端可以进行出队操作,特点是先进先出。
1.3、数组
数组是有序元素的序列,在内存中的分配是连续的,有索引概念,特点是查询快、增删慢。
1.4、链表
链表是由一系列节点组成,节点包含数据域和指针域,按照链表的指向又分为单向链表、双向链表、循环链表等,链表的特点是查询慢、增删快。
1.5、树
树是由n(n>=1)个节点组成的有层次的集合,特点有:
1)、每个节点有0个或多个子节点。
2)、没有父节点的节点称为根节点。
3)、每一个非根节点有且只有一个父节点。
4)、除了根节点外,每个子节点可以分为多个不相交的子树。
5)、右子树永远比左子树大,读取顺序为从左到右。
1.6、哈希表
哈希表又叫散列表,由键(key)和值(value)进行直接访问的一种数据结构,通过key和value映射到集合的某个位置,访问该位置上的元素。
1.7、图
图是一系列顶点的集合,顶点之间通过边进行连接,图分为无向图和有向图:
1)、无向图:边仅仅连接两个顶点,没有其他含义。
2)、有向图:边不仅连接两个顶点,并且具有方向。
二、集合体系
2.1、Collection(接口)
集合是一组被称为其元素的对象,collection是一个接口无法直接对其创建对象,若想要使用collection中的方法可以实现其子接口(list和set)的具体子类
2.1.1、list
特点:元素有序且可以发生重复的集合,有索引下标的概念。
1)、ArrayList
底层数据结构是数组,查询快,增删慢,线程不安全的,效率高。
//创建List集合对象
List ls1 = new ArrayList;
//创建元素对象
Student s1 = new Student("zhangsan","21");
Student s2 = new Student("lisi","22");
Student s3 = new Student("wangwu","23");
将元素添加到List集合
ls1.add(s1);
ls1.add(s2);
ls1.add(s3);
void add(int index,Object element) 指定位置索引添加元素到集合中
//将s5添加在s2和s3之间
Student s5 = new Student("zzz", 20);
ls1.add(2,s5);
E remove(int index) 指定索引删除某个元素,返回被删除的元素
//o 接收返回值
Object o = ls1.remove(2);
System.out.println("被删除的是: "+o);
Object get(int index) 根据索引获取集合中的元素对象
Object o = ls1.get(2);
System.out.println(o);
Object set(int index,Object element) 指定位置索引,修改元素,返回原本位置上的元素对象
Student s6 = new Student("www", 31);
Object o = ls1.set(2, s6);
System.out.println("原数据为: "+o);
一个迭代器对象只有一个游标可以移动 ,ListIterator listIterator() List集合专有的迭代器
//listIterator()通过观察子类源码发现,底层是返回了一个ListItr类的对象
//ListItr类是继承自Itr类,也拥有hasNext()和next()方法
ListIterator listIterator = ls1.listIterator();
while (listIterator.hasNext()){
Object o1 = listIterator.next();
System.out.println(o1);
}
2)、Vector
底层数据结构是数组,查询快,增删慢,线程安全的,效率低
3)、LinkedList
底层数据结构是双链表,增删快,查询慢,线程不安全的,效率高。
LinkedList类特有功能: public void addFirst(E e)及addLast(E e) public E getFirst()及getLast() public E removeFirst()及public E removeLast()
//public void addFirst(E e)及addLast(E e) 在List集合开头和结尾添加元素
ls1.addFirst("小胡");
ls1.addLast("小花");
//public E getFirst()及getLast() 获取List集合第一个和最后一个元素
System.out.println(ls1.getFirst());
System.out.println(ls1.getLast());
//public E removeFirst()及public E removeLast() 删除List集合第一个和最后一个元素
System.out.println(ls1.removeFirst());
System.out.println(ls1.removeLast());
2.1.2、Set
元素唯一且无序,没有索引
1)、HashSet
底层数据结构是哈希表
//创建set集合对象
HashSet<Student> set1 = new HashSet<>();
//创建元素对象
Student s1 = new Student("zhangsan",10);
Student s2 = new Student("lisi",12);
Student s3 = new Student("wangwu",13);
将元素添加到set集合
set1.add(s1);
set1.add(s2);
set1.add(s3);
2)、LinkedHashSet
继承自HashSet类, 底层数据结构是哈希表和双链表,哈希表保证了元素的唯一性,双链表保证了元素的有序
3)、TreeSet
底层数据结构是红黑树,存在两种排序方式:自然排序和比较器排序
public class TreeSetTest {
public static void main(String[] args) {
//创建键盘录入对象
Scanner sc = new Scanner(System.in);
//创建TreeSet集合
TreeSet<Student> set1 = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
//显式条件:按照总分从高到低输出到控制台
int i = o2.getSumScore() - o1.getSumScore();
//隐式条件
//总分一样,各科的分数不一定一样
//总分一样,语文成绩不一定一样
int i2 = (i == 0) ? o2.getChinese() - o1.getChinese() : i;
//总分,语文成绩一样,数学成绩不一定一样
int i3 = (i2 == 0) ? o2.getMath() - o1.getMath() : i2;
//各科分数都一样,姓名不一定一样
return (i3 == 0) ? o2.getName().compareTo(o1.getName()) : i3;
}
});
Student student;
for (int i = 1; i <= 5; i++) {
System.out.println("请输入第 "+i+" 个学生的信息:");
System.out.print("姓名:");
String name = sc.next();
System.out.print("语文成绩:");
int chinese = sc.nextInt();
System.out.print("数学成绩:");
int math = sc.nextInt();
System.out.print("英语成绩:");
int english = sc.nextInt();
//创建一个学生对象,将当前学生的信息进行封装
student = new Student(name,chinese,math,english);
//将学生对象添加到集合中
set1.add(student);
System.out.println("----------------------------");
}
System.out.println("所有学生信息添加完毕!具体信息如下:");
System.out.println("姓名\t\t语文成绩\t\t数学成绩\t\t英语成绩\t\t英语成绩");
//遍历集合
for (Student student1 : set1) {
System.out.println(student1.getName()+"\t\t"+student1.getChinese()+"\t\t"+student1.getMath()+"\t\t"+student1.getEnglish()+"\t\t"+student1.getSumScore());
}
}
}
两种排序方式:
自然排序:使用无参构造方法创建TreeSet集合对象,要求元素类实现Comparable<元素类>接口,重写compareTo方法。
Comparable接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序。
实现Comparable的类必须实现 compareTo(Object obj) 方法,两个对象即通过compareTo(Object obj)方法的返回值来比较大小。如果当前对象this大于形参对象obj,则返回正整数,如果当前对象this小于形参对象obj,则返回负整数,如果当前对象this等于形参对象obj,则返回零。
实现Comparable接口的对象列表(和数组)可以通过 Collections.sort 或 Arrays.sort进行自动排序。
class Student implements Comparable {
private String name;
private Integer age;
@Override
public int compareTo(Object o) {
//下面那一片代码都可以用注释这个代替,因为age可以直接比较大小
//为了写的更详细,所以展开弄得
//return this.age.compareTo(o.getAge());
if(o instanceof Student) {
Student other = (Student) o;
if (this.age > other.age) {
return 1;
} else if (this.age < other.age) {
return -1;
}
return 0;
}
throw new RuntimeException("输入的数据类型不一致");
} //构造器、getter、setter、toString()方法略
}
比较器排序:使用有参构造方法创建TreeSet集合对象,将实现了Comparator接口且重写compare方法的对象当作构造方法的参数使用。
当元素的类型没有实现java.lang.Comparable接口而又不方便修改代码,或者实现了java.lang.Comparable接口的排序规则不适合当前的操作,那么可以考虑使用 Comparator的对象来排序,强行对多个对象进行整体排序的比较
重写compare(Object o1,Object o2)方法,比较o1和o2的大小:如果方法返 回正整数,则表示o1大于o2;如果返回0,表示相等;返回负整数,表示 o1小于o2
可以将 Comparator传递给 sort方法(如 Collections.sort或 Arrays.sort), 从而允许在排序顺序上实现精确控制。
public static void main(String[] args) {
TestA testA1 = new TestA("老张", 3);
TestA testA2 = new TestA("老李", 1);
TestA testA3 = new TestA("老王", 2);
List<TestA> list = new ArrayList<>();
list.add(testA1);
list.add(testA2);
list.add(testA3);
System.out.println("排序前--:"+list.toString());
Collections.sort(list, new Comparator<TestA>() {
@Override
public int compare(TestA o1, TestA o2) {
//升序
return o1.getAge().compareTo(o2.getAge());
}
});
System.out.println("升序排序后--:"+list.toString());
Collections.sort(list, new Comparator<TestA>() {
@Override
public int compare(TestA o1, TestA o2) {
//降序
return o2.getAge().compareTo(o1.getAge());
}
});
System.out.println("降序排序后--:"+list.toString());
}
2.2、Map(接口)
HashMap(由键决定特点):无序、不重复、无索引。(用的最多)
LinkedHashMap (由键决定特点):由键决定的特点:有序、不重复、无索引。
TreeMap(由键决定特点):按照大小默认升序排序、不重复、无索引。
2.2.1、创建方法
//创建Map集合的对象
Map<String,String> m= new HashMap<>();
//2.添加元素
//put方法的细节:
//添加/覆盖
//在添加数据的时候,如果键不存在,那么直接把键值对对象添加到map集合当中,方法返回nu11
//在添加数据的时候,如果键是存在的,那么会把原有的键值对对象覆盖,会把被覆盖的值进行返回。
m.put("白月初","苏苏");
m.put("东方月初","红红");
m.put("戴沐白","朱竹清");
String value = m.put("白月初", "涂山苏苏");
System.out.println(value);//返回覆盖的值 苏苏
//删除
String result = m.remove("东方月初");
System.out.println(result); //返回 删除键的值 红红
//清空
//m.clear();
//判断是否包含键
boolean keyResult = m.containsKey("戴沐白");
System.out.println(keyResult);//true
//是否包含 值
boolean valueResult = m.containsValue("朱竹清");
System.out.println(valueResult);//true
boolean empty = m.isEmpty();
System.out.println(empty);//false
int size = m.size();
System.out.println(size);//2
//打印
System.out.println(m);//{白月初=涂山苏苏, 戴沐白=朱竹清}
2.2.2、遍历方法
1)、通过键遍历集合
//创建Map集合的对象
Map<String,String> map= new HashMap<>();
//添加元素
map.put("白月初","苏苏");
map.put("东方月初","红红");
map.put("戴沐白","朱竹清");
//通过键找值
//3.1获取所有的键,把这些键放到一个单列集合当中
Set<String> keys = map.keySet();
//3.2遍历单列集合,得到每一个键
for (String key : keys){
//3.3利用map集合中的键获取对应的值 get
String value = map.get(key);
System.out.println(key+"="+value);
}
/* 运行结果:
白月初=苏苏
东方月初=红红
戴沐白=朱竹清
*/
2)、通过键值对遍历集合
//Map创建以及添加元素同上
//通过键值对对象进行遍历
//3.1通过一个方法获取所有的键值对对象,返回一个Set集合
Set<Map.Entry<String, String>> entries = map.entrySet();
//3.2遍历entries这个集合,去得到里面的每一个键值对对象
for (Map.Entry<String, String>entry :entries){ //entries 可以换为map.entrySet()
//3.3利用entry调用get方法获取键和值
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key+"="+value);
}
2.2.3、TreeMap的排序方式
1)、实现Comparable接口
//创建集合
TreeMap<Student,String>tm = new TreeMap<>();
//创建学生对象
Student s1 = new Student("zhangsan",23);
Student s3 = new Student("wangwu",25);
Student s2 = new Student("lisi",24);
Student s4 = new Student("lisi",24);
//添加元素
tm.put(s1,"江苏");
tm.put(s2,"天津");
tm.put(s3,"北京");
tm.put(s4,"南京");
//打印
System.out.println(tm);
/*运行结果:
{Student{name = zhangsan, age = 23}=江苏, Student{name = lisi, age = 24}=南京, Student{name = wangwu, age = 25}=北京}
*/
2)、比较器排序
//Integer、Double 默认情况下都是按照升序排列的
//String 按照字母再ASCII码表中对应的数字升序排列
//创建集合对象
TreeMap<Integer,String> tm =new TreeMap<>();
//添加元素
tm.put(5,"ab");
tm.put(4,"cd");
tm.put(3,"ef");
tm.put(2,"hi");
tm.put(1,"gk");
System.out.println(tm); //默认升序排序
//要求:按照降序排序 使用比较器对象
TreeMap<Integer,String> tm2 =new TreeMap<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
//o1:当前要添加的元素
//o2:表示已经在红黑树中存在的元素
return o2-o1;
}
});
//2.添加元素
tm2.put(5,"ab");
tm2.put(4,"cd");
tm2.put(3,"ef");
tm2.put(2,"hi");
tm2.put(1,"gk");
System.out.println(tm2);
/*运行结果:
{1=gk, 2=hi, 3=ef, 4=cd, 5=ab}
{5=ab, 4=cd, 3=ef, 2=hi, 1=gk}
*/