链表由结点组成,每个结点除了保留本身的数据,还须要有指向其余结点的指针。与数组相比,链表在物理存储上是不间断的,不能通过下标进行随机拜访来获取元素。然而链表能够很容易的通过调整指针的指向实现减少和删除结点。

按指针的指向,链表分为:

  • 单向链表
  • 双向链表

单向链表

单向链表的结点只有一个指向下一个结点的指针。

先创立一个结点对象,蕴含一个指针属性next:

public class Node {    private int data;    private Node next;    public Node() {    }    public Node(int data) {        this.data = data;    }    public Node(Node next) {        this.next = next;    }    public Node(int data, Node next) {        this.data = data;        this.next = next;    }    public int getData() {        return data;    }    public void setData(int data) {        this.data = data;    }    public Node getNext() {        return next;    }    public void setNext(Node next) {        this.next = next;    }    @Override    public String toString() {        return "Node{" +                "data=" + data +                '}';    }}

将对单向链表的罕用操作封装到类中:

public class SingleLinkedList {    /**     * 遍历单向链表     * @param head 头结点     */    public void list(Node head) {        if (head == null || head.getNext() == null) {            System.out.println("the List is empty");            return;        }        Node temp = head.getNext();        while (true) {            if (temp == null) {                break;            }            System.out.println(temp);            temp = temp.getNext();        }    }    /**     * 获取单向链表长度(结点个数),不统计头结点     * @param head 头结点     * @return 返回链表长度(结点个数)     */    public int getLength(Node head) {        if (head == null || head.getNext() == null) {            return 0;        }        Node temp = head.getNext();        int length = 0;        while (temp != null) {            length++;            temp = temp.getNext();        }        return length;    }    /**     * 增加结点到单向链表的最初     * 1.找到以后单向链表的最初结点     * 2.将最初结点的next指向新结点     * @param head 头结点     * @param node     */    public boolean add(Node head, Node node) {        if (head == null || node == null) {            return false;        }        Node temp = head;        while (true) {            if (temp.getNext() == null) {                break;            }            temp = temp.getNext();        }        temp.setNext(node);        return true;    }    /**     * 增加结点到指定结点前面     * @param node 指定的结点     * @param insertNode 增加的结点     */    public boolean insert(Node node, Node insertNode) {        if (node == null || insertNode == null) {            return false;        }        if (node.getNext() == null) {            node.setNext(insertNode);            return true;        }        insertNode.setNext(node.getNext());        node.setNext(insertNode);        return true;    }    /**     * 删除指定结点,须要找到指定结点的前一个结点     * @param deleteNode 删除的结点     */    public boolean delete(Node head, Node deleteNode) {        if (head == null || deleteNode == null || head == deleteNode) {            return false;        }        Node temp = head;        while (true) {            if (temp.getNext() == null) {                return false;            }            if (temp.getNext() == deleteNode) {                break;            }            temp = temp.getNext();        }        temp.setNext(temp.getNext().getNext());        return true;    }}

进行测试:

public static void main(String[] args) {        Node head = new Node(0);        SingleLinkedList singleLinkedList = new SingleLinkedList();        Node node1 = new Node(1);        Node node2 = new Node(2);        Node node3 = new Node(3);        Node node4 = new Node(4);        System.out.println("===增加结点到最初===");        singleLinkedList.add(head,node1);        singleLinkedList.add(head,node2);        singleLinkedList.add(head,node3);        singleLinkedList.add(head,node4);        System.out.println("链表结点为:");        singleLinkedList.list(head);        System.out.println("链表长度为:");        System.out.println(singleLinkedList.getLength(head));        System.out.println("===增加结点到指定结点前面===");        Node node5 = new Node(5);        singleLinkedList.insert(node2,node5);        System.out.println("链表结点为:");        singleLinkedList.list(head);        System.out.println("链表长度为:");        System.out.println(singleLinkedList.getLength(head));        System.out.println("===删除指定结点===");        singleLinkedList.delete(head,node5);        System.out.println("链表结点为:");        singleLinkedList.list(head);        System.out.println("链表长度为:");        System.out.println(singleLinkedList.getLength(head));    }

输入后果为:

