1. 程式人生 > >Java語言實現雙鏈表

Java語言實現雙鏈表

java語言實現雙鏈表其實很簡單,雙鏈表的基本操作有:增、刪、改、差、取得指定節點的內容、判空、節點個數、清除、輸出。
相對比較難一點的是連結串列的刪除,這裡說明一下具體的實現刪除可以在外部寫一個刪除的方法,此處用的方法非常容易理解,不
用像以前那樣考慮是否為頭結點、是否為空等等,只需要兩步操作即可。具體操作在程式碼中展示:

程式碼實現如下:
interface ILink {
	void add(Object obj); // 增

	boolean remove(Object obj); // 刪

	Object set(int index, Object newData); // 替換

	Object get(int index); // 取得指定節點的內容

	int contains(Object data); // 判斷節點內容是否存在

	int size(); // 節點個數

	void clear(); // 清除

	Object[] toArray(); // 將連結串列轉化為陣列

	void printLink(); // 輸出
}

class LinkImpl implements ILink {
	private Node head; // 設定頭結點
	private Node last; // 設定尾節點
	private int size; // 設定節點個數

	private class Node { // 通過內部類設定節點
		private Node pre; // 前指標
		private Node next; // 後指標
		private Object data; // 節點資料

		public Node(Node pre, Node next, Object data) {
			this.pre = pre;
			this.next = next;
			this.data = data;
		}
	}

	@Override
	public void add(Object obj) { // 採用尾插的方式
		Node temp = this.last; // 儲存當前連結串列的尾節點
		Node newNode = new Node(temp, null, obj); // 設定新節點
		this.last = newNode; // 因為是尾插的方式,先讓連結串列的尾節點指向新節點
		if (this.head == null) { // 如果連結串列為空,直接插入
			this.head = newNode;
		} else {
			temp.next = newNode; // 如果連結串列不為空,讓當前連結串列的尾節點指向新節點
		}
		this.size++; // 插入節點完成,節點個數++
	}

	@Override
	public boolean remove(Object obj) {
		if (obj == null) { // 若要刪除的節點為空節點
			for (Node temp = head; temp != null; temp = temp.next) {
				if (temp.data == null) { // 找到空節點
					unLink(temp); // 刪除
					return true;
				}
			}
		} else { // 要刪除節點不為空
			for (Node temp = head; temp != null; temp = temp.next) {
				if (obj.equals(temp.data)) { // 找到該節點
					unLink(temp); // 刪除該節點
					return true;
				}
			}
		}
		return false;
	}

	@Override
	public Object set(int index, Object newData) {
		if (!isLinkIndex(index)) { // 判斷該節點是否存在
			return null;
		}
		Object result = node(index).data; // 儲存該節點的data
		node(index).data = newData; // 設定新的data
		return result; // 返回
	}

	@Override
	public Object get(int index) {
		if (!isLinkIndex(index)) { // 判斷該節點是否存在
			return null;
		}
		return node(index).data; // 返回該下標的節點
	}

	@Override
	public int contains(Object data) {
		int i = 0;
		if (data == null) { // 若要查詢節點為空節點
			for (Node temp = head; temp != null; temp = temp.next) {
				if (temp.data == null) {
					return i;
				}
				i++;
			}
		} else { // 若要查詢節點不為空節點
			for (Node temp = head; temp != null; temp = temp.next) {
				if (data.equals(temp.data)) {
					return i;
				}
				i++;
			}
		}
		return -1; // 找不到返回-1
	}

	@Override
	public int size() {
		return this.size;
	}

	@Override
	public void clear() {
		for (Node temp = head; temp != null;) {
			Node flag = temp.next;
			temp.pre = temp = temp.next = null;
			temp = flag;
			this.size--;
		}
	}

	@Override
	public Object[] toArray() {
		Object[] result = new Object[this.size];
		int i = 0;
		for (Node temp = head; temp != null; temp = temp.next) {
			result[i++] = temp.data;
		}
		return result;
	}

	@Override
	public void printLink() {
		Object[] data = this.toArray();
		for (Object temp : data) {
			System.out.println(temp);
		}
	}

