单链表
链表大家都很熟悉,链表是由若干个节点串起来的一个结构。类似于火车一样,拥有一个头结点(火车头)之后挂着一个个的节点,每个节点后面跟上另一个节点。每个节点分为两个域,一个数据域,用来存放这个节点的数据,一个是节点域,用来存放下一个节点。
所以对于单链表,用java实现我们首先创建节点类。
Node类:
//联结点,相当于是车厢 public class Node { //数据域 public long data; //节点域 public Node next; //默认构造方法 public Node(long value) { this.data = value; } //显示方法 public void display() { System.out.print(data + " "); } }
再实现一些链表的基本操作。
LinkList类:
//链表,相当于火车 public class LinkList { //车头,头结点 private Node first; public LinkList() { first = null; } //插入节点,在头结点之后插入 public void insertFirst(long value) { Node aNode = new Node(value); aNode.next = first; first = aNode; } //删除头节点 public Node deleteFirst() { Node tmp = first.next; first = tmp; return tmp; } //显示方法 public void display() { Node now = first; while(now != null) { now.display(); now = now.next; } System.out.println(); } //查找方法 public Node find(long value) { Node now = first; while(now.data != value) { if(now.next == null) { return null; } now = now.next; } return now; } //根据数值删除 public Node delete(long value) { Node now = first; Node before = first; while(now.data != value) { if(now.next == null) { return null; } before = now; now = now.next; } if(now == first) { first = first.next; } else { before.next = now.next; } return now; } }
对上面一些基础的方法测试:
public class Test { public static void main(String[] args) { LinkList ll = new LinkList(); ll.insertFirst(1); ll.insertFirst(2); ll.insertFirst(3); ll.insertFirst(4); ll.insertFirst(5); ll.display(); // // ll.deleteFirst(); // ll.display(); // ll.find(2).display(); // Node node = ll.delete(2); // ll.display(); } }
双端链表
双端链表相比于单链表,其实就是加入了一个尾节点来标识表尾
Node类:
//联结点,相当于是车厢 public class Node { //数据域 public long data; //节点域(后) public Node next; //默认构造方法 public Node(long value) { this.data = value; } //显示方法 public void display() { System.out.print(data + " "); } }
相比于单链表,双端链表在插入和删除等操作时进行了一点小的修改,体现在吧last移动的处理上
FirstLastLinkList类:
//双端链表 public class FirstLastLinkList { //车头,头结点 private Node first; //尾节点 private Node last; public FirstLastLinkList() { first = null; last = null; } //插入节点,在头结点之后插入 public void insertFirst(long value) { Node aNode = new Node(value); if (isEmpty()) { last = aNode; } aNode.next = first; first = aNode; } //尾节点插入 public void insertLast(long value) { Node aNode = new Node(value); if (isEmpty()) { first = aNode; } else { last.next = aNode; } last = aNode; } //删除头节点 public Node deleteFirst() { Node tmp = first; if (first.next == null) { last = null; } first = tmp.next; return tmp; } //显示方法 public void display() { Node now = first; while(now != null) { now.display(); now = now.next; } System.out.println(); } //查找方法 public Node find(long value) { Node now = first; while(now.data != value) { if(now.next == null) { return null; } now = now.next; } return now; } //根据数值删除 public Node delete(long value) { Node now = first; Node before = first; while(now.data != value) { if(now.next == null) { return null; } before = now; now = now.next; } if(now == first) { first = first.next; } else { before.next = now.next; } return now; } //判断是否为空 public boolean isEmpty() { return first == null; } }
针对双端链表的一点测试(大家可以自己使用测测):
public class Test { public static void main(String[] args) { // TODO 自动生成的方法存根 FirstLastLinkList f1 = new FirstLastLinkList(); // f1.insertFirst(34); // f1.insertFirst(56); // f1.insertFirst(67); // f1.display(); // // f1.deleteFirst(); // f1.deleteFirst(); // f1.display(); f1.insertLast(56); f1.insertLast(90); f1.insertLast(12); f1.display(); // f1.delete(12); // f1.display(); while (!f1.isEmpty()) { f1.deleteFirst(); f1.display(); } } }
双向链表
为了解决尾删这个问题,引入双向链表,在单链表和双端链表中,如果要进行尾部删除,就要吧表遍历一遍,耗时间耗空间。双向链表的每个节点分为3个域,一个数据域,另外两个节点域,既保存前面的节点的信息,也保存后面的节点的信息。可以理解为有2个指针,既有next后指针,又有previous前指针。
Node类:
//联结点,相当于是车厢 public class Node { //数据域 public long data; //节点域(后) public Node next; //节点域(前) public Node previous; //默认构造方法 public Node(long value) { this.data = value; } //显示方法 public void display() { System.out.print(data + " "); } }
DoubleLinkList类:
//双向链表 public class DoubleLinkList { //车头,头结点 private Node first; //尾节点 private Node last; public DoubleLinkList() { first = null; last = null; } //插入节点,在头结点之后插入 public void insertFirst(long value) { Node aNode = new Node(value); //为空,设置尾节点为新增加的节点 if (isEmpty()) { last = aNode; } //链表不为空的时候,把插入前第一个节点的previous指向新节点 else { first.previous = aNode; } aNode.next = first; first = aNode; } //尾节点插入 public void insertLast(long value) { Node aNode = new Node(value); if (isEmpty()) { first = aNode; } else { last.next = aNode; aNode.previous = last; } last = aNode; } //删除头节点 public Node deleteFirst() { Node tmp = first; if (first.next == null) { last = null; } else { //这里因为存在双指针,所以需要吧后面节点的指向前面节点的那个指针置空 first.next.previous = null; } first = tmp.next; return tmp; } //删除尾节点 public Node deleteLast() { Node tmp = last; if (first.next == null) { first = null; } else { //意思同上 last.previous.next = null; } last = last.previous; return last; } //显示方法 public void display() { Node now = first; while(now != null) { now.display(); now = now.next; } System.out.println(); } //查找方法 public Node find(long value) { Node now = first; while(now.data != value) { if(now.next == null) { return null; } now = now.next; } return now; } //根据数值删除 public Node delete(long value) { Node now = first; while(now.data != value) { if(now.next == null) { return null; } now = now.next; } if(now == first) { first = first.next; } else { now.previous.next = now.next; } return now; } //判断是否为空 public boolean isEmpty() { return first == null; } }
对双向链表的基本功能进行一些测试:
public class TestDoubleLinkList { public static void main(String[] args) { // TODO 自动生成的方法存根 DoubleLinkList dL = new DoubleLinkList(); dL.insertLast(45); dL.insertLast(56); dL.insertLast(90); dL.display(); // dL.deleteLast(); // dL.display(); while(!dL.isEmpty()) { dL.deleteFirst(); dL.display(); } } }