线性表的链式存储的特点是用一组任意存储单元来存储线性表的的数据元素,这组存储单元可以是连续的,也可以不是连续的,这意味着这些数据元素存储在内存未被占用的任意位置上。
【1】链表的基本术语
- 结点:链表的结点包括两部分,数据域和指针域。存储数据元素的部分称为数据域;存储直接后继的信息的域叫做指针域;
- 头指针:把链表中第一个结点的存储位置叫做头指针,那么整个链表必须从头指针开始;
- 头结点:单链表的第一个结点之前会附设一个结点,称之为头结点,头结点的数据域可以不存储任何数据元素;
- 空链表:头结点的指针域为“空”;
- 带有头结点的链表表示形式:
【2】单链表的Java代码实现
- 链表的定义
-
/** * Created by shifeifei on 2017/6/5. * 线性表之单链表 */ public class SingleLinkedList { //链表的长度 private int size = 0; //定义头结点 private Node<String> header; //单链表的第一个元素 private Node<String> first; public SingleLinkedList() { //初始化头结点 header = new Node<String>(); } //定义链表节点 private static class Node<E> { private E data; //节点元素 private Node<E> next; //指向下一个节点元素指针 public Node() { } public Node(E data) { this.data = data; } } }
- 链表中如何添加元素
-
s->next = p->next; p->next = s;
Java代码的实现:
-
/** * 单链表表尾添加元素 * * @param e */ public void add(String e) { Node<String> node = new Node<String>(e); if (null == first) { first = node; //头结点指向链表第一个节点 header.next = first; size++; return; } Node<String> temp = first; while (null != temp.next) { temp = temp.next; } temp.next = node; size++; } /** * 单链表指定位置添加元素 * * @param e * @param index */ public void add(String e, int index) { int j = 1; Node temp = header; if (null == temp.next || index > size) { throw new RuntimeException("链表为空||插入位置不合法"); } while (null != temp.next && j < index) { //继续寻找插入点 temp = temp.next; j++; } //找到插入点,开始插入元素 Node tempNode = new Node(e); tempNode.next = temp.next; temp.next = tempNode; size++; }
- 单链表删除元素
-
p->next = p->next->next;
Java代码实现:
-
/** * 单链表删除元素 * * @param e */ public void delete(String e) { Node temp = header; while (null != temp.next) { Node tempNext = temp.next; if (null != tempNext.data && tempNext.data.equals(e)) { temp.next = tempNext.next; size--; } else { temp = temp.next; } } } /** * 单链表元素遍历 */ public void print() { Node temp = header; while (null != temp.next) { temp = temp.next; System.out.println("当前节点元素: " + temp.data); } } public static void main(String[] args) { SingleLinkedList list = new SingleLinkedList(); list.add("a"); list.add("b"); list.add("e"); list.add("f"); list.print(); System.out.println("-----------------------"); list.add("g", 2); list.print(); System.out.println("链表长度: " + list.size); System.out.println("-----------------------"); list.delete("a"); list.print(); }
【3】循环链表介绍
将单链表中终端结点的指针域由空指针改为指向头结点,就使得整个单链表形成一个环,这种头尾循环的单链表称之为循环链表。
- 循环单链表的Java实现
-
/** * Created by shifeifei on 2017/6/9. * 循环单链表 */ public class LoopSinglyLinkedList { //链表的长度 private int size = 0; //定义头结点 private Node<String> header; public LoopSinglyLinkedList() { //初始化一个空链表 header = new Node<String>(); header.next = header; } //定义链表节点 private static class Node<E> { private E data; //节点元素 private Node<E> next; //指向下一个节点元素指针 public Node() { } public Node(E data) { this.data = data; } } /** * 表尾添加元素 * * @param e */ public void add(String e) { Node<String> node = new Node<String>(e); if (header.next == header) { //说明是空链表 node.next = header; header.next = node; size++; return; } Node temp = header; while (header != temp.next) { temp = temp.next; } temp.next = node; node.next = header; //表尾链接头结点 size++; } /** * 指定位置添加元素 * * @param e * @param index */ public void add(String e, int index) { int j = 1; //记录下标位置 if (header.next == header || index > size) { throw new RuntimeException("链表为空 || 插入位置不合法"); } Node temp = header; while (header != header.next && j < index) { temp = temp.next; j++; } //找到插入点,开始插入 Node<String> node = new Node<String>(e); node.next = temp.next; temp.next = node; size++; } /** * 删除元素 * * @param e */ public void delete(String e) { if (header.next == header) { throw new RuntimeException("链表为空"); } Node temp = header; while (header != temp.next) { Node tempNext = temp.next; if (null != tempNext.data && tempNext.data.equals(e)) { temp.next = tempNext.next; size--; } else { temp = temp.next; } } } public void print() { if (header.next == header) { System.out.println("该链表是空链表"); } Node temp = header; while (header != temp.next) { temp = temp.next; System.out.println("当前链表元素: " + temp.data); } System.out.println("链表当前长度: " + size + "\n"); } public static void main(String[] args) { LoopSinglyLinkedList linkedList = new LoopSinglyLinkedList(); linkedList.add("a"); linkedList.add("b"); linkedList.add("c"); linkedList.add("d"); linkedList.print(); linkedList.add("f", 2); linkedList.print(); linkedList.delete("d"); linkedList.print(); } }
【4】双向链表
双向链表就是在单链表的每个节点中再设置一个指向其前驱节点的指针域;
- 双向链表定义
-
/** * Created by shifeifei on 2017/6/9. * 双向链表 */ public class DoubleLinkedList<T> { //链表的长度 private int size; //头结点 private Node<T> header = new Node<T>(null, null, null); /** * 链表结点 */ private static class Node<T> { T element; private Node<T> prior; //前驱结点 private Node<T> next; //后驱结点 public Node(T element, Node<T> prior, Node<T> next) { this.element = element; this.prior = prior; this.next = next; } } public DoubleLinkedList() { //初始化一个空链表,前驱和后驱都指向自己 header.next = header.prior = header; } }
- 链表尾部添加元素
上图的插入顺序理解:想搞定插入节点s的前驱和后继,再搞定后结点的前驱,最后解决前结点的后继。
Java代码实现:
-
/** * 链表末尾添加元素 * * @param e */ public void add(T e) { //创建一个新结点,设置它的前驱是原链表尾结点,后继是头节点 Node<T> node = new Node<T>(e, header.prior, header); //设置该新结点的后驱结点(就是头结点header)的前驱 node.next.prior = node; //设置该新结点的前驱结点(就是原链表尾结点)的后驱 node.prior.next = node; size++; }
- 链表删除指定元素
Java代码实现:
-
/** * 删除结点元素 */ public void delete(T e) { Node<T> node = new Node<T>(e, null, null); //遍历查找结点 for (Node<T> temp = header.next; temp != header; temp = temp.next) { if (temp.element.equals(node.element)) { temp.prior.next = temp.next; temp.next.prior = temp.prior; size--; } } }
- 其他方法
-
public void print() { if (size < 1) { throw new RuntimeException("空链表"); } for (Node<T> temp = header.next; temp != header; temp = temp.next) { System.out.println("元素结点: " + temp.element); } } public static void main(String[] args) { DoubleLinkedList<String> linkedList = new DoubleLinkedList<String>(); linkedList.add("a"); linkedList.add("b"); linkedList.add("c"); linkedList.add("d"); linkedList.print(); linkedList.delete("b"); System.out.println("------------------------------"); linkedList.print(); }
- 推荐博客文章:http://blog.youkuaiyun.com/javazejian/article/details/53047590