数组、ArrayList、链表、LinkedList
数组
| 数组 | ||||
| 数组类型 |
不可重复 无序(线性查找) |
可重复(找到第一个即可) 无序(线性查找) |
不可重复 有序(二分查找) |
可重复(找到第一个即可) 有序(二分查找) |
| 插入 | O(N) |
O(1) |
O(logN+N) | O(logN+N) |
| 查询 | O(N) | O(N) | O(logN) | O(logN) |
| 删除(无洞) | O(N) | O(N) | O(lonN+N) | O(logN+N) |
| 总结 | 可重复无序插入快、下标已知更新查找快;查找删除慢、大小固定 | 查找快;插入删除慢、大小固定 | ||
| 应用 | 员工表,雇用解雇不经常发生 | |||
| java数组 | 无序、可重复;插入快、查询删除慢、大小固定;如果已知下标,更新查找快 | |||
| ArrayList | 大小可以扩展;但这是以牺牲效率为代价的 | |||
| Vector | 大小可以扩展;但这也是以牺牲效率为代价的 | |||
java 数组(无序、可重复)
已知下标查找更新快O(1)
String str = strs[1];
strs[1] = "花";
查找慢O(N)
int index = findChar("花", strs);
删除慢O(N)
deleteChar("花", strs);
中部插入慢O(N)
insertCharWithMiddle("兴", 1, strs);
大小固定
public static void main(String[] args) {
String[] strs = {"中", "华", "人", "民", "共", "和", "国", null, null, null, null};
print(strs);
// 已知下标查找更新快
System.out.println(strs[1]);
strs[1] = "花";
print(strs);
// 查找慢,需要花费O(N)的时间
int index = findChar("花", strs);
if (index == strs.length) {
System.out.println("Can't find this char");
} else {
System.out.println("Find this char");
}
// 删除慢,需要花费O(N)的时间
deleteChar("花", strs);
print(strs);
// 中部插入慢,需要花费O(N)的时间
insertCharWithMiddle("兴", 1, strs);
print(strs);
}
private static void insertCharWithMiddle(String str, int index, String[] strs) {
for (int i = strs.length - 2; i >= index; i--) {
strs[i + 1] = strs[i];
}
strs[index] = str;
}
private static void deleteChar(String str, String[] strs) {
int index = findChar(str, strs);
if (index != strs.length) {
for (int i = index; i < strs.length - 2; i++) {
strs[i] = strs[i + 1];
}
strs[strs.length - 1] = null;
}
}
public static int findChar(String str, String[] strs) {
for (int i = 0; i < strs.length; i++) {
if (strs[i].equals(str)) {
return i;
}
}
return strs.length;
}
public static void print(String[] strs) {
System.out.println(Arrays.asList(strs));
}
ArrayList
末尾插入快,已知下标查找快更新快
一个参数的add("xxx")方法效率高O(1)
get(1)方法效率高O(1)——已知下标查找快
set(1, "xxx")方法效率高O(1)——已知下标更新快
中部插入、查询、删除慢
add(1, "xxx")方法效率低O(N)——中部插入
contains、indexOf方法效率低O(N)——查询慢
remove(1),remove("xxx")方法效率低O(N)——删除慢
数组固定大小,虽然ArrayList可以自动扩展,但是以牺牲效率为代价的。
public static void main(String[] args) {
List<String> list = new ArrayList<>(8);
// add方法效率高O(1)
list.add("中");
list.add("华");
list.add("人");
list.add("民");
list.add("共");
list.add("和");
list.add("国");
System.out.println(list);
// get(1),方法效率高O(1),如果知道下标查找快
System.out.println(list.get(1));
// add(1, "xxx")方法效率低O(N),中部插入慢
list.add(1, "花");
System.out.println(list);
// 删除慢O(N)
list.remove(1);
list.remove("人");
System.out.println(list);
// contains、indexOf方法都比较慢,需要O(N)的时间
System.out.println(list.contains("中"));;
System.out.println(list.indexOf("中"));
}
ArrayList容量扩展源码分析
package java.util; import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import sun.misc.SharedSecrets; public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable { // 默认容量是10
private static final int DEFAULT_CAPACITY = 10; // 默认最大容量是MAX_ARRAY_SIZE,实际可以扩展至Integer的最大值
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; public boolean add(E e) {
// ensure /ɪn'ʃʊə/ 确保 Capacity /kəˈpæsəti/ 容量
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
// 原来数组的元素个数加上新集合的容量
ensureCapacityInternal(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == EMPTY_ELEMENTDATA) {
// System.out.println(Math.max(10, 11)); 输出11,比较两个数字,返回大的数字
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
} ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
// 父类的一个成员变量,应该是修改次数的记录
modCount++;
// 数组容量不够
if (minCapacity - elementData.length > 0)
// grow /grəʊ/ 扩大
grow(minCapacity);
}
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
// System.out.println(20 >> 1); 结果是20的二分之一,10
// 1、扩展后的数组是原来数组加上原来数组的一半,适用于add(E e)方法
// add(int index, E e)指定的下标越界会报异常,下标必须正确,不存在扩容
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 2、扩展后的数组是指定的下标值,比如原有容量是10,addAll一个有8个元素的集合
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 3、扩展后的数组是Integer的最大值,默认的最大值是Integer.MAX_VALUE - 8
// private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}
}
链表
除非频繁通过下标访问各个数据,否则都可以使用链表代替数组
链表也可以是有序的无序的,可重复的不可重复的
简单的一个链表定义
class Link {
private long id; // data
private String name; // data
private byte age; // data
private String address; // data
private Link next;
}
class LinkList {
private Link first;
}
最后一个元素的next引用是null
单链表
insertFirst();
deleteFirst();
isEmpty(); // 是否为空
find(); // 遍历,查找指定Link
delete(); // 遍历,删除指定Link
insertAfter(); // 遍历,插入
双端链表
新增对最后一个Link的引用
insertLast();
表头多次插入会颠倒Link插入的顺序;表尾多次插入会保持Link插入的顺序
双端链表也不能提高删除最后一个链接点的效率
链表的效率
表头插入查询删除快,O(1)
中部插入查询删除慢,需要O(N)次比较;在数组中执行这些操作也需要O(N)次比较,但是链表仍然要快一些,因为链表不需要移动元素,只需要比较,而复制时间大于比较时间
有序链表
只有insert()方法与无序链表中的insert()方法不同
效率:插入删除O(N),删除最小值O(1)
双向链表

