链式表
概念:每一个元素都包含一个称之为结点(node)的结构,我们去添加一个元素就会产生一个包含
元素的结点,每个节点和它相邻的节点相连接
结点=数据域+引用域
节点之间是通过引用域相连接的
链表是一种物理存储单元上非连续的存储结构,数据之间也是非连续的,数据元素的顺序是通过链表中的引用域链接次序决定的
实现
class Node{}
带头结点的链表,永远有一head引用指向当前链表的第一个节点,同时该链表的第一个节点
不能存放有效元素,data域只能存放一个无效元素

实现带头结点单链表

class SingleLinkedListTakeHead<T>{

    private Node<T> head;

    class Node<T>{
        private T data;
        private Node<T> next;

        public Node(T data){
            this.data = data;
        }
    }

    public SingleLinkedListTakeHead(){
        head = new Node<T>((T)new Object());
    }

    public void addHead(T data){
        Node<T> newNode = new Node<>(data);

        //将head后面的节点绑定在newNode节点之后
        newNode.next = head.next;
        //将head节点的next指向newNode
        head.next = newNode;

    }

    public void addTail(T data){
        Node<T> newNode = new Node<>(data);

        //遍历当前链表,找到尾节点,尾节点之后绑定newNode
        Node<T> tmp = head;
        while(tmp.next != null){
            tmp = tmp.next;
        }

        //跳出循环tmp.next = null,此时tmp就是尾节点
        tmp.next = newNode;
    }

    public boolean delete(T data){
        if(head.next == null){
            return false;
        }

        //删除节点,涉及到删除节点的前一个节点的操作
        Node<T> tmp = head;
        while(tmp.next != null ){
            if(tmp.next.data == data){
                //tmp为所删除节点的前一个节点
                tmp.next = tmp.next.next;
                //连续使用.操作符,注意.操作符之前的引用是否为null
                //如果为null,会造成空指针异常
                return true;
            }
            tmp = tmp.next;
        }
        return false;
    }

    public T findNode(int index){
        //假设当前链表的index从0开始
        if(index <= 0) return null;
        Node<T> tmp = head.next;

        while(index-- > 1 && tmp != null){
            tmp = tmp.next;
        }
        if(tmp != null){
            return tmp.data;
        }
        return null;
    }

    public boolean set(int index, T newData){
        if(index <= 0 ) return false;
        Node<T> tmp = head.next;

        while(index-- > 1 && tmp != null){
            tmp = tmp.next;
        }

        if(tmp != null){
            tmp.data = newData;
            return true;
        }
        return false;
    }

    public String toString(){
        StringBuilder sb = new StringBuilder();

        if(head.next == null){
            return "No Data";
        }

        //遍历链表
        Node<T> tmp = head.next;
        while(tmp != null){
            sb.append(tmp.data + " ");
            tmp = tmp.next;
        }

        return sb.toString();
    }
}

public class TestDemo1 {
    public static void main(String[] args) {
        SingleLinkedListTakeHead<Integer> list = new SingleLinkedListTakeHead<>();
        list.addHead(1);
        list.addHead(2);
        list.addHead(3);
        list.addHead(4);
        list.addHead(5);
        System.out.println(list.toString());
        list.delete(3);
        list.delete(1);
        System.out.println(list.toString());
        System.out.println(list.findNode(2));
        System.out.println(list.set(2, 100));
        System.out.println(list.toString());

        list.addTail(1000);
        list.addTail(2000);
        System.out.println(list.toString());

    }
}

实现不带头节点的单链表

class SingleLinkedList<T>{
    protected Node<T> head;

    class Node<T>{
        protected T data;
        protected Node<T> next;

        public Node(T data){
            this.data = data;
        }
    }

    public void add(T data){
        Node<T> newNode = new Node<>(data);

        //第一种情况,head节点为空,直接head指向newNode
        if(head == null){
            head = newNode;
        }else{
            //第二种情况,head节点非空,遍历整个链表,找到尾节点,添加新节点
            Node<T> tmp = head;

            while(tmp.next != null){
                tmp = tmp.next;
            }
            //tmp即为当前链表的尾节点,在tmp之后绑定newNode
            tmp.next = newNode;
        }
    }

    public boolean delete(T data){
        //删除节点会涉及到所删除节点的前一个节点的操作,head节点没有前一节点
        //需要单独处理

        //第一种情况,删除头节点,直接将head设置为下一个节点
        if(head.data == data){
            head = head.next;
            return true;
        }else{
            //第二种情况,不是头节点,需要遍历找到所删除节点
            Node<T> tmp = head;
            while(tmp.next != null){
                if(tmp.next.data == data){
                    tmp.next = tmp.next.next;
                    return true;
                }
                tmp = tmp.next;
            }
            return false;
        }
    }

    public String toString(){
        StringBuilder sb = new StringBuilder();

        if(head == null){
            return "No Data";
        }

        Node<T> tmp = head;
        sb.append(tmp.data + " ");
        while(tmp.next != null){
            sb.append(tmp.next.data + " ");
            tmp = tmp.next;
        }
        return sb.toString();
    }
}

public class TestDemo2 {
    public static void main(String[] args) {
        SingleLinkedList<String> list = new SingleLinkedList<>();
        list.add("tu");
        list.add("lun");
        list.add("you");
        list.add("xiu");
        list.add("123");

        System.out.println(list.toString());

        list.delete("tu");
        list.delete("123");
        list.delete("you");
        System.out.println(list.toString());
    }
}

单向循环链表

class LoopSingleLinkedList<E>{
    protected Node<E> head;

    class Node<E>{
        protected E data;
        protected Node<E> next;

