第三章 链表

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实现单链表常见操做

韩顺平数据结构

大话数据结构