實現自定義的 LinkedList


1.實現思路:通過雙鏈表來實現,并且保留該表兩端的引用。

2.實現設計:


a. MyLinkedList類:包含到兩端的鏈,表的大小以及一些方法。
b. Node類:一個節點包含數據以及前一個節點的鏈和下一個節點的鏈,以及其構造方法。
c. LinkedListIterator類:實現接口Iterator,提供next,hasNext,remove方法的實現。


3. 具體實現過程---Coding:


a. 實現Node類:

//定義節點,類型為AnyType
    private static class Node<AnyType>{
        //通過構造函數,創建一個節點
        public Node(AnyType d, Node<AnyType> p, Node<AnyType> n){
            data = d;
            prev = p;
            next = n;
        }
        //當前結點數據
        public AnyType data;
        //向前驅點
        public Node<AnyType> prev;
        //向后驅點
        public Node<AnyType> next;
    }

b. 定義一些常量:

public class MyLinkedList<Object> implements Iterable<Object> {
    //定義當前長度
    private int theSize;
    //定義操作次數,增加,刪除等影響結構的操作
    private int modCount = 0;
    //定義開始標記
    private Node<Object> beginMarker;
    //定義結束標記
    private Node<Object> endMarker;
}

c.構造函數以及初始化操作:

//創建時,清空所有之前的數據
    public MyLinkedList(){
        doClear();
    }

    //清空操作
    public void clear(){
        doClear();
    }

    //實現具體的清空操作
    public void doClear() {
        //定義開始節點
        beginMarker = new Node<Object>(null,null,null);
        //定義結束節點,注意這里將開始節點作為結束節點的向前節點
        endMarker = new Node<Object>(null, beginMarker, null);
        //將結束節點作為開始節點的向后節點
        beginMarker.next = endMarker;
        //初始化大小為0
        theSize = 0;
        //操作加1
        modCount ++;
    }

    //返回當前長度
    public int size(){
        return theSize;
    }

    //判斷當前鏈表是否為空
    public boolean isEmpty(){
        return theSize == 0;
    }

d. get操作,獲取到節點以及節點數據等

    /**
     * 根據鏈表位置獲取到對應的數據:通過調用getNode方法獲取到當前結點,
     * 再獲取到當前結點的數據
     * @param idx 傳入的位置
     * @return
     */
    public Object get(int idx){
        return getNode(idx).data;
    }

    /**
     * 獲取到對應位置的節點:調用具體的getNode方法去獲取
     * @param idx
     * @return
     */
    private Node<Object> getNode(int idx){
        return getNode(idx, 0 , size());
    }

    /**
     * 實現根據位置獲取到節點
     * @param idx 當前位置
     * @param lower 開始位置
     * @param upper 結束位置
     * @return
     */
    private Node<Object> getNode(int idx, int lower, int upper){
        //定義一個臨時節點
        Node<Object> p;
        //若傳入的位置超出范圍,則拋出異常
        if (idx < lower || idx > upper)
            throw new IndexOutOfBoundsException();
        //若當前位置在左邊,則從開始出進行向后遍歷
        if (idx < size() / 2){
            //移動到開始處
            p = beginMarker;
            //遍歷直到到達所要求的位置
            for (int i = 0; i < idx; i ++){
                p = p.next;
            }
        }
        //若當前位置在右邊,則從尾部開始進行向前遍歷
        else {
            p = endMarker;
            for (int i = size(); i > idx; i --){
                p = p.prev;
            }
        }
        return p;
    }

e. set操作,用于更新節點數據:

    /**
     * 更新數據操作
     * @param idx 傳入的鏈表位置
     * @param newVal 更新的數據
     * @return
     */
    public Object set(int idx, Object newVal){
        //獲取到對應位置的節點
        Node<Object> p = getNode(idx);
        //獲取到當前數據
        Object oldVal = p.data;
        p.data = newVal;
        //返回原來的數據
        return oldVal;
    }

