Java 实现双向且双端的链表,使用dummyHead、dummyTail、index

文章目录

  • 思路
  • 实现
  • 测试

思路

双向链表:next、prev 双向节点指针;
使用 head、tail 表示双端;
使用虚拟头、尾结点,方便循环遍历;
使用 index,向用户提供类似数组一样的增、删、查(能查就能改,改没考虑);
内部维护一个 size变量,表示实际节点的数量(不算虚拟头和尾);
由 size、index,可以确定增、删、查是要从头还是从尾遍历实现:

//最近的节点: true 靠近 head;false 靠近 tail
private boolean nearlyNode(int index) {
	return size - index >= index;
}

实现

/**
 * desc  : 链表 使用虚拟头节点(dummy head node), 且是双(向)链表
 *          增:O(n)
 *          删除: O(n)
 *          查: O(n)
 *          这三者若只操作链表头、尾,则是 O(1)
 *
 *          在 增、删、查时,用 nearlyNode():boolean 判断 最近的节点: true 靠近 head;false 靠近 tail;
 *          在 增、删时,
 *              要考虑新结点的前后节点;
 *              要增、删的节点的前节点的 后节点;
 *              要增、删的节点的后节点的 前节点。
 * author: stone
 * email : [email protected]
 * time  : 2018/12/24 12 39
 */
public class MyLinkedList3 {
    private int size;
    private Node dummyHead;
    private Node dummyTail;

    public MyLinkedList3() {
        size = 0;
        dummyHead = new Node();
        dummyTail = new Node();
        dummyHead.next = dummyTail;
        dummyTail.prev = dummyHead;
    }

    private class Node {
        E e;
        Node next;
        Node prev;

        Node(E e, Node next, Node prev) {
            this.e = e;
            this.next = next;
            this.prev = prev;
        }

        Node(E e) {
            this(e, null, null);
        }

        Node() {
            this(null, null, null);
        }

        @Override
        public String toString() {
            return e.toString();
        }
    }

    public int getSize() {
        return size;
    }

    public boolean isEmpty() {
//        return head == null;
        return size == 0;
    }

    public E get(int index) {
        if (index < 0 || index > size) {
            throw new IllegalArgumentException("get failed");
        }

        Node cur;
        if (nearlyNode(index)) {
            System.out.println("get nearly head, index=" + index);
            cur = dummyHead;
            for (int i = 0; i <= index; i++) {
                cur = cur.next;
            }
        } else {
            System.out.println("get nearly tail, index=" + index);
            cur = dummyTail;
            for (int i = size - 1; i >= index; i--) {
                cur = cur.prev;
            }
        }

        return cur.e;
    }

    public E getFirst() {
        return get(0);
    }

    public E getLast() {
        return get(size - 1);
    }

    //最近的节点: true 靠近 head;false 靠近 tail
    private boolean nearlyNode(int index) {
        return size - index >= index;
    }

    public void add(int index, E e) {
        if (index < 0 || index > size) {
            throw new IllegalArgumentException("linked list add error.");
        }

        Node p;
        Node newNode;
        if (nearlyNode(index)) {
            System.out.println("add nearly head, index=" + index);
            p = dummyHead;
            for (int i = 0; i < index; i++) {
                p = p.next;
            }
            newNode = new Node(e, p.next, p);
            p.next.prev = newNode;
            p.next = newNode;
        } else {
            System.out.println("add nearly tail, index=" + index);
            p = dummyTail;
            for (int i = size; i >= index; i--) {
                p = p.prev;
            }
            newNode = new Node(e, p.next, p);
            p.next.prev = newNode;
            p.next = newNode;
        }

        size++;
    }

    public void addFirst(E e) {
        add(0, e);
    }

    public void addLast(E e) {
        add(size, e);
    }

    public boolean contains(E e) {
        Node cur = dummyHead.next;
        while (cur != null) {
            if (cur.e.equals(e)) {
                return true;
            }
            cur = cur.next;
        }
        return false;
    }