        public Node(E data){
            this.data = data;
        }
    }

    public void add(E data){
        //创建一个新节点
        Node<E> newNode = new Node<>(data);

        //当前链表为空
        if(head == null){
            head = newNode;
            newNode.next = head;
        }

        //遍历至尾节点
        Node<E> tmp =head;
        while(tmp.next != head){
            tmp = tmp.next;
        }
        newNode.next = tmp.next;
        tmp.next = newNode;
    }

    public boolean delete(E data){
        //head是所删除节点,改变head的引用,同时改变尾节点的next
        if(head.data == data){
            //找到尾节点
            Node<E> tmp = head;
            while(tmp.next != head){
                tmp = tmp.next;
            }
            head = head.next;
            tmp.next = head;
            return true;
        }

        Node<E> prev = head;//保存当前节点的前一个节点
        Node<E> cur = head.next;//保存当前节点

        while(cur != head){
            if(cur.data == data){
                prev.next = cur.next;
                return true;
            }
            prev = cur;
            cur = cur.next;
        }
        return false;
    }

    public int getLength(){

        int count = 1; //计数器
        Node<E> tmp = head.next;

        while(tmp != head){
            count++;
            tmp = tmp.next;
        }
        return count;
    }

    public E findValue(int index){
        //index默认从0开始,head的索引就是0
        int length = getLength();
        //判断index的合法性
        if(index < 0 || index >= length){
            return null;
        }

        Node<E> tmp = head;
        for(int i=0; i<index; i++){
            tmp = tmp.next;
        }
        //跳出循环 i = index, tmp指向就是所要查找的节点
        return tmp.data;
    }

    public void show(){

        System.out.print(head.data + " ");
        Node<E> tmp = head.next;
        while(tmp != head){
            System.out.print(tmp.data + " ");
            tmp = tmp.next;
        }
        System.out.println();
    }
}

public class TestDemo1 {
    public static void main(String[] args) {
        LoopSingleLinkedList<Integer> list = new LoopSingleLinkedList<>();
        list.add(10);
        list.add(20);
        list.add(0);
        list.add(1);
        list.add(5);
        list.add(15);
        list.add(30);
        list.show();
        list.delete(10);
        list.delete(30);
        list.delete(0);
        list.show();
        System.out.println(list.findValue(0));
        System.out.println(list.findValue(3));
    }
}

双向链表

class DoubleLinkedList<E>{
    protected Node<E> first; //指向链表中第一个节点
    protected Node<E> last; //指向链表中的最后一个节点
    protected int size; //当前链表的节点个数

    class Node<E>{
        protected E data; //当前节点的内容
        protected Node<E> prev; //前驱引用
        protected Node<E> next; //后继引用

        public Node(E data, Node<E> prev, Node<E> next){
            this.data = data;
            this.prev = prev;
            this.next = next;
        }
    }

    public void add(E value){
        Node<E> tmp = last;
        Node<E> newNode = new Node<>(value, tmp, null);

        last = newNode;
        if(tmp == null){
            first = newNode; //原先链表为空,此时该节点作为链表中第一个节点存在
        }else{
            tmp.next = newNode;
        }
        size++;
    }

    public void add(int index, E value){
        //根据index找到该节点
        if(index < 0 || index > size){
            return;
        }
        if(index == size){
            add(value);
        }else{
            //根据index得到该位置的节点
            Node<E> succ = findNodeByIndex(index);
            //得到该节点的前驱引用
            Node<E> succPre = succ.prev;
            //new一个新节点
            Node<E> newNode = new Node(value, succPre, succ);
            //绑定新节点为succ的前驱引用
            succ.prev = newNode;
            if(succPre == null){
                //说明原先链表只有一个节点
                first = newNode;
            }else{
                succPre.next = newNode;
            }
        }
        size++;
    }

    public Node<E> findNodeByIndex(int index){
        Node<E> tmp = first;
        for(int i=0; i<index; i++){
            tmp = tmp.next;
        }
        return tmp;
    }

    public Node<E> findValueByValue(E value){
        for(Node<E> tmp = first; tmp != null; tmp = tmp.next){
            if(value.equals(tmp.data)){
                return tmp;
            }
        }
        return null;
    }

    public boolean delete(E value){
        //删除元素所在的节点
        //找出元素所在的节点
        Node<E> succ = findValueByValue(value);
        if(succ == null){
            return false;
        }
        //考虑删除的是第一个节点或者最后一个节点的情况
        Node<E> succPrev = succ.prev;
        Node<E> succNext = succ.next;

        //如果删除的是第一个节点
        if(succPrev == null){
            first = succNext;
        }else{
            succPrev.next = succNext;
            succ.prev = null;
        }
        //如果删除的是最后一个节点
        if(succNext == null){
            last = succPrev;
        }else{
            succNext.prev = succPrev;
            succ.next = null;
        }

        size--;
        return true;

    }

    public String toString(){
        StringBuilder sb = new StringBuilder();
        for(Node<E> tmp = first; tmp != null; tmp = tmp.next){
            sb.append(tmp.data + " ");
        }
        return sb.toString();
    }
}
public class TestDemo3 {
    public static void main(String[] args) {
        DoubleLinkedList<String> list = new DoubleLinkedList<>();
        list.add("abc");
        list.add("faafabc");
        list.add("fafabc");
        list.add("vsdfabc");
        list.add("wwabc");
        list.add("adaabc");
        System.out.println(list.toString());
        list.add(1, "tulun");
        list.add(5, "software");
        System.out.println(list.toString());
        list.delete("abc");
        list.delete("adaabc");
        list.delete("fafabc");
        System.out.println(list.toString());
    }
}