	// ==========================
	// 根據下標返回節點
	private Node node(int index) {
		if (index < (this.size >> 1)) { // 小於中間節點下標,從前往後找
			Node temp = head;
			for (int i = 0; i < index; i++) {
				temp = temp.next;
			}
			return temp;
		} else {
			Node temp = this.last;
			for (int i = this.size - 1; i > index; i--) {
				temp = temp.pre;
			}
			return temp;
		}
	}

	// 判斷傳入結點的下標是否存在
	private boolean isLinkIndex(int index) {
		return index >= 0 && index < this.size;
	}

	// 刪除節點
	private void unLink(Node node) {
		Node nodePre = node.pre; // 儲存要刪除節點的前一個節點
		Node nodeNext = node.next; // 儲存要刪除節點的下一個節點
		// 先判斷前指標(pre指標域)
		if (node.pre == null) { // 如果要刪除節點為頭結點
			this.head = nodeNext; // 當前頭結點指向該節點下一個節點
		} else {
			nodePre.next = nodeNext; // 前一個節點的next域指向該節點的next
			node.pre = null; // 釋放該節點的前指標域(pre)
		}
		// 再判斷後指標(next指標域)
		if (node.next == null) { // 如果要刪除的節點為尾節點
			this.last = nodePre; // 當前的尾節點指向該節點的前一個節點
		} else {
			nodeNext.pre = nodePre; // 下一個節點的pre域指向該節點的pre
			node.next = null; // 釋放該節點的後指標域(next)
		}
		node.data = null; // 釋放該節點的值域(data)
		this.size--; // 節點個數減1
	}
}

 

程式碼檢測:

1、插入的檢測(採用尾插):

程式碼:

public class Test{
    public static void main(String[] args) {
        ILink link = new LinkImpl();
        link.add("頭結點");
        link.add("節點1");
        link.add("節點2");
        link.add("節點3");
        link.add("尾節點");
        link.printLink();

    }
}

執行結果:

 

2、刪除操作的檢測:(如果刪除成功返回true,失敗返回false)

程式碼:

public class Test{
    public static void main(String[] args) {
        ILink link = new LinkImpl();
        link.add("頭結點");
        link.add("節點1");
        link.add("節點2");
        link.add("節點3");
        link.add("尾節點");

        link.remove("節點2"); // 刪除節點2
        System.out.println(link.remove("節點6")); // 刪除一個不存在的節點-->會返回false

        link.printLink();

    }
}

 

執行結果:

 

3、替換(根據指定位置替換)

程式碼:

public class Test{
    public static void main(String[] args) {
        ILink link = new LinkImpl();
        link.add("頭結點");
        link.add("節點1");
        link.add("節點2");
        link.add("節點3");
        link.add("尾節點");

        link.set(2,"Hello World!!!"); // 把下標為2的節點改為Hello World

        link.printLink();

    }
}

執行結果:

 

4、 查詢(根據下標查詢該節點的值)

程式碼:

public class Test{
    public static void main(String[] args) {
        ILink link = new LinkImpl();
        link.add("頭結點");
        link.add("節點1");
        link.add("節點2");
        link.add("節點3");
        link.add("尾節點");

        System.out.println(link.get(2)); // 查詢下標為2的節點的值
        
    }
}

 

執行結果:

5、判斷連結串列中該節點是否存在(存在,返回該節點的值,不存在,返回null)

public class Test{
    public static void main(String[] args) {
        ILink link = new LinkImpl();
        link.add("頭結點");
        link.add("節點1");
        link.add("節點2");
        link.add("節點3");
        link.add("尾節點");

        System.out.println(link.get(2)); // 查詢下標為2的節點的值
        System.out.println(link.get(5)); // 查詢一個不存在的節點

    }
}

執行結果:

 

6、輸出節點的個數(清除節點後輸節點的個數)

程式碼:

public class Test {
    public static void main(String[] args) {
        ILink link = new LinkImpl();
        link.add("頭結點");
        link.add("節點1");
        link.add("節點2");
        link.add("節點3");
        link.add("尾節點");
        link.printLink();
        
        System.out.println("==========================");
        System.out.println("未清除之前節點個數為:" + link.size());
        System.out.println("==========================");
        link.clear();
        System.out.println("清除後節點個數為:" + link.size());

    }
}

執行結果: