手寫JDK1.8前的LinkedList(頭節點非哨兵節點,雙向循環鏈表)

在這裏插入圖片描述
六種方法的實現:

package list;

import java.util.ArrayList;
import java.util.List;

/**
*@author  Edward
*@date  2020年6月30日---下午2:32:40
*/
public class LinkedList<E> {
	private Node head;
	private int size;
	
	class Node{
		E data;
		Node prev;
		Node next;
		Node(E e) {
			data=e;
		}
	}
	
	public boolean add(E e) {
		Node node = new Node(e);
		if (head==null) {
			head = node;
			head.next = head;
			head.prev = head;
			size++;
			return true;
		}
		Node last = head.prev;
		last.next = node;
		node.prev = last;
		head.prev = node;
		node.next = head;
		size++;
		return true;
	}
	
	public void add(int index,E e) {
		if (index<0||index>size) {
			throw new IndexOutOfBoundsException("下標越界啦");
		}
		Node node = new Node(e);
		if (head==null) {
			head=node;
			// 當head是唯一節點時,必須設置前後爲自己(其默認值均爲null),否則toString遍歷中會空指針
			head.next = head;
			head.prev = head;
			size++;
			return;
		}
		Node next = getNode(index);
		Node prev = next.prev;
		
		node.next = next;
		next.prev = node;
		prev.next = node;
		node.prev = prev;
		if (index == 0) {
			head = node;
		}
		size++;
		
	}
	
	public String toString() {
		if (head==null) {
			return "[]";
		}
		Node dummyHead = new Node(null);
		dummyHead.next = head;
		List<E>list = new ArrayList<E>();
		do {
			dummyHead = dummyHead.next;
			list.add(dummyHead.data);
		} while (dummyHead.next!=head);
		return list.toString();
		
	}
	
	public int size() {
		return size;
	}
	
	
	public E get(int index) {
		if (index<0||index>=size) {
			throw new IndexOutOfBoundsException("下標越界啦");
		}
		Node node = getNode(index);
		return node.data;
	}
	
	public E remove(int index) {
		if (index<0||index>=size) {
			throw new IndexOutOfBoundsException("下標越界啦");
		}
		// 這個雙向循環鏈表的很多操作是基於頭節點的,因此可能影響head的操作需要特殊處理
		// 邊界條件,如果整個鏈表只有一個節點,需設置頭節點爲null
		if (size==1) {
			E data = head.data;
			head = null;
			size--;
			return data;
		}
		Node node = getNode(index);
		node.prev.next = node.next;
		node.next.prev = node.prev;
		size--;
		// 邊界條件,如果刪除的是頭節點,需重新設置一個頭節點
		if (index==0) {
			head=node.next;
		}
		
		return node.data;
	}

	private Node getNode(int index) {
		Node node = head;
		if (index<size/2) {
			for (int i = 0; i < index; i++) {
				node = node.next;
			}
		}else {
			for (int i = size; i > index; i--) {
				node= node.prev;
			}
			
		}
		return node;
	}

}

在這裏插入圖片描述

需要注意的是,當改動涉及頭節點時,需要對特殊情況進行處理,如:添加節點時,頭節點爲唯一節點。這是因爲,頭節點的變動會間接影響其他方法的運行,且頭節點是未初始化的,如原先頭節點爲null,則需要先對頭節點進行初始化。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章