每个Link多了一个指向前一个元素的引用
第一个元素指向前一个元素的引用是null
双向链表的缺点是每次插入或删除一个Link的时候,要处理四个链接点的引用,而不是两个
双向链表不必是双端链表
deleteLast();
链表迭代器
实现从链接点到链接点步进,以提高效率
java LinkedList
java里的LinkedList是一个双端链表、双向链表。
public static void main(String[] args) {
LinkedList<String> strings = new LinkedList<>();
strings.add("1");// 末尾添加
strings.add(1,"2");// 遍历,for循环的i和index比较,在Node里并没有成员变量index
strings.addFirst("3");
strings.addLast("4");
strings.contains("5");// 遍历
strings.element();//返回第1项
strings.get(1);// 遍历,for循环的i和index比较
strings.getFirst();
strings.getLast();
strings.indexOf("6");// 遍历,for循环里index递增并返回
strings.offer("7");// 末尾添加
strings.offerFirst("8");// 表头添加
strings.offerLast("9");// 末尾添加
strings.peek();// 返回第1项
strings.peekFirst();
strings.peekLast();
strings.poll();
strings.pollFirst();
strings.pollLast();
strings.pop();// 弹出第1项
strings.push("");// 添加到第1项
strings.remove(); //删除第1项
strings.remove(1);
strings.remove("10");
strings.removeFirst();
strings.removeLast();
}
java ArrayList和LinkedList
ArrayList底层是一个无序的可重复的数组,LinkedList底层是一个双端双向链表。
除非频繁地通过下标查询数据,否则都可以使用LinkedList来代替;LinkedList不需要扩容,直接在链表末尾添加元素,如果是添加一个集合,使用for循环。
首尾查询插入删除
ArrayList尾部插入快O(1)
LinkedList首尾插入快O(1)
中部查询插入删除
ArrayList中部插入删除O(N),N
LinkedList中部插入删除O(N),N/2
数组、ArrayList、链表、LinkedList的更多相关文章
- JAVA 基本数据结构--数组、链表、ArrayList、Linkedlist、hashmap、hashtab等
概要 线性表是一种线性结构,它是具有相同类型的n(n≥0)个数据元素组成的有限序列.本章先介绍线性表的几个基本组成部分:数组.单向链表.双向链表:随后给出双向链表的C.C++和Java三种语言的实现. ...
- 数组Array和列表集合ArrayList、LinkedList和Vector的区别
一.ArrayList和Vector的区别 ArrayList与Vector主要从以下方面来说. 1.同步性: Vector是线程安全的,也就是说是同步的,而ArrayList是线程序不安全的,不是同 ...
- C# 基础至集合-数组、List<T>、ArrayList、LinkedList、HashMap的一些区别
1:数组 ]; //赋值 strs[] = "; strs[] = "; //修改 strs[] = "burg"; //删除 没法删除 除非转化为可变数组li ...
- Collection集合重难点梳理,增强for注意事项和三种遍历的应用场景,栈和队列特点,数组和链表特点,ArrayList源码解析, LinkedList-源码解析
重难点梳理 使用到的新单词: 1.collection[kəˈlekʃn] 聚集 2.empty[ˈempti] 空的 3.clear[klɪə(r)] 清除 4.iterator 迭代器 学习目标: ...
- 深入理解java中的ArrayList和LinkedList
杂谈最基本数据结构--"线性表": 表结构是一种最基本的数据结构,最常见的实现是数组,几乎在每个程序每一种开发语言中都提供了数组这个顺序存储的线性表结构实现. 什么是线性表? 由0 ...
- ArrayList,Vector,LinkedList
在java.util包中定义的类集框架其核心的组成接口有如下:·Collection接口:负责保存单值的最大父接口 |-List子接口:允许保存重复元素,数据的保存顺序就是数据的增加顺序: |-Set ...
- Java数据结构之表的增删对比---ArrayList与LinkedList之一
一.Java_Collections表的实现 与c不同Java已经实现并封装了现成的表数据结构,顺序表以及链表. 1.ArrayList是基于数组的实现,因此具有的特点是:1.有索引值方便查找,对于g ...
- C++模拟实现JDK中的ArrayList和LinkedList
Java实现ArrayList和LinkedList的方式采用的是数组和链表.以下是用C++代码的模拟: 声明Collection接口: #ifndef COLLECTION_H_ #define C ...
- ArrayList与LinkedList用法与区别
1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构. 2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedLis ...
- ArrayList 和 LinkedList 的区别
1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构.2.对于随机访问get和set,ArrayList优于LinkedList,因为LinkedList要移动 ...
随机推荐
- 在MVC3中修改KindEditor实现上传图片到指定文件夹
KindEditor编辑器默认上传的图片文件夹,是根据系统时间自动生成的,图片是自动上传到这些文件夹里面,无法选择.如果要上传图片到指定文件夹,像相册一样管理图片,则需要扩展KindEditor编辑器 ...
- 阿里巴巴Java开发规范---个人总结
一.编程规约 (一) 命名规约 1. [强制]所有编程相关命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束. 反例: _name / __name / $Object / name_ / ...
- 有意思的App
掘金 javadoop 专业相机也羡慕奖 – Focos 说个睡前故事 so easy 奖 – 洪恩双语绘本 效率蹭蹭上升奖 – Sorted³ 时光隧道走一回奖 – NOMO 相机 设计师也爱用奖 ...
- 到网上收集了一个“高大上”的CSS3登入表单和大家分享一下
要求 必备知识 基本了解CSS语法,初步了解CSS3语法知识. 开发环境 Adobe Dreamweaver CS6 演示地址 演示地址 预览截图(抬抬你的鼠标就可以看到演示地址哦): 制作步骤: 一 ...
- Spring框架引入
Struts与Hibernate可以做什么事? Struts, Mvc中控制层解决方案 可以进行请求数据自动封装.类型转换.文件上传.效验… Hibernate, 持久层的解决方案: 可以做到, 把对 ...
- nova scheduler 介绍
在 openstack 中,scheduler 负责从宿主机(运行 nova-compute 的节点)中根据一系列的算法和参数(CPU 核数,可用 RAM,镜像类型等 )选择出来一个,来部署虚拟机(i ...
- Java集合——HashMap,HashTable,ConcurrentHashMap区别
Map:“键值”对映射的抽象接口.该映射不包括重复的键,一个键对应一个值. SortedMap:有序的键值对接口,继承Map接口. NavigableMap:继承SortedMap,具有了针对给定搜索 ...
- SpringMVC之类型转换
在数据绑定上,SpringMVC提供了到各种基本类型的转换,由前端到后台时,SpringMVC将字符串参数自动转换为各种基本类型.而对于其他,则需要自己编写代码进行转换.本随笔以转换时间类型为例,使用 ...
- PTA (Advanced Level) 1007 Maximum Subsequence Sum
Maximum Subsequence Sum Given a sequence of K integers { N1, N2, ..., NK }. A continuous su ...
- Hibernate 分页 查询
昨天的作业 分页: 主要的代码块:(明天实现分页的封装) package com.cy.beans; import java.util.List; /** * 定义一个分页对象 * @author ...