什么是链表?
链表,顾名思义,是一条相互链接的数据节点表。每个节点由两部分组成:数据和指向下一个节点的指针。链表的基本结构如下图所示:
一般来说,链表的头结点不存放具体的数据,所以也被称为哑节点(dummy node)。原因在于这样可以比较好地区分链表的头结点,而且可以大大简化链表的各种操作,避免很多不必要的边界讨论。
链表的种类
单向链表 双向链表 循环链表 多向表(网状表)
链表的优缺点
这里的优缺点主要是和链表对应的另一个数据结构:数组相比得出的。
链表的优点在于:
1.物理存储单元上非连续,而且采用动态内存分配,能够有效的分配和利用内存资源;
2.节点删除和插入简单,不需要内存空间的重组。
作为一种数据结构,链表必然也有让人诟病的地方。链表的缺点在于:
1.不能进行索引访问,只能从头结点开始顺序查找;
2.数据结构较为复杂,需要大量的指针操作,容易出错。
数组
所谓数组,就是相同数据类型的元素按一定顺序排列的集合

构造方法摘要 | |
---|---|
ArrayList() 构造一个初始容量为 10 的空列表。 | |
ArrayList(Collection<? extends E> c) 构造一个包含指定 collection 的元素的列表,这些元素是按照该 collection 的迭代器返回它们的顺序排列的。 | |
ArrayList(int initialCapacity) 构造一个具有指定初始容量的空列表。 |
ArrayList,Vector, LinkedList的存储性能和特性
ArrayList和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector由于使用了synchronized方法(线程安全),通常性能上较ArrayList差,而LinkedList使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。
ArrayList底层是数组
List是线性表的数据结构,ArrayList是顺序存储的线性表,ArrayList实现了Serializable接口,因此它支持序列化,能够通过序列化传输
LinkedList底层是链表
LinkedList是链式存储的线性表,实质是双向链表,实现了List和Deque接口。Deque代表双端队列,既可以当做队列也可以当作栈。
Vector和ArrayList区别
Vector提供synchronized修饰方法,是线程安全版本的ArrayList
.Vector
ArryList和Vector可变长度数组的原理: 当默认10的长度的数组不够存储时,会建立一个新数组。将原来数组的内容拷贝到新的数组当中,并将新增加的元素追加到拷贝完的数组尾,如果仍然不够重复上述动作。其中,ArryList的增加是以原来50%长度进行增加,而Vector是按照100%延长。这里在添一点就是:ArryList是线程不安全的,Vector是安全的。由于是否有锁的判断将影响效率。故Arrylist效率远远高于Vector。而且只要是常用的容器就不是同步的,因为同步效率比较低。 |
ArrayList()初始化时为10的空列表
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this(10);
}
add时计算当前最小的长度和最大(10)的比较:
知识点:>>1是二分之一的表示形式
public boolean add(E e) {
ensureCapacityInternal(size + 1); // size初始化为0
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
modCount++;//protected transient int modCount = 0;
// overflow-conscious code
if (minCapacity - elementData.length > 0)// private transient Object[] elementData;初始化数组
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);//增加二分之一
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);// 复制指定的数组,截取或用 null 填充(如有必要),以使副本具有指定的长度
}