1. 程式人生 > >資料結構(java)——單鏈表、雙端連結串列和雙向連結串列

資料結構(java)——單鏈表、雙端連結串列和雙向連結串列

單鏈表

    連結串列大家都很熟悉,連結串列是由若干個節點串起來的一個結構。類似於火車一樣,擁有一個頭結點(火車頭)之後掛著一個個的節點,每個節點後面跟上另一個節點。每個節點分為兩個域,一個數據域,用來存放這個節點的資料,一個是節點域,用來存放下一個節點。

    所以對於單鏈表,用java實現我們首先建立節點類。

Node類:

//聯結點,相當於是車廂
public class Node {
	//資料域
	public long data;
	//節點域
	public Node next;
	
	//預設構造方法
	public Node(long value) {
		this.data = value;
	}
	
	//顯示方法
	public void display() {
		System.out.print(data + " ");
	}
}

再實現一些連結串列的基本操作。

LinkList類:

//連結串列,相當於火車
public class LinkList {
	//車頭,頭結點
	private Node first;
	
	public LinkList() {
		first = null;
	}
	
	//插入節點,在頭結點之後插入
	public void insertFirst(long value) {
		Node aNode = new Node(value);
		aNode.next = first;
		first = aNode;
	}
	
	//刪除頭節點
	public Node deleteFirst() {
		Node tmp = first.next;
		first = tmp;
		return tmp;
	}
	
	
	//顯示方法
	public void display() {
		Node now = first;
		while(now != null) {
			now.display();
			now = now.next;
		}
		System.out.println();
	}
	
	//查詢方法
	public Node find(long value) {
		Node now = first;
		while(now.data != value) {
			if(now.next == null) {
				return null;
			}
			now = now.next;
		}
		return now;
	}
	
	//根據數值刪除
	public Node delete(long value) {
		Node now = first;
		Node before = first;
		while(now.data != value) {
			if(now.next == null) {
				return null;
			}
			before = now;
			now = now.next;
		}
		
		if(now == first) {
			first = first.next;
		}
		else {
			before.next = now.next;
		}
		return now;
	}
}

對上面一些基礎的方法測試:

public class Test {

	public static void main(String[] args) {


		LinkList ll = new LinkList();
		ll.insertFirst(1);
		ll.insertFirst(2);
		ll.insertFirst(3);
		ll.insertFirst(4);
		ll.insertFirst(5);
		
		ll.display();
//		
//		ll.deleteFirst();
//		ll.display();
		
//		ll.find(2).display();
		
//		Node node = ll.delete(2);
//		ll.display();
	}
}

雙端連結串列

雙端連結串列相比於單鏈表,其實就是加入了一個尾節點來標識表尾

Node類:

//聯結點,相當於是車廂
public class Node {
	
	//資料域
	public long data;
	//節點域(後)
	public Node next;
	
	//預設構造方法
	public Node(long value) {
		this.data = value;
	}
	
	//顯示方法
	public void display() {
		System.out.print(data + " ");
	}
}

相比於單鏈表,雙端連結串列在插入和刪除等操作時進行了一點小的修改,體現在吧last移動的處理上

FirstLastLinkList類:

//雙端連結串列
public class FirstLastLinkList {
	//車頭,頭結點
	private Node first;
	//尾節點
	private Node last;
	
	public FirstLastLinkList() {
		first = null;
		last = null;
	}
	
	//插入節點,在頭結點之後插入
	public void insertFirst(long value) {
		Node aNode = new Node(value);
		if (isEmpty()) {
			last = aNode;
		}
		aNode.next = first;
		first = aNode;
	}
	
	//尾節點插入
	public void insertLast(long value) {
		Node aNode = new Node(value);
		if (isEmpty()) {
			first = aNode;
		}
		else {
			last.next = aNode;
		}
		last = aNode;
	}
	
	//刪除頭節點
	public Node deleteFirst() {
		Node tmp = first;
		if (first.next == null) {
			last = null;
		}
		first = tmp.next;
		return tmp;
	}
	
	//顯示方法
	public void display() {
		Node now = first;
		while(now != null) {
			now.display();
			now = now.next;
		}
		System.out.println();
	}
	
	//查詢方法
	public Node find(long value) {
		Node now = first;
		while(now.data != value) {
			if(now.next == null) {
				return null;
			}
			now = now.next;
		}
		return now;
	}
	