f. 添加操作:主要理解addBefore操作

    /**
     * 實現默認方式添加元素
     * @param x
     * @return
     */
    public boolean add(Object x){
        //調用add方法,添加到尾部
        add(size(), x);
        return true;
    }

    /**
     * 實現添加到具體的某個位置中
     * @param idx
     * @param x
     */
    public void add(int idx, Object x) {
        addBefore(getNode(idx), x);
    }

    /**
     * 實現具體的添加操作
     * @param p 當前位置的節點
     * @param x 節點數據
     */
    private void addBefore(Node<Object> p , Object x){
        //根據p節點創建一個新的節點
        Node<Object> newNode = new Node<Object>(x, p.prev, p);
        //連接新節點與前后兩個節點
        newNode.prev.next = newNode;
        p.prev = newNode;
        //長度和操作次數++
        theSize ++;
        modCount ++;
    }

添加操作示意圖:

add_node
 //實際上,通過構造函數,便完成了示意圖中的1和2操作
 Node<Object> newNode = new Node<Object>(x, p.prev, p);
 //實現了操作3
 newNode.prev.next = newNode;
 //實現了操作4
 p.prev = newNode;

g. 實現刪除節點操作:

    /**
     * 實現移除某個位置的節點
     * @param idx
     * @return
     */
    public Object remove(int idx){
        return remove(getNode(idx));
    }

    /**
     * 具體移除節點操作
     * @param p 傳入要移除的節點
     * @return
     */
    private Object remove(Node<Object> p){
        //移除當前節點
        p.next.prev = p.prev;
        p.prev.next = p.next;
        //長度--
        theSize --;
        //操作次數++
        modCount ++;
        //返回移除節點的數據
        return p.data;
    }

刪除示意圖:

delete_node.png

h. 實現查找元素位置操作:

/**
     * 實現查找鏈表中首先出現的元素位置
     * @param x
     * @return
     */
    public int indexOf(Object x){
        int index = 0;
        //若傳入的數據為空
        if (x == null){
            //遍歷鏈表,查找是否含有數據為null的節點,找到后立即返回當前位置
            for (Node<Object> node = beginMarker.next; node != endMarker; node = node.next){
                if (node.data == null){
                    return index;
                }
                index ++;
            }
        }
        //數據不為空時,使用equals方法進行比較
        else {
            for (Node<Object> node = beginMarker.next; node != endMarker; node = node.next){
                if (x.equals(node.data)){
                    return index;
                }
                index ++;
            }
        }
        return -1;
    }

    /**
     * 實現查找鏈表中元素最后出現的位置
     * 從尾節點開始向前遍歷搜查
     * @param x
     * @return
     */
    public int lastIndexOf(Object x){
        int index = size() - 1;
        if (x == null){
            for (Node<Object> node = endMarker.prev; node != beginMarker; node = node.prev){
                if (node.data == null){
                    return index;
                }
                index --;
            }
        } else {
            for (Node<Object> node = endMarker.prev; node != beginMarker; node = node.prev){
                if (x.equals(node.data)){
                    return index;
                }
                index --;
            }
        }
        return -1;
    }

i. 實現LinkedListIterator類:

private class LinkedListIterator implements Iterator<Object>{
        //定義當前結點為始節點的下一個節點
        private Node<Object> current = beginMarker.next;
        //定義操作次數
        private int expectedModCount = modCount;
        //判斷是否可以進行刪除
        private boolean okToRemove = false;

        //判斷是否存在下一個節點
        @Override
        public boolean hasNext() {
            return current != endMarker;
        }

        //獲取到下一個節點數據
        @Override
        public Object next() {
            //操作次數不一致拋出異常
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            //不存在下一個節點,拋出異常
            if (!hasNext())
                throw new NoSuchElementException();
            //獲取到下一個節點的數據,并設置okToRemove為true,表示可以進行刪除
            Object nextItem = current.data;
            current = current.next;
            okToRemove = true;
            return nextItem;
        }

        //進行刪除操作
        public void remove(){
            //操作次數不一致,拋出異常
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            //無法進行刪除操作,必須先進行next,才可以進行remove操作
            if (!okToRemove)
                throw new IllegalStateException();
            //調用鏈表中的remove方法進行刪除操作,注意傳入的是current.pre節點
            MyLinkedList.this.remove(current.prev);
            //操作次數++
            expectedModCount ++;
            okToRemove = false;
        }
    }

完整代碼如下:

/**
 * Created by Administrator on 2017/3/5/005.
 * 實現自定義LinkedList
 */
public class MyLinkedList<Object> implements Iterable<Object> {
    //定義當前長度
    private int theSize;
    //定義操作次數,增加,刪除等影響結構的操作
    private int modCount = 0;
    //定義開始標記
    private Node<Object> beginMarker;
    //定義結束標記
    private Node<Object> endMarker;

    //定義節點,類型為AnyType
    private static class Node<AnyType>{
        //通過構造函數,創建一個節點
        public Node(AnyType d, Node<AnyType> p, Node<AnyType> n){
            data = d;
            prev = p;
            next = n;
        }
        //當前結點數據
        public AnyType data;
        //向前驅點
        public Node<AnyType> prev;
        //向后驅點
        public Node<AnyType> next;
    }

    //創建時,清空所有之前的數據
    public MyLinkedList(){
        doClear();
    }

    //清空操作
    public void clear(){
        doClear();
    }

    //實現具體的清空操作
    public void doClear() {
        //定義開始節點
        beginMarker = new Node<Object>(null,null,null);
        //定義結束節點,注意這里將開始節點作為結束節點的向前節點
        endMarker = new Node<Object>(null, beginMarker, null);
        //將結束節點作為開始節點的向后節點
        beginMarker.next = endMarker;
        //初始化大小為0
        theSize = 0;
        //操作加1
        modCount ++;
    }

    //返回當前長度
    public int size(){
        return theSize;
    }

    //判斷當前鏈表是否為空
    public boolean isEmpty(){
        return theSize == 0;
    }

    /**
     * 根據鏈表位置獲取到對應的數據:通過調用getNode方法獲取到當前結點,
     * 再獲取到當前結點的數據
     * @param idx 傳入的位置
     * @return
     */
    public Object get(int idx){
        return getNode(idx).data;
    }

    /**
     * 更新數據操作
     * @param idx 傳入的鏈表位置
     * @param newVal 更新的數據
     * @return
     */
    public Object set(int idx, Object newVal){
        //獲取到對應位置的節點
        Node<Object> p = getNode(idx);
        //獲取到當前數據
        Object oldVal = p.data;
        p.data = newVal;
        //返回原來的數據
        return oldVal;
    }

    /**
     * 獲取到對應位置的節點:調用具體的getNode方法去獲取
     * @param idx
     * @return
     */
    private Node<Object> getNode(int idx){
        return getNode(idx, 0 , size());
    }

    /**
     * 實現根據位置獲取到節點
     * @param idx 當前位置
     * @param lower 開始位置
     * @param upper 結束位置
     * @return
     */
    private Node<Object> getNode(int idx, int lower, int upper){
        //定義一個臨時節點
        Node<Object> p;
        //若傳入的位置超出范圍,則拋出異常
        if (idx < lower || idx > upper)
            throw new IndexOutOfBoundsException();
        //若當前位置在左邊,則從開始出進行向后遍歷
        if (idx < size() / 2){
            //移動到開始處
            p = beginMarker;
            //遍歷直到到達所要求的位置
            for (int i = 0; i < idx; i ++){
                p = p.next;
            }
        }
        //若當前位置在右邊,則從尾部開始進行向前遍歷
        else {
            p = endMarker;
            for (int i = size(); i > idx; i --){
                p = p.prev;
            }
        }
        return p;
    }

    /**
     * 實現默認方式添加元素
     * @param x
     * @return
     */
    public boolean add(Object x){
        //調用add方法,添加到尾部
        add(size(), x);
        return true;
    }

    /**
     * 實現添加到具體的某個位置中
     * @param idx
     * @param x
     */
    public void add(int idx, Object x) {
        addBefore(getNode(idx), x);
    }

    /**
     * 實現具體的添加操作
     * @param p 當前位置的節點
     * @param x 節點數據
     */
    private void addBefore(Node<Object> p , Object x){
        //實際上,通過構造函數,便完成了示意圖中的1和2操作
        Node<Object> newNode = new Node<Object>(x, p.prev, p);
        //實現了操作3
        newNode.prev.next = newNode;
        //實現了操作4
        p.prev = newNode;
        //長度和操作次數++
        theSize ++;
        modCount ++;
    }

    /**
     * 實現移除某個位置的節點
     * @param idx
     * @return
     */
    public Object remove(int idx){
        return remove(getNode(idx));
    }

    /**
     * 具體移除節點操作
     * @param p 傳入要移除的節點
     * @return
     */
    private Object remove(Node<Object> p){
        //移除當前節點
        p.next.prev = p.prev;
        p.prev.next = p.next;
        //長度--
        theSize --;
        //操作次數++
        modCount ++;
        //返回移除節點的數據
        return p.data;
    }

    /**
     * 獲取到第一個節點數據
     * @return
     */
    public Object getFirst(){
        //先判斷鏈表是否為空,為空則拋出異常
        if (isEmpty()){
            throw new NoSuchElementException();
        }
        return beginMarker.next.data;
    }

    //獲取到鏈表中的最后一個節點數據
    public Object getLast(){
        if (isEmpty()){
            throw new NoSuchElementException();
        }
        return endMarker.prev.data;
    }

    //移除鏈表中第一個節點
    public Object removeFirst(){
        if (isEmpty()){
            throw new NoSuchElementException();
        }
        //調用remove方法,移除開始節點的下一個節點即可
        return remove(beginMarker.next);
    }

    //移除鏈表中的最后一個節點
    public Object removeLast(){
        if (isEmpty()){
            throw new NoSuchElementException();
        }
        //調用remove方法,移除結束節點的上一個節點即可
        return remove(endMarker.prev);
    }

    //從頭部開始添加節點
    public void addFirst(Object x){
        //將添加節點設置為頭節點即可
        addBefore(beginMarker.next, x);
    }

    //從尾部添加節點
    public void addLast(Object x){
        add(x);
    }

    //添加一個Collection集合
    public void addAll(Collection<Object> collection){
        //添加集合為空,則拋出異常
        if (collection == null){
            throw new NullPointerException();
        }
        //遍歷集合,并逐個添加到鏈表中
        for (Object aCollection : collection) {
            add(aCollection);
        }
    }

    //判斷鏈表中是否含有某個元素,調用indexOf方法即可
    public boolean contains(Object x){
        return indexOf(x) != -1;
    }

    /**
     * 實現查找鏈表中首先出現的元素位置
     * @param x
     * @return
     */
    public int indexOf(Object x){
        int index = 0;
        //若傳入的數據為空
        if (x == null){
            //遍歷鏈表,查找是否含有數據為null的節點,找到后立即返回當前位置
            for (Node<Object> node = beginMarker.next; node != endMarker; node = node.next){
                if (node.data == null){
                    return index;
                }
                index ++;
            }
        }
        //數據不為空時,使用equals方法進行比較
        else {
            for (Node<Object> node = beginMarker.next; node != endMarker; node = node.next){
                if (x.equals(node.data)){
                    return index;
                }
                index ++;
            }
        }
        return -1;
    }

    /**
     * 實現查找鏈表中元素最后出現的位置
     * 從尾節點開始向前遍歷搜查
     * @param x
     * @return
     */
    public int lastIndexOf(Object x){
        int index = size() - 1;
        if (x == null){
            for (Node<Object> node = endMarker.prev; node != beginMarker; node = node.prev){
                if (node.data == null){
                    return index;
                }
                index --;
            }
        } else {
            for (Node<Object> node = endMarker.prev; node != beginMarker; node = node.prev){
                if (x.equals(node.data)){
                    return index;
                }
                index --;
            }
        }
        return -1;
    }

