第三章 鏈表

1 基本概念

  • 鏈表是一系列存儲數據元素的單元經過指針串接起來造成的,所以每一個單元至少有兩個域,一個域用於數據元素的存儲,另外一個或兩個域是指向其餘單元的指針。這裏具備一個數據域和多個指針域的存儲單元一般稱爲結點(node)
  • 鏈表分爲帶頭結點的鏈表和不帶頭結點的鏈表,根據實際須要來肯定。
  • 指向鏈表中第一個結點的指針稱爲頭指針,頭指針是鏈表必須的元素;
  • 鏈表數據結構中主要包含單向鏈表、雙向鏈表及循環鏈表

2 概念辨析:頭結點,頭指針

  • 一般使用「頭指針」來標識一個鏈表,頭指針始終指向鏈表的第一個結點。如單鏈表L,頭指針爲NULL的時表示一個空鏈表。下圖爲一個不帶頭結點的單鏈表,頭指針指向鏈表第一個結點,但結點1並非頭結點html

    image-20200826141721487

  • 在單鏈表的第一個結點以前附加一個結點,稱爲頭結點。頭結點的Data域能夠不存儲任何信息,也能夠記錄表長等相關信息。以下圖,就是一個含有頭結點的鏈表,此時頭指針指向頭結點java

image-20200826140121285

  • 不管是否有頭結點,頭指針始終指向鏈表的第一個結點。若是有頭結點,頭指針就指向頭結點。

3 單鏈表

 單鏈表只有一個指針域,在整個結點中數據域用來存儲數據元素,指針域用於指向下一個具備相同結構的結點,以下圖所示。node

img

 與數組相似,單向鏈表中的節點也具備一個線性次序。以下圖所示,若是節點 1 的 next 引用指向節點2,則結點1就是結點2的直接前驅,結點2是結點1的直接後繼。即只能經過前驅節點找到後繼節點,而沒法從後繼節點找到前驅節點。數組

image-20200826141721487

特色:數據結構

  • 數據元素的存儲對應的是不連續的存儲空間,每一個存儲結點對應一個須要存儲的數據元素。每一個結點是由數據域和指針域組成。 元素之間的邏輯關係經過存儲節點之間的連接關係反映出來。
  • 邏輯上相鄰的節點物理上沒必要相鄰。

優勢:ide

  • 插入、刪除靈活 。沒必要移動節點,只要改變節點中的指針,可是須要先定位到結點上。
  • 有元素纔會分配結點空間,不會有閒置的結點。

缺點:oop

  • 比順序存儲結構的存儲密度小 。每一個節點都由數據域和指針域組成,因此相同空間內假設全存滿的話順序比鏈式存儲更多。
  • 查找結點時鏈式存儲要比順序存儲慢。每一個節點地址不連續、無規律,致使按照索引查詢效率低下。

單鏈表的Java實現this

package com.victor.linkedlist;

import java.util.Scanner;


public class SingleLinkedListDemo {

	public static void main(String[] args) {
		SingleLinkedList  sll = new SingleLinkedList();
		char key = ' '; //接收用戶輸入
		Scanner scanner = new Scanner(System.in);
		boolean loop = true;
		//輸出一個菜單欄
		while(loop){
			System.out.println("s(show): 打印鏈表");
			System.out.println("a(add): 從尾部添加結點");
			System.out.println("g(get): 刪除尾結點");
			System.out.println("l(head): 輸出鏈表長度");
			System.out.println("e(exit): 退出程序");
			key = scanner.next().charAt(0);
			switch (key) {
			case 's':
				sll.showLinkedList();
				break;
			case 'a': //從尾部添加結點
				System.out.println("請輸入一個整數");
				int value = scanner.nextInt();
				sll.addFromTail(value);  //最好判斷一下value是否是整數
				break;
			case 'g': //刪除鏈表尾結點
				try {
					int res = sll.getListNode();;
					System.out.printf("刪除的結點值爲%d\n", res);
				} catch (Exception e) {
					System.out.println(e.getMessage()); 
				}
				break;
			case 'l': //輸出鏈表長度
				System.out.printf("鏈表長度爲%d\n", sll.getLength());
				break;
			case 'e': //退出
				scanner.close();
				loop = false;
				break;
			default:
				break;
			}
		}
		System.out.println("程序退出");
	}
}

//定義結點類
class ListNode{
	private int data;
	private ListNode next = null;
	
	//構造方法
	public ListNode(int data) {
		this.data = data;
	}
	
	//返回data值
	public int getData() {
		return this.data;
	}

	//設置data值
	public void setData(int data) {
		this.data = data;
	}

	//返回下一個結點地址
	public ListNode getNext() {
		return this.next;
	}

	//設置下一個結點地址
	public void setNext(ListNode next) {
		this.next = next;
	}

	//重寫toString方法
	@Override
	public String toString() {
		return "ListNode [data=" + data + "]";
	}
}

//定義單鏈表類
class SingleLinkedList{
	//頭結點
	private ListNode head;
	
	//構造方法
	public SingleLinkedList() {
		head = new ListNode(-1);
	}
	
	//頭插法添加結點
	public void addFromHead(int data) {
		ListNode ListNode = new ListNode(data);  //新建結點
		ListNode curr = head.getNext();
		head.setNext(ListNode);
		ListNode.setNext(curr);
	}
	
	//尾插法添加結點
	public void addFromTail(int data) {
		ListNode ListNode = new ListNode(data);  //新建結點
		ListNode curr = head;
		while(curr.getNext() != null) {
			curr = curr.getNext();
		}
		curr.setNext(ListNode);
	}
	
	//刪除鏈表尾結點
	public int getListNode() {
		if (head.getNext() == null) {
			throw new RuntimeException("鏈表爲空鏈表");
		}
		ListNode curr = head;
		ListNode prev = head;
		while(curr.getNext() != null) {
			prev = curr;
			curr = curr.getNext();
		}
		prev.setNext(null);
		return curr.getData();
	}
	
	//求鏈表長度
	public int getLength() {
		int length = 0;
		ListNode curr = head;
		while(curr.getNext() != null) {
			length++;
			curr = curr.getNext();
		}
		return length;
	}
	
	//打印鏈表
	public void showLinkedList() {
		ListNode curr = head.getNext();
		while(curr != null) {
			System.out.println(curr);
			curr = curr.getNext();
		}
	}

}

reference.net

深入理解:帶頭結點和不帶頭結點的區別 使用頭結點的優點https://blog.csdn.net/qq_24118527/article/details/81317410指針

鏈表詳解(易懂)https://blog.csdn.net/SlimShadyKe/article/details/89503062

詳細實現單鏈表的基本操做【Java版】

java實現單鏈表常見操做

韓順平數據結構

大話數據結構