	//根據數值刪除
	public Node delete(long value) {
		Node now = first;
		Node before = first;
		while(now.data != value) {
			if(now.next == null) {
				return null;
			}
			before = now;
			now = now.next;
		}
		
		if(now == first) {
			first = first.next;
		}
		else {
			before.next = now.next;
		}
		return now;
	}
	
	//判斷是否為空
	public boolean isEmpty() {
		return first == null;
	}
}

針對雙端連結串列的一點測試(大家可以自己使用測測):

public class Test {

	public static void main(String[] args) {
		// TODO 自動生成的方法存根
		FirstLastLinkList f1 = new FirstLastLinkList();
//		f1.insertFirst(34);
//		f1.insertFirst(56);
//		f1.insertFirst(67);
//		f1.display();
//		
//		f1.deleteFirst();
//		f1.deleteFirst();
//		f1.display();
		
		f1.insertLast(56);
		f1.insertLast(90);
		f1.insertLast(12);
		f1.display();
		
//		f1.delete(12);
//		f1.display();
		while (!f1.isEmpty()) {
			f1.deleteFirst();
			f1.display();
		}
	}
}

雙向連結串列

為了解決尾刪這個問題,引入雙向連結串列,在單鏈表和雙端連結串列中,如果要進行尾部刪除,就要吧表遍歷一遍,耗時間耗空間。雙向連結串列的每個節點分為3個域,一個數據域,另外兩個節點域,既儲存前面的節點的資訊也儲存後面的節點的資訊。可以理解為有2個指標,既有next後指標,又有previous前指標。

Node類:

//聯結點,相當於是車廂
public class Node {
	
	//資料域
	public long data;
	//節點域(後)
	public Node next;
	//節點域(前)
	public Node previous;
	
	//預設構造方法
	public Node(long value) {
		this.data = value;
	}
	
	//顯示方法
	public void display() {
		System.out.print(data + " ");
	}
}

DoubleLinkList類:

//雙向連結串列

public class DoubleLinkList {
	//車頭,頭結點
	private Node first;
	//尾節點
	private Node last;
	
	public DoubleLinkList() {
		first = null;
		last = null;
	}
	
	//插入節點,在頭結點之後插入
	public void insertFirst(long value) {
		Node aNode = new Node(value);
		
		//為空,設定尾節點為新增加的節點
		if (isEmpty()) {
			last = aNode;
		}
		//連結串列不為空的時候,把插入前第一個節點的previous指向新節點
		else {
			first.previous = aNode;
		}
		aNode.next = first;
		first = aNode;
	}
	
	//尾節點插入
	public void insertLast(long value) {
		Node aNode = new Node(value);
		if (isEmpty()) {
			first = aNode;
		}
		else {
			last.next = aNode;
			aNode.previous = last;
		}
		last = aNode;
	}
	
	//刪除頭節點
	public Node deleteFirst() {
		Node tmp = first;
		if (first.next == null) {
			last = null;
		}
		else {
			//這裡因為存在雙指標,所以需要吧後面節點的指向前面節點的那個指標置空
			first.next.previous = null;
		}
		first = tmp.next;
		return tmp;
	}
	
	//刪除尾節點
	public Node deleteLast() {
		Node tmp = last;
		if (first.next == null) {
			first = null;
		}
		else {
			//意思同上
			last.previous.next = null;
		}
		last = last.previous;
		return last;
	}
	
	//顯示方法
	public void display() {
		Node now = first;
		while(now != null) {
			now.display();
			now = now.next;
		}
		System.out.println();
	}
	
	//查詢方法
	public Node find(long value) {
		Node now = first;
		while(now.data != value) {
			if(now.next == null) {
				return null;
			}
			now = now.next;
		}
		return now;
	}
	
	//根據數值刪除
	public Node delete(long value) {
		Node now = first;
		while(now.data != value) {
			if(now.next == null) {
				return null;
			}
			now = now.next;
		}
		
		if(now == first) {
			first = first.next;
		}
		else {
			now.previous.next = now.next;
		}
		return now;
	}
	
	//判斷是否為空
	public boolean isEmpty() {
		return first == null;
	}
}

對雙向連結串列的基本功能進行一些測試:

public class TestDoubleLinkList {

	public static void main(String[] args) {
		// TODO 自動生成的方法存根
		DoubleLinkList dL = new DoubleLinkList();
		dL.insertLast(45);
		dL.insertLast(56);
		dL.insertLast(90);
		dL.display();
		
//		dL.deleteLast();
//		dL.display();
		
		while(!dL.isEmpty()) {
			dL.deleteFirst();
			dL.display();
		}
	}

}