数组、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要移动 ...
随机推荐
- MATLAB下数组随机打乱顺序的方法
一:问题 有两个规模相同的数组,两个数组相同位置的元素一一对应,现在要将两数组的元素同时打乱顺序,并且乱序后的两数组对应位置元素要保持乱序前的对应关系. 二:方法 采用randperm()函数,产生 ...
- Java操作word文档使用JACOB和POI操作word,Excel,PPT需要的jar包
可参考文档: http://wibiline.iteye.com/blog/1725492 下载jar包 http://download.csdn.net/download/javashixiaofe ...
- (转)9 db2trc案例2(1,2)
原文:http://book.51cto.com/art/200906/130068.htm 9.3.3 db2trc案例2(1) 在AIX操作系统上,系统原先运行良好,而后用户从DB2 V8 FP ...
- MySQL笔记(4)---表
1.前言 上一章记录了MySQL中的一些文件组成,以及相关作用和参数配置,本章开始记录深层次的存储结构,以便更好理解MySQL的设计. 2.索引组织表 InnoDB中,表都是根据主键顺序组织存放的,这 ...
- JAVA 利用Dom4j实现英语六级词汇查询 含演示地址
要求 必备知识 基本了解JAVA编程知识,DOM基础. 开发环境 MyEclipse10 演示地址 演示地址 通过前面几天的学习,现在基本掌握了JAVA操作DOM方面的知识,现在来一个小DEM ...
- tomcat 调优-生产环境必备
目录 1. tomcat 启动慢 1.1 tomcat 获取随机值阻塞 1.2 tomcat 需要部署的web应用程序太多 1.3 tomcat启动内存不足 2 Connector 调优 2.2 Co ...
- Windows Mobile设备操作演示准备工作小记
公司最近为PDA开发了一款作业程序,我在工作中常常需要将操作过程通过电脑上设影出来为客户讲解使用方法.本文记录了相关的准备工作. 1. 微软嵌入式操作系统体系 RTOS: Embedded Real ...
- redis-小用
1.redis之flushall.flushdb‘尴尬’操作恢复 redis是基于内存的一种高效数据库,在内存中高效但是不安全,重启和断电都会导致数据丢失.所以就需要用到数据的持久化,redis有两种 ...
- git 分支 branch 操作
创建分支 git branch test: 基于当前commit创建test分支..git/HEAD 文件中记录了当前分支名字. 删除分支 git branch -d test:删除本地test分支 ...
- Windows安装Apache2.4和PHP5.6
VC11 下载安装http://www.microsoft.com/en-us/download/details.aspx?id=30679 ================= PHP(5.6) VC ...