文章目录
List集合
预备知识
Collection集合体系
常见数据结构的特点
- 队列:先进先出,后进后出。
- 栈:后进先出,先进后出。
- 数组:内存连续区域,查询快,增删慢。
- 链表:元素是游离的,查询慢,首尾操作极快。
- 二叉树:永远只有一个根节点, 每个结点不超过2个子节点的树。
- 查找二叉树:小的左边,大的右边,但是可能树很高,查询性能变差。
- 平衡查找二叉树:让树的高度差不大于1,增删改查都提高了。
- 红黑树(就是基于红黑规则实现了自平衡的排序二叉树)
List集合特点:
- ArrayList、LinekdList :有序,可重复,有索引。
- 有序:存储和取出的元素顺序一致
- 有索引:可以通过索引操作元素
- 可重复:存储的元素可以重复
List集合特有方法
List集合因为支持索引,所以多了很多索引操作的独特api,其他Collection的功能List也都继承了。所以List可以使用Collection的API;
方法名称 | 说明 |
---|---|
void add(int index,E element) | 在此集合中的指定位置插入指定的元素 |
E remove(int index) | 删除指定索引处的元素,返回被删除的元素 |
E set(int index,E element) | 修改指定索引处的元素,返回被修改的元素 |
E get(int index) | 返回指定索引处的元素 |
示例1:ListDemo01类
import java.util.ArrayList;
import java.util.List;
public class ListDemo01 {
public static void main(String[] args) {
List<String> list1 = new ArrayList<>();
list1.add("java");
list1.add("java");
list1.add("html");
list1.add("css");
list1.add("javascript");
// 用Collection的方法添加元素;
list1.add(4,"c++");
//在此集合中的指定位置插入指定的元素
System.out.println(list1);;
System.out.println(list1.remove(5));
//删除指定索引处的元素,返回被删除的元素
System.out.println(list1);
System.out.println(list1.set(2, "c"));
//修改指定索引处的元素,返回被修改的元素
System.out.println(list1);
System.out.println(list1.get(4));
//返回指定索引处的元素
System.out.println(list1);
}
}
运行结果:
[java, java, html, css, c++, javascript]
javascript
[java, java, html, css, c++]
html
[java, java, c, css, c++]
c++
[java, java, c, css, c++]
List集合的遍历方式
- 迭代器
- 增强for循环
- Lambda表达式
- for循环(因为List集合存在索引)
前三种也是Collection集合的遍历方式,请参考Collection集合(yi)
方法四:因为List集合存在索引,可以用遍历数组那样遍历List集合;
示例2:ListDemo01类
import java.util.ArrayList;
import java.util.List;
public class ListDemo01 {
public static void main(String[] args) {
List<String> list1 = new ArrayList<>();
list1.add("java");
list1.add("java");
list1.add("html");
list1.add("css");
list1.add("javascript");
for (int i = 0; i < list1.size(); i++) {
System.out.println(list1.get(i));
}
}
}
运行结果:
java
java
html
css
javascript
List的实现类的底层原理
- ArrayList底层是基于数组实现的,根据查询元素快,增删相对慢。
- LinkedList底层基于双链表实现的,查询元素慢,增删首尾元素是非常快的。
ArrayList集合底层原理
- ArrayList底层是基于数组实现的:根据索引定位元素快,增删需要做元素的移位操作。
- 第一次创建集合并添加第一个元素的时候,在底层创建一个默认长度为10的数组。每次扩容都是扩容到原来长度的1.5倍。
因为ArrayList底层是基于数组实现的,所以ArrayList查询元素快,增删元素相对较慢。
LinkedList集合的底层原理
底层数据结构是双链表,查询慢,首尾操作的速度是极快的,所以多了很多首尾操作的特有API。
LinkedList集合的特有功能
方法名称 | 说明 |
---|---|
public void addFirst(E e) | 在该列表开头插入指定的元素 |
public void addLast(E e) | 将指定的元素追加到此列表的末尾 |
public E getFirst() | 返回此列表中的第一个元素 |
public E getLast() | 返回此列表中的最后一个元素 |
public E removeFirst() | 从此列表中删除并返回第一个元素 |
public E removeLast() | 从此列表中删除并返回最后一个元素 |
示例3:用LinkList类模拟枪的装弹和射击
分析:枪的装弹和射击,用栈,子弹是后进先出,先进后出。addFirst可以用push代替,removeFirst可以pop代替。
import java.util.LinkedList;
public class LinkListDemo1 {
public static void main(String[] args) {
//栈
LinkedList<String> list1 = new LinkedList<>();
list1.addFirst("第一颗子弹");
list1.addFirst("第二颗子弹");
list1.addFirst("第三颗子弹");
list1.addFirst("第四颗子弹");
list1.addFirst("第五颗子弹");
//压栈
System.out.println(list1);
while (list1.size() > 0) {
System.out.println(list1.removeFirst());
}
//出栈
System.out.println(list1);
}
}
运行结果:
[第五颗子弹, 第四颗子弹, 第三颗子弹, 第二颗子弹, 第一颗子弹]
第五颗子弹
第四颗子弹
第三颗子弹
第二颗子弹
第一颗子弹
[]
示例4:模拟四个人排队。
分析:排队先进先出,后进后出。
import java.util.LinkedList;
public class LinkListDemo2 {
public static void main(String[] args) {
//队列
LinkedList<String> list1 = new LinkedList<>();
list1.addLast("1");
list1.addLast("2");
list1.addLast("3");
list1.addLast("4");
//进队列
System.out.println(list1);
while (list1.size() > 0) {
System.out.println(list1.removeFirst());
}
//出队列
System.out.println(list1);
}
}
运行结果:
[1, 2, 3, 4]
1
2
3
4
[]
集合的并发修改异常问题
当我们从集合中找出某个元素并删除的时候可能出现一种并发修改异常问题。
示例5:迭代器遍历集合且直接用集合删除元素的时候可能出现。
错误代码:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class test {
public static void main(String[] args) {
List<String> list1 = new ArrayList<>();
list1.add("蔡徐坤");
list1.add("小黑子");
list1.add("真爱粉");
list1.add("荔枝");
list1.add("ikun");
System.out.println(list1);
Iterator it = list1.iterator();
while(it.hasNext()){
String ele = (String) it.next();
if("小黑子".equals(ele)){
list1.remove("小黑子");
}
}
System.out.println(list1);
}
}
错误信息:Exception in thread “main” java.util.ConcurrentModificationException
原因:list1.remove()删除当前元素,且后移
解决方法:迭代器遍历集合但是用迭代器自己的删除方法操作可以解决。,用it.remove()删除。
正确代码:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class test {
public static void main(String[] args) {
List<String> list1 = new ArrayList<>();
list1.add("蔡徐坤");
list1.add("小黑子");
list1.add("真爱粉");
list1.add("荔枝");
list1.add("ikun");
System.out.println(list1);
Iterator it = list1.iterator();
while(it.hasNext()){
String ele = (String) it.next();
if("小黑子".equals(ele)){
it.remove();
//删除当前元素,且不会后移
}
}
System.out.println(list1);
}
}
运行结果:
[蔡徐坤, 小黑子, 真爱粉, 荔枝, ikun]
[蔡徐坤, 真爱粉, 荔枝, ikun]
使用增强for循环,Lambda表达式可能出现,且无法解决。
示例6:使用for循环遍历并删除元素不会存在这个问题。
方案一
ublic class test {
public static void main(String[] args) {
List<String> list1 = new ArrayList<>();
list1.add("蔡徐坤");
list1.add("小黑子");
list1.add("真爱粉");
list1.add("荔枝");
list1.add("ikun");
System.out.println(list1);
for (int i = 0; i < list1.size(); i++) {
if("小黑子".equals(list1.get(i))){
list1.remove(i);
i--;
}
}
System.out.println(list1);
}
}
方案二:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class test {
public static void main(String[] args) {
List<String> list1 = new ArrayList<>();
list1.add("蔡徐坤");
list1.add("小黑子");
list1.add("真爱粉");
list1.add("荔枝");
list1.add("ikun");
System.out.println(list1);
for (int i = list1.size()-1; i >=0 ; i--) {
if("小黑子".equals(list1.get(i))){
list1.remove(i);
}
}
System.out.println(list1);
}
}