List 列表清单
1.ArrayList 数组列表 – 不安全
1.接口 List、RandomAccess: 可以插入空数据,也支持随机访问
2.基于动态数组 ==> 思考下如下 实现种 transient 作用?
transient Object[] elementData 数组
private int size 大小
3.add()
public boolean add(E e) {
	ensureCapacityInternal(size + 1);  // Increments modCount!!
	elementData[size++] = e;
	return true;
}
// 先做扩容校验
// 再将值放入尾部,size+1
4.add(index, e) 指定位置添加
public void add(int index, E element) {
    rangeCheckForAdd(index);
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    //复制,向后移动
    System.arraycopy(elementData, index, elementData, index + 1,size - index);
    elementData[index] = element;
    size++;
}
// 先做扩容校验
// 再进行数据复制,把index空出来插入(插入效率低)
5.扩容 也是数组复制过程
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1); // 位操作扩容2倍
    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);
}
// ==> ArrayList 主要消耗是数组扩容,和指定位置插入数据
// ==> 指定大小、减少指定位置插入
4.快速失败:Fail-Fast–modCount 面对并发修改快速失败
5.序列化 Serialize
ArrayList 基于动态数组,并非所有空间都被适用,故用了 transient Object[] elementData
==> 自定义序列化: 只序列化被使用的数据 当对象中自定义了 writeObject 和 readObject 方法时,
 JVM 会调用这两个自定义方法来实现序列化与反序列化
// 写序列化
private void writeObject(java.io.ObjectOutputStream s)
    throws java.io.IOException{
    // Write out element count, and any hidden stuff
    int expectedModCount = modCount;
    s.defaultWriteObject();
    // Write out size as capacity for behavioural compatibility with clone()
    s.writeInt(size);
    // Write out all elements in the proper order.
    //只序列化了被使用的数据
    for (int i=0; i<size; i++) {
        s.writeObject(elementData[i]);
    }
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
}
// 读序列化
private void readObject(java.io.ObjectInputStream s)
    throws java.io.IOException, ClassNotFoundException {
    elementData = EMPTY_ELEMENTDATA;
    // Read in size, and any hidden stuff
    s.defaultReadObject();
    // Read in capacity
    s.readInt(); // ignored
    if (size > 0) {
        // be like clone(), allocate array based upon size not capacity
        ensureCapacityInternal(size);
        Object[] a = elementData;
        // Read in all elements in the proper order.
        for (int i=0; i<size; i++) {
            a[i] = s.readObject();
        }
    }
}
2.ArrayList 和 Array
ArrayList: 动态数组链表存储对象类型不固定,为Object,如存 int 会自动装箱/拆箱成 Integer
Array: 高效,但长度无法改变只能存储相同类型对象
3.Vector 同步线程安全
1.接口 List RandomAccess, 也是一个动态数组存放数据
2.add() 使用 synchronized 进行了同步写数据,开销较大
// 添加元素 synchronized
public synchronized boolean add(E e) {
    modCount++;
    ensureCapacityHelper(elementCount + 1);
    elementData[elementCount++] = e;
    return true;
}
3.add(index, e) 指定位置添加
public void add(int index, E element) {
    insertElementAt(element, index);
}
// 插入元素 synchronized
public synchronized void insertElementAt(E obj, int index) {
    modCount++;
    if (index > elementCount) {
        throw new ArrayIndexOutOfBoundsException(index + " > " + elementCount);
    }
    ensureCapacityHelper(elementCount + 1);
    System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
    elementData[index] = obj;
    elementCount++;
}
4.自定义 ArrayList
实现 ArrayList 容量 底层 增删改查
boolean add(Object obj)
Object remove(int index)
Object set(int index, Object obj)
Object get(int index)
public class Node {
	private Object data;
	private Node next;
	public Node() {
		super();
	}
	public Node(Object data, Node next) {
		super();
		this.data = data;
		this.next = next;
	}
	public Object getData() {
		return data;
	}
	public void setData(Object data) {
		this.data = data;
	}
	public Node getNext() {
		return next;
	}
	public void setNext(Node next) {
		this.next = next;
	}
}
5.LinkedList 链表列表 / 链表双向队列
1.接口: List Deque
[Deque] 给定类型的元素进行线性处理 == 双向队列   
1.支持高效插入和删除容器的**头部元**   
2.能够快速地**随机访问**任一个元素
删除、插入效率高 O(1)
查询效率低 O(n/2)
2.底层基于双向链表 ==> jdk1.7/8 后取消了循环,修改为双向链表
- 谁能告诉我这是为啥呢? – 2020年12月8日

