一般使用“头指针”来标识一个链表,头指针始终指向链表的第一个结点。如单链表L,头指针为NULL的时表示一个空链表。下图为一个不带头结点的单链表,头指针指向链表第一个结点,但结点1并非头结点;html
在单链表的第一个结点以前附加一个结点,称为头结点。头结点的Data域能够不存储任何信息,也能够记录表长等相关信息。以下图,就是一个含有头结点的链表,此时头指针指向头结点;java
单链表只有一个指针域,在整个结点中数据域用来存储数据元素,指针域用于指向下一个具备相同结构的结点,以下图所示。node
与数组相似,单向链表中的节点也具备一个线性次序。以下图所示,若是节点 1 的 next 引用指向节点2,则结点1就是结点2的直接前驱,结点2是结点1的直接后继。即只能经过前驱节点找到后继节点,而没法从后继节点找到前驱节点。数组
特色:数据结构
优势: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
韩顺平数据结构
大话数据结构