Java 中的 List —— 有序序列
List 在 java 中是个有序序列:
一、容量
ArrayList 中有一个容量概念,表示基础数组的大小(无参时默认为 10)。在需要的时候(比如 add操作)会自动增加其容量。LinkedList 没有这个概念。
TreeMap 也有容量,默认是 16.
二、改善的 search 方法
LinkedList 与 ArrayList 都很低效O(N)。比如 Collection 的 contain 和 remove 方法而言。他们均花费线性时间。下面对存、取、查找这三类情况进行比较:
- 访问数组中第 n 个数据的时间花费是 O(1) (类似地 HashMap 中通过 key 访问 value,但其存取都是 O(1) ,因为其索引是无序的,而数组是有序的索引),但是要在数组中查找一个指定的数据则是 O(N) 。当向数组中插入或者删除数据的时候,最好的情况是在数组的末尾进行操作,时间复杂度是 O(1) ,但是最坏情况是插入或者删除第一个数据,时间复杂度是 O(N) 。 在数组的任意位置插入或者删除数据的时候,后面的数据全部需要移动,移动的数据还是和数据个数有关所以总体的时间复杂度仍然是 O(N) 。
- 在链表中查找第 n 个数据以及查找指定的数据的时间复杂度是 O(N) ,但是链表插入和删除数据的时间复杂度是 O(1) ,因为只需要调整指针就可以。
- 堆栈实现了一种后进先出的语义 (LIFO) ,可以使用数组或者是链表来实现它。队列实现了先入先出的语义 (FIFO) 。队列也可以使用数组和链表来实现
提高运行效率 O(logn),可以使用 Collections.binarySearch(List list),二分法进行查找,需要对原集合/数组进行排序(双枢纽快速排序 O(n log(n))。
注意:
Collections.binarySearch 不支持 Set 集合,因为 HashSet/LinkedHashSet 使用的是哈希表,查询值(的位置/是否存在)只需要 比较哈希值,时间效率是 O(1)。因此不需要二分搜索法查找。
1 2 3 4 5 6 7 8 9 10 11 | arrayList.add( 311 ); arrayList.add( 233 ); arrayList.add( 999 ); arrayList.add( 777 ); arrayList.sort((o1, o2) -> o1 - o2); int index = Collections.binarySearch(arrayList, 777 ); if (index >= 0 ) { System.out.printf( "找到了,索引为%s" , index); } |
三、改善的 remove 方法(此方法对 ArrayList 无效,ArrayList 由于 remove 会改变数组结构,结构重组将花费大量时间。)
foreach 增强 for循环,抛异常
1 2 3 4 5 6 7 8 9 | public static void removeEvensVer2(List<Integer> lst) { for (Integer x : lst) { if (x % 2 == 0 ) lst.remove(x); } } 抛异常 java.util.ConcurrentModificationException |
正的 for 循环,这会删除下标为偶数的元素,因为每次删除后,后面的元素的下标全部减1,相当于元素位置全部左移一位,再次删除时,会跳过一个元素进行删除。
1 2 3 | for ( int i = 0 ;i < list.size();i++){ list.remove(i); } |
倒的 for循环(全部删除)
1 2 3 | for ( int i = list.size()- 1 ;i >= 0 ;i--){ list.remove(i); } |
新建一个要删除的List,最后一起删除。list.removeAll(deleteList)。
使用 while循环(但是这个方法对于 LinkedList 来说有几个糟糕的操作:1,使用 get方法,去遍历,在遍历的时候 get也花费线性时间。2,remove 同理,remove方法本身也花费线性时间)
1 2 3 4 5 6 7 8 | public static void removeEvensVer1(List<Integer> lst) { int i = 0 ; while (i < lst.size()) if (lst.get(i) % 2 == 0 ) lst.remove(i); else i++; } |
迭代器自带的 remove 处理 LinkedList:
当迭代到其节点时处理 remove 该节点的元素,仅花费常数时间。此外,LinkedList 除了 Collection 借口提供的 iterator方法之外, 还有扩展的 listIterator()
返回一个扩展接口 ListIterator<E>,具有 hasPrevious() pevious() add(Anytype x) set(AnyType newVal) 方法。主要方便从末尾向前迭代,和在迭代时添加和改变值(对于 LinkedList 改变和添加值花费较少。)
1 2 3 4 5 6 | public static void removeEvensVer3(List<Integer> lst) { Iterator<Integer> itr = lst.iterator(); while (itr.hasNext()) if (itr.next() % 2 == 0 ) itr.remove(); } |
四、排序
对于有序序列,可以使用 Collections.sort(List<T> list, Comparator<? super T> c) 按照自己的要求进行排序。
对于 TreeSet/TreeMap 基于红黑树数据结构,可以按照元素的自然顺序,或者创建 set 时提供的 Comparator
进行排序。
五、 ArrayList 与 LinkedList、Array 的区别
Array 固定长度,可以包含 primitives 基础类型与对象了;
ArrayList 基于数组结构,是大小可变数组的实现。ArrayList 只能包含 对象,可以使用泛型;
LinkedList 基于双向链表结构,List 接口的链接列表实现。实现所有可选的列表操作,并且允许所有元素(包括 null)。除了实现 List 接口外,LinkedList 类还为在列表的开头及结尾 get、remove 和 insert 元素提供了统一的命名方法。这些操作允许将链接列表用作堆栈、队列或双端队列 (实现了 Queue 与 Deque 接口)。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· 【.NET】调用本地 Deepseek 模型
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)
2017-08-21 solus 系统 - 安装 mariadb