3.add() 添加到队列尾
public boolean add(E e) {
    linkLast(e);
    return true;
}
/**
 * Links e as last element.
 */
void linkLast(E e) {
    final Node<E> l = last;
    final Node<E> newNode = new Node<>(l, e, null);
    last = newNode;
    if (l == null)
        first = newNode;
    else
        l.next = newNode;
    size++;
    modCount++;
}
// 每次插入都是移动指针,和 ArrayList 的拷贝数组来说效率要高上不少 
// 时间复杂度 O(1)
4.get() 查询
public E get(int index) {
    checkElementIndex(index);
    return node(index).item;
}
Node<E> node(int index) {
    // assert isElementIndex(index);
    if (index < (size >> 1)) {
        Node<E> x = first;
        for (int i = 0; i < index; i++)
            x = x.next;
        return x;
    } else {
        Node<E> x = last;
        for (int i = size - 1; i > index; i--)
            x = x.prev;
        return x;
    }
}
// index 离头近从头遍历,反之亦然
// 时间复杂度 O(n/2) 获取一个节点,效率低
6.自定义LinkedList
自定义考虑哪些问题呢?
- ==> 考虑这些问题可以更深入的理解如何设计数据结构
- 参考如下案例,看案例对这些问题是如何回应的,然后可翻看LinkedList源码比对下
- 链表的头节点是不是单独的一个节点,其值为空其指向为下一个节点;
- 这个头节点我们可以放数据进去吗?
- 尾节点是指向最后一个节点的一个节点呢.
- 还是尾节点只是一个地址变量 这个地址变量的内容是最后一个链节的地址
- 又或者说头节点也是这样一个地址变量指向第一节点的物理内存
public class LinkedList2 {
	private Node head;
	private Node last;
	private int size;
	public LinkedList2(){
		head=new Node();
		last=head;
	}
	public boolean add(Object obj){
		if (head.getData()==null) {
			head.setData(obj);
		}else{
		Node newNode=new Node();
		newNode.setData(obj);
		last.setNext(newNode);
		last=newNode;
		}
		size++;
		return true;
	}
	public Object remove(int index){
		if (index==0) {
			head=head.getNext();
			return null;
		}
		Node before=head;
		for (int i = 0; i < index-1; i++) {
			before=before.getNext();
		}// 注意index;
		Node current=before.getNext();
		before.setNext(current.getNext());
		current.setNext(null);
		return current.getData();
	}
	public String toString(){
		StringBuffer sb=new StringBuffer();
		Node currentNode=head;
		sb.append("[");
		while (currentNode!=null) {
			sb.append(currentNode.getData()+" ");
			currentNode=currentNode.getNext();
		}
		sb.append("]");
		return sb.toString();
	}
}
public class Test {
	public static void main(String[] args) {
		day33.LinkedList2 ll=new day33.LinkedList2();
		ll.add("a");
		ll.add("b");
		ll.add("c");
		ll.add("d");
		ll.add("e");
		ll.add("f");
		System.out.println(ll);
	   ll.remove(2);
	   System.out.println(ll);
	}
}
SortedList 排序列表
- TODO 2020年12月8日 将来再研究
private Comparator<Element<E>> elementComparator;
private Element<E>[] sorted;
private int[] perm;
private int size;
private final SortHelper helper = new SortHelper();
private final Element<E> tempElement = new Element<>(null, -1);
public Element(E e, int index) {
	this.e = e;
	this.index = index;
}
参考:
文档信息
- 本文作者:jiushun.cheng
- 本文链接:https://minipa.github.io/2016/06/21/java-data/
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