===增加结点到最初===链表结点为:Node{data=1}Node{data=2}Node{data=3}Node{data=4}链表长度为:4===增加结点到指定结点前面===链表结点为:Node{data=1}Node{data=2}Node{data=5}Node{data=3}Node{data=4}链表长度为:5===删除指定结点===链表结点为:Node{data=1}Node{data=2}Node{data=3}Node{data=4}链表长度为:4

反转单向链表

指定一个新的头结点,将每一个解决的结点都放在新的头结点之后。

    /**     * 反转单向链表     * @param head     * @return     */    public Node reverse(Node head) {        if (head == null || head.getNext() == null) {            return head;        }        // 指定一个新的头结点        Node newHead = new Node(0);        // 指定以后解决的结点        Node curr = head.getNext();        // 指定以后解决结点的下一结点        Node next = null;        while (curr != null) {            // 第一步:获取反转前以后结点的下一结点            next = curr.getNext();            // 第二步:指定以后结点的下一结点为新的头结点的下一结点            curr.setNext(newHead.getNext());            // 第三步:指定新的头结点的下一结点为以后解决的结点            newHead.setNext(curr);            // 持续解决后一个结点            curr = next;        }        // 指定原头结点的下一结点为新头结点的下一结点        head.setNext(newHead.getNext());        return head;    }

第一个结点解决示意图:

第二个结点解决示意图:

后面的循环遍历都没有思考单向列表成环的状况,如果有环的话,就会导致有限循环,能够通过快慢指针来查看环:

/**     * 检测环     * @param head 头结点     * @return     */    public boolean checkCircle(Node head) {        if (head == null) {            return false;        }        Node fast = head.getNext();        Node slow = head;        while (fast != null && fast.getNext() != null) {            fast = fast.getNext().getNext();            slow = slow.getNext();            if (slow == fast) {                return true;            }        }        return false;    }

双向链表

双向链表的结点有两个指针,别离指向上一个结点和下一个结点。

先创立一个结点对象,蕴含两指针属性pre和next:

public class DoubleNode {    private int data;    private DoubleNode pre;    private DoubleNode next;    public DoubleNode() {    }    public DoubleNode(int data) {        this.data = data;    }    public DoubleNode(DoubleNode pre, DoubleNode next) {        this.pre = pre;        this.next = next;    }    public DoubleNode(int data, DoubleNode pre, DoubleNode next) {        this.data = data;        this.pre = pre;        this.next = next;    }    public int getData() {        return data;    }    public void setData(int data) {        this.data = data;    }    public DoubleNode getPre() {        return pre;    }    public void setPre(DoubleNode pre) {        this.pre = pre;    }    public DoubleNode getNext() {        return next;    }    public void setNext(DoubleNode next) {        this.next = next;    }    @Override    public String toString() {        return "DoubleNode{" +                "data=" + data +                '}';    }}

将对双向链表的罕用操作封装到类中:

public class DoubleLinkedList {    /**     * 遍历双向链表     * @param head 头结点     */    public void list(DoubleNode head) {        if (head.getNext() == null) {            System.out.println("the List is empty");            return;        }        DoubleNode temp = head.getNext();        while (true) {            if (temp == null) {                break;            }            System.out.println(temp);            temp = temp.getNext();        }    }    /**     * 获取双向链表长度(结点个数),不统计头结点     * @param head 头结点     * @return 返回链表长度(结点个数)     */    public int getLength(DoubleNode head) {        if (head == null || head.getNext() == null) {            return 0;        }        DoubleNode temp = head.getNext();        int length = 0;        while (temp != null) {            length++;            temp = temp.getNext();        }        return length;    }    /**     * 增加结点到双向链表的最初     * 1.找到以后双向链表的最初结点     * 2.将最初结点的next指向新结点     * 3.将新结点的pre指向前一结点     * @param head 头结点     * @param node 减少的结点     */    public void add(DoubleNode head, DoubleNode node) {        DoubleNode temp = head;        while (true) {            if (temp.getNext() == null) {                break;            }            temp = temp.getNext();        }        temp.setNext(node);        node.setPre(temp);    }    /**     * 增加结点到指定结点前面     * @param node 指定的结点     * @param insertNode 增加的结点     */    public boolean insertAfter(DoubleNode node, DoubleNode insertNode) {        if (node == null || insertNode == null) {            return false;        }        if (node.getNext() == null) {            node.setNext(insertNode);            insertNode.setPre(node);            return true;        }        insertNode.setPre(node);        insertNode.setNext(node.getNext());        node.getNext().setPre(insertNode);        node.setNext(insertNode);        return true;    }    /**     * 增加结点到指定结点后面     * @param node 指定的结点     * @param insertNode 增加的结点     */    public boolean insertBefore(DoubleNode node, DoubleNode insertNode) {        if (node == null || insertNode == null) {            return false;        }        if (node.getPre() == null) {            insertNode.setNext(node);            node.setPre(insertNode);            return true;        }        insertNode.setPre(node.getPre());        insertNode.setNext(node);        node.getPre().setNext(insertNode);        node.setPre(insertNode);        return true;    }    /**     * 删除指定结点     * @param deleteNode 删除的结点     */    public boolean delete(DoubleNode deleteNode) {        if (deleteNode == null) {            return false;        }        if (deleteNode.getPre() != null){            deleteNode.getPre().setNext(deleteNode.getNext());        }        if (deleteNode.getNext() != null) {            deleteNode.getNext().setPre(deleteNode.getPre());        }        return true;    }    /**     * 检测环     * @param head 头结点     * @return     */    public boolean checkCircle(DoubleNode head) {        if (head == null) {            return false;        }        DoubleNode fast = head.getNext();        DoubleNode slow = head;        while (fast != null && fast.getNext() != null) {            fast = fast.getNext().getNext();            slow = slow.getNext();            if (slow == fast) {                return true;            }        }        return false;    }}

进行测试:

public static void main(String[] args) {        DoubleNode head = new DoubleNode(0);        DoubleLinkedList doubleLinkedList = new DoubleLinkedList();        DoubleNode node1 = new DoubleNode(1);        DoubleNode node2 = new DoubleNode(2);        DoubleNode node3 = new DoubleNode(3);        DoubleNode node4 = new DoubleNode(4);        System.out.println("===增加结点到最初===");        doubleLinkedList.add(head,node1);        doubleLinkedList.add(head,node2);        doubleLinkedList.add(head,node3);        doubleLinkedList.add(head,node4);        System.out.println("链表结点为:");        doubleLinkedList.list(head);        System.out.println("链表长度为:");        System.out.println(doubleLinkedList.getLength(head));        System.out.println("===增加结点到指定结点前面===");        DoubleNode node5 = new DoubleNode(5);        doubleLinkedList.insertAfter(node2,node5);        System.out.println("链表结点为:");        doubleLinkedList.list(head);        System.out.println("链表长度为:");        System.out.println("===增加结点到指定结点后面===");        DoubleNode node6 = new DoubleNode(6);        doubleLinkedList.insertBefore(node2,node6);        System.out.println("链表结点为:");        doubleLinkedList.list(head);        System.out.println("链表长度为:");        System.out.println(doubleLinkedList.getLength(head));        System.out.println("===删除指定结点===");        doubleLinkedList.delete(node5);        System.out.println("链表结点为:");        doubleLinkedList.list(head);        System.out.println("链表长度为:");        System.out.println(doubleLinkedList.getLength(head));    }

输入后果为:

===增加结点到最初===链表结点为:DoubleNode{data=1}DoubleNode{data=2}DoubleNode{data=3}DoubleNode{data=4}链表长度为:4===增加结点到指定结点前面===链表结点为:DoubleNode{data=1}DoubleNode{data=2}DoubleNode{data=5}DoubleNode{data=3}DoubleNode{data=4}链表长度为:===增加结点到指定结点后面===链表结点为:DoubleNode{data=1}DoubleNode{data=6}DoubleNode{data=2}DoubleNode{data=5}DoubleNode{data=3}DoubleNode{data=4}链表长度为:6===删除指定结点===链表结点为:DoubleNode{data=1}DoubleNode{data=6}DoubleNode{data=2}DoubleNode{data=3}DoubleNode{data=4}链表长度为:5

欢送关注我的公众号,一起学习。