    /**
     * 實現鏈表的遍歷
     * @return
     */
    public Iterator<Object> iterator(){
        return new LinkedListIterator();
    }

    private class LinkedListIterator implements Iterator<Object>{
        //定義當前結點為始節點的下一個節點
        private Node<Object> current = beginMarker.next;
        //定義操作次數
        private int expectedModCount = modCount;
        //判斷是否可以進行刪除
        private boolean okToRemove = false;

        //判斷是否存在下一個節點
        @Override
        public boolean hasNext() {
            return current != endMarker;
        }

        //獲取到下一個節點數據
        @Override
        public Object next() {
            //操作次數不一致拋出異常
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            //不存在下一個節點,拋出異常
            if (!hasNext())
                throw new NoSuchElementException();
            //獲取到下一個節點的數據,并設置okToRemove為true,表示可以進行刪除
            Object nextItem = current.data;
            current = current.next;
            okToRemove = true;
            return nextItem;
        }

        //進行刪除操作
        public void remove(){
            //操作次數不一致,拋出異常
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            //無法進行刪除操作,必須先進行next,才可以進行remove操作
            if (!okToRemove)
                throw new IllegalStateException();
            //調用鏈表中的remove方法進行刪除操作,注意傳入的是current.pre節點
            MyLinkedList.this.remove(current.prev);
            //操作次數++
            expectedModCount ++;
            okToRemove = false;
        }
    }
}

測試代碼:

public class LinkedListTest {

    public static void main(String[] args){
        //進行添加操作
        MyLinkedList<String> myLinkedList = new MyLinkedList<>();
        myLinkedList.add("Java");
        myLinkedList.add("C++");
        myLinkedList.add("Python");
        myLinkedList.add(2, "PHP");
        //遍歷結果
        printLinkedList(myLinkedList.iterator());

        //進行刪除和更新操作
        myLinkedList.remove(2);
        myLinkedList.set(1,"JavaScript");
        printLinkedList(myLinkedList.iterator());

        //獲取到首尾元素
        System.out.println("first data : " + myLinkedList.getFirst());
        System.out.println("last data : " + myLinkedList.getLast());

        //移除首尾節點
        myLinkedList.removeFirst();
        myLinkedList.removeLast();
        printLinkedList(myLinkedList.iterator());

        //分別從首尾部添加
        myLinkedList.addFirst("C#");
        myLinkedList.addLast("CSS");
        printLinkedList(myLinkedList.iterator());

        //清空操作
        myLinkedList.clear();
        printLinkedList(myLinkedList.iterator());

        //addAll方法
        List<String> list = new ArrayList<>();
        list.add("JAVA");
        list.add("C++");
        list.add("C");
        list.add("JavaScript");
        list.add("C");
        list.add("HTML");
        myLinkedList.addAll(list);
        printLinkedList(myLinkedList.iterator());

        //查找元素
        System.out.println("是否存在CSS教程: " + myLinkedList.contains("CSS"));
        System.out.println("是否存在HTML教程: " + myLinkedList.contains("HTML"));
        System.out.println("C教程開始的位置為: " + myLinkedList.indexOf("C"));
        System.out.println("C教程最后的位置為: " + myLinkedList.lastIndexOf("C"));
    }

    private static void printLinkedList(Iterator<String> iterator){
        System.out.print("當前鏈表為: ");
        while (iterator.hasNext()){
            System.out.print(iterator.next() + " ");
        }
        System.out.println();
    }
}

輸出結果:

當前鏈表為: Java C++ PHP Python 
當前鏈表為: Java JavaScript Python 
first data : Java
last data : Python
當前鏈表為: JavaScript 
當前鏈表為: C# JavaScript CSS 
當前鏈表為: 
當前鏈表為: JAVA C++ C JavaScript C HTML 
是否存在CSS教程: false
是否存在HTML教程: true
C教程開始的位置為: 2
C教程最后的位置為: 4
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容