    public E remove(int index) {
        if (index < 0 || index >= size) {
            throw new IllegalArgumentException("remove failed.");
        }

        Node retNode;
        if (nearlyNode(index)) {
            System.out.println("remove nearly head, index=" + index);
            Node p = dummyHead;
            for (int i = 0; i < index; i++) {
                p = p.next;
            }
            retNode = p.next;
            p.next = retNode.next;
            retNode.next.prev = p;
//            retNode.next = null;//可以注释掉, java 有垃圾回收机制
//            retNode.prev = null;//可以注释掉, java 有垃圾回收机制
        } else {
            System.out.println("remove nearly tail, index=" + index);
            Node p = dummyTail;
            for (int i = size - 1; i >= index; i--) {
                p = p.prev;
            }
            retNode = p;
            retNode.prev.next = p.next;
            retNode.next.prev = p.prev;
//            retNode.next = null;//可以注释掉, java 有垃圾回收机制
//            retNode.prev = null;//可以注释掉, java 有垃圾回收机制
        }

        size--;
        return retNode.e;
    }

    public E removeFirst() {
        return remove(0);
    }

    public E removeLast() {
        return remove(size - 1);
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(String.format("linked list size: %d,  \n", getSize()));
        sb.append("head->");
        Node p = dummyHead.next;

        //遍历方式一
        for (int i = 0; i < size; i++) {
            sb.append(p.e + "->");
            p = p.next;
        }
        //遍历方式二
        /*while (p != dummyTail) {
            sb.append(p.e + "->");
            p = p.next;
        }*/
        sb.append("tail");
        return sb.toString();
    }

}

测试

public static void main(String[] args) {
    MyLinkedList3 linkedList = new MyLinkedList3<>();
    for (int i = 0; i < 5; i++) {
        linkedList.addFirst(i*20);
    }
    System.out.println(linkedList);
    System.out.println();

    System.out.println("------add------");
//        linkedList.add(2, 33);
    linkedList.add(3, 33);
    linkedList.addLast( 77);
    System.out.println(linkedList);
    linkedList.add( 5, 999);
    System.out.println(linkedList);
    System.out.println();

    System.out.println("-----remove-----");
    linkedList.remove(5);
    System.out.println(linkedList);
    linkedList.removeFirst();
    System.out.println(linkedList);
    linkedList.removeLast();
    System.out.println(linkedList);
    System.out.println();
//
    System.out.println("-----get-----");
    System.out.println(linkedList.get(2));
    System.out.println(linkedList.getFirst());
    System.out.println(linkedList.getLast());
    System.out.println();

    System.out.println("-----reverse recursion------");
    MyLinkedList3.Node tail = linkedList.dummyTail.prev;
    StringBuilder sb = new StringBuilder();
    sb.append("tail->");
    while (tail != linkedList.dummyHead) {
        sb.append(tail.e + "->" );
        tail = tail.prev;
    }
    sb.append("head");
    System.out.println(sb);
}

输出:

add nearly head, index=0
add nearly head, index=0
add nearly head, index=0
add nearly head, index=0
add nearly head, index=0
linked list size: 5,  
head->80->60->40->20->0->tail

------add------
add nearly tail, index=3
add nearly tail, index=6
linked list size: 7,  
head->80->60->40->33->20->0->77->tail
add nearly tail, index=5
linked list size: 8,  
head->80->60->40->33->20->999->0->77->tail

-----remove-----
remove nearly tail, index=5
linked list size: 7,  
head->80->60->40->33->20->0->77->tail
remove nearly head, index=0
linked list size: 6,  
head->60->40->33->20->0->77->tail
remove nearly tail, index=5
linked list size: 5,  
head->60->40->33->20->0->tail

-----get-----
get nearly head, index=2
33
get nearly head, index=0
60
get nearly tail, index=4
0

-----reverse recursion------
tail->0->20->33->40->60->head

你可能感兴趣的:(数据结构和算法)