JAVA資料結構之連結串列

菩提天珠發表於2020-09-29

1、單連結串列的資料結構

單連結串列中的資料是以結點的形式存在,每一個結點是由資料元素(資料域)和下一個結點的儲存的位置(指標域)組成。單連結串列與陣列相比的最大差別是:單連結串列的資料元素存放在記憶體空間的地址是不連續的,而陣列的資料元素存放的地址在記憶體空間中是連續的。具體的資料模型用下圖大概描述一下。

 

2、單連結串列的優缺點

優點:

插入刪除速度快、記憶體利用率高,不會浪費記憶體、大小沒有固定,擴充很靈活

由於連結串列的節點在記憶體中可以存在任何地方、不要求連續,且每個節點中都儲存著下一節點的記憶體地址。如果需要新插入一個新節點(資料),只需要把此節點的記憶體地址指向下一節點,上一節點的記憶體地址指向本節點就OK了,其餘節點都不用發生改變,所以插入刪除速度快。不像陣列一樣增加、刪除資料後其他的元素的下標都得發生改變。

缺點:

不可以進行隨機查詢

這個由連結串列的資料結構決定的,查詢某個節點的資料都必須在head(頭節點)依次指向下一節點,直到找到我們需要的資料節點。這一點不像陣列一樣可以根據陣列下標直接進行查詢。

3、單連結串列的簡單實現

在這裡就使用程式碼簡單的實現下單連結串列的資料結構,並實現增刪改查。

新建一個節點類,用來儲存每個節點的資料

public class Node <T>{
    //資料域
	public T t;
    //指標域
	public Node next;
	public Node(T t,Node next){
		this.t = t;
		this.next = next;
	}
	public Node(T t){
		this(t,null);
	}
}

新建連結串列類,宣告增刪改查方法

1、在連結串列頭部新增節點方法

public class LinkList<T> {
	
	private Node head;    		//頭結點
	private int size;			//連結串列元素個數
	//建構函式
	public LinkList(){
		this.head = null;
		this.size = 0;
	}
	/**
	 * 往連結串列頭部插入值
	 * @param t
	 */
	public void addFirst(T t) {
		Node node = new Node(t);	//節點物件
		node.next = this.head;
		this.head = node;
		this.size++;
	}
	
	/**
	 * java類的預設繼承方法,繼承於object類。
	 */
	public String toString() {
		StringBuffer sb = new StringBuffer();
		Node cur = this.head;
		while(cur != null){
			sb.append(cur.t+"=>");
			cur = cur.next;
		}
		sb.append("NULL");
		return sb.toString();
	}
	
}

在連結串列的頭部新增節點,具體操作是把新節點的next指向當前頭結點,更新this.head為新增的節點,節點數量加一。具體如下圖:

測試方法:

public static void main(String[] args) {
		// TODO Auto-generated method stub


		LinkList<String> linklist = new LinkList();
		String[] strArray = new String[6];
		strArray[0] = "one";
		strArray[1] = "two";
		strArray[2] = "three";
		strArray[3] = "four";
		strArray[4] = "five";
		strArray[5] = "six";
		for(String str : strArray) {
			linklist.addFirst(str);
			System.out.println(linklist);
		}
		

	}

執行main方法

2、在連結串列根據位置插入資料

具體程式碼如下:

/**
	 * 往連結串列中間插入值
	 * @param index
	 * @param t
	 */
	public void add(int index,T t) {
		//當index值小於零或者大於連結串列長度時,丟擲異常
		if (index <0 || index > this.size){
			throw new IllegalArgumentException("index is error");
		}
		//當index為零的時候向連結串列頭部插入一個值
		if (index == 0){
			this.addFirst(t);
		}
		//獲取當前連結串列的頭元素(第一個值)
		Node preNode = this.head;
		//找到要插入節點的前一個節點
		for(int i=0;i<index-1;i++) {
			preNode = preNode.next;
		}
		Node cruNode = new Node(t);
		//要插入的節點的下一個節點指向preNode節點的下一個節點
		cruNode.next = preNode.next;
		//preNode的下一個節點指向要插入節點node
		preNode.next = cruNode;
		this.size++;
	}

原理圖形表達:

測試程式碼main如下:

public static void main(String[] args) {
		// TODO Auto-generated method stub


		LinkList<String> linklist = new LinkList();
		String[] strArray = new String[6];
		strArray[0] = "one";
		strArray[1] = "two";
		strArray[2] = "three";
		strArray[3] = "four";
		strArray[4] = "five";
		strArray[5] = "six";
		for(String str : strArray) {
			linklist.addFirst(str);
			System.out.println(linklist);
		}
		
		linklist.add(3, "23");
		System.out.println(linklist);
		linklist.add(3, "45");
		System.out.println(linklist);
		

	}

測試結果如下:

3、查詢方法

//連結串列中是否包含某個元素
	public boolean contains(T t){
		Node cur = this.head;
		while(cur != null){
			if(cur.t.equals(t)){
				return true;
			}
			else {
				cur = cur.next;
			} 
		}
		return false;
	}

根據方法傳入的值從連結串列的頭部進行遍歷,如果找到了return結果true,找不到就return結果false。

測試程式碼:

public static void main(String[] args) {
		// TODO Auto-generated method stub


		LinkList<String> linklist = new LinkList();
		String[] strArray = new String[6];
		strArray[0] = "one";
		strArray[1] = "two";
		strArray[2] = "three";
		strArray[3] = "four";
		strArray[4] = "five";
		strArray[5] = "six";
		for(String str : strArray) {
			linklist.addFirst(str);
			System.out.println(linklist);
		}
		
		linklist.add(3, "23");
		System.out.println(linklist);
		linklist.add(3, "45");
		System.out.println(linklist);
		System.out.println(linklist.contains("four"));
		System.out.println(linklist.contains("ten"));
	
	}

演示結果:

4、刪除方法

public void remove(T t) {
		
		if(this.head ==null) {
			System.out.println("連結串列中無資料,不可進行刪除!!");
		}else {
			//如果要刪除的元素跟連結串列頭部的元素相同,就刪除頭部(把頭元素的指向的元素設為頭元素)
			if(head.t.equals(t)) {
				head = head.next;
				this.size--;
			}else {
				//獲取當前節點為頭部節點
				Node cur = this.head;
				//一直迴圈遍歷連結串列到最後
				while(cur.next != null) {
					//當前元素的下一個元素為要刪除的值時,那就把當前元素下一個元素的下一個元素 設為 當前元素的下一個元素
					if(cur.next.t.equals(t)) {
						cur.next = cur.next.next;
					}else {
						cur = cur.next;
					}
				}
				
			}
			
		}
		
	}

原理圖形表達:

測試程式碼:

public static void main(String[] args) {
		// TODO Auto-generated method stub


		LinkList<String> linklist = new LinkList();
		String[] strArray = new String[6];
		strArray[0] = "one";
		strArray[1] = "two";
		strArray[2] = "three";
		strArray[3] = "four";
		strArray[4] = "five";
		strArray[5] = "six";
		for(String str : strArray) {
			linklist.addFirst(str);
			System.out.println(linklist);
		}
		
		linklist.add(3, "23");
		System.out.println(linklist);
		linklist.add(3, "45");
		System.out.println(linklist);
		System.out.println(linklist.contains("four"));
		System.out.println(linklist.contains("ten"));
		
		linklist.remove("45"); 
		System.out.println(linklist);
		 
	
	}

測試的結果:

到這就簡單演示了單連結串列的資料結構,深入研究還是看一下java的LinkedList。

相關文章