作爲Java程序員,紮實的數據結構算法能力是必須的
LinkedList理解的最好方式是,自己手動實現它
ArrayList和LinkedList是順序存儲結構和鏈式存儲結構的表在java語言中的實現.
ArrayList提供了一種可增長數組的實現,使用ArrayList,因爲內部使用數組實現,所以,它的優點是,對於get和set操作調用花費常數時間.缺點是插入元素和刪除元素會付出昂貴的代價.因爲這個操作會導致後面的元素都要發生變動,除非操作發生在集合的末端.
鑑於這個缺點,如果需要對錶結構的前端頻繁進行插入,刪除操作,那麼數組就不是一個好的實現,爲此就需要使用另一種結構,鏈表,而LinkedList就是基於一種雙鏈表的實現,使用它的優點就是,對於元素的插入,刪除操作開銷比較小,無論是在表的前端還是後端.但是缺點也顯而易見,對於get操作,它需要從表的一端一個一個的進行查找,因此對get的調用花費的代價也是很昂貴的.
理解這集合最好的方式就是自己去實現它,下面我們通過代碼來實現自己的LinkedList.
注意點:在學習數據結構的雙向鏈表,會學習頭結點和尾結點,加上頭結點和尾結點,操作其他結點可以保持同一個動作,但是在JDK實現雙向鏈表代碼中,沒有加頭結點和尾結點,下面看LinkedList實現的簡易版
public class LinkedList<E> implements Iterable<E> {
private int size;
private Node first;
private Node last;
//靜態內部類
private static class Node<E>{
private E data;
private Node prev;
private Node next;
public Node(E data, Node prev, Node next) {
super();
this.data = data;
this.prev = prev;
this.next = next;
}
}
//不添加頭結點和尾結點
public void add(int index,E e){
testIndex(index);
//根據index位置,選擇不同的方式添加結點
if(index == size){
lastNode(e);
}else
//使用node()方法,查找到當前index位置的node結點
beforeNode(node(index),e);
}
//根據索引,插入結點,參數node爲插入前,需要插入位置的node
private void beforeNode(Node<E> node, E e) {
final Node<E> pnode = node.prev;
final Node<E> nnode = node;
final Node<E> newNode = new Node<E>(e, pnode,nnode );
//爲插入的兩邊結點分別添加前後指針域
pnode.next = newNode;
nnode.prev = newNode;
size++;
}
//默認直接在鏈表尾部添加結點
public void add(E e){
this.add(size,e);
}
//根據索引值,在鏈表中查找到當前位置結點
private Node<E> node(int index) {
if(index<size>>1){
Node<E> node = first;
for(int i = 0;i<index;i++)
{
node = node.next;
}
return node;
}else{
Node<E> node = last;
for(int i= size-1;i>index;i--){
node = node.prev;
}
return node;
}
}
//在jdk源碼中,只有根據索引值來取值
public E get(int index){
Node<E> node = (Node) node(index);
return node.data;
}
//在雙向鏈表的最後添加元素,由於沒有頭結點和尾結點
private void lastNode( E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<E>(e,l,null);
last = newNode;
if(l == null){
first = newNode;
}else{
l.next = last;
}
size++;
}
private void testIndex(int index) {
//拋出運行時異常,是非檢查異常,所以不要trycatch,index >= 0 && index <= size;
if(!(index>=0&&index<=size)){
throw new ArrayOutOfBoundsException("位置信息初始化錯誤,大於size");
}
}
public int size(){
return size;
}
public boolean isEmpty(){
return size == 0;
}
@Override
public Iterator<E> iterator() {
return new ListIterator();
}
//使用內部類,編寫遍歷集合邏輯
public class ListIterator implements Iterator<E>{
private Node<E> node = first;
@Override
public boolean hasNext() {
// node = node.next;
return node != null;
}
@Override
public E next() {
E val = node.data;
node = node.next;
return val;
}
}
}
下面是測試自己手寫LinkedList代碼
public class TestLinkedList {
public static void main(String[] args) {
LinkedList<Integer> list = new LinkedList<>();
// System.out.println(list.size());
list.add(111);
list.add(1554);
list.add(333);
list.add(88888);
list.add(262511);
System.out.println(list.size());
Integer ai = list.get(2);
System.out.println(ai);
list.add(1, 66669);
// System.out.println(list.size());
System.out.println(list.get(1));
Iterator<Integer> it = list.iterator();
while(it.hasNext()){
System.out.print(it.next()+" ");
}
}
}
測試結果
個人理解:理解源碼和數據結構的最好方式,單步調試初步理解,自己重新手寫