java 双向链表的实现 及反转双向链表

双向链表,顾名思义,就是每个节点都有两个指针,分别指向当前节点的前一个节点及后一个节点。

下面给出具体实现:


import java.util.StringJoiner;

class LinkedList<Z> {

    private static class Node<Z> {
        Z data;
        Node<Z> next;
        Node<Z> prev;
    }

    private final Node<Z> head;
    private final Node<Z> tail;
    private int length = 0;

    LinkedList() {
        this.head = new Node<>();
        this.tail = new Node<>();

        head.next = tail;
        head.prev = null;
        tail.next = null;
        tail.prev = head;
    }

    public int size() {
        return length;
    }

    public boolean addFirst(Z data) {
        return insert(0, data);
    }

    public boolean addLast(Z data) {
        return insert(length, data);
    }

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

    public boolean removeLast() {
        return remove(length - 1);
    }

    public boolean remove(Z data) {
        return remove(indexOf(data));
    }

    public void reverse() {
        if (head.next == tail) {
            return;
        }
        // _ 2 3 4 5 6 _
        Node<Z> rh = new Node<>();
        rh.next = tail;
        Node<Z> cur = head.next;
        Node<Z> cn;
        while (cur != tail) {
            cn = cur.next;
            cur.next = rh.next;
            rh.next.prev = cur;
            cur.prev = rh;
            rh.next = cur;
            cur = cn;
        }
        rh.next.prev = head;
        head.next = rh.next;
    }

    public Z get(int index) {
        if (index < 0 || index >= length) {
            return null;
        }
        int pos = -1;
        Node<Z> h = head;
        while (h.next != tail) {
            h = h.next;
            pos++;
            if (index == pos) {
                break;
            }
        }
        return h.data;
    }

    public int indexOf(Z data) {
        if (length == 0 || data == null) {
            return -1;
        }
        boolean found = false;
        int pos = -1;
        Node<Z> h = head;
        while (h.next != tail) {
            h = h.next;
            pos++;
            if (data.equals(h.data)) {
                found = true;
                break;
            }
        }
        return found ? pos : -1;
    }

    public int lastIndexOf(Z data) {
        if (length == 0 || data == null) {
            return -1;
        }

        int pos = length - 1;
        Node<Z> t = tail.prev;
        while (t != head) {
            if (data.equals(t.data)) {
                break;
            }
            t = t.prev;
            pos--;
        }
        // if (pos == -1) { return -1; }
        return pos;
    }

    public boolean insert(int index, Z data) {
        if (index < 0 || index > length || data == null) {
            return false;
        }
        // _ 4 [k] 7 _
        // _ 3 5 4 1  [9] _
        // _ 8 [x] _
        // _ [x] 3 _
        int pos = -1;
        Node<Z> h = head;
        while (h.next != tail) {
            if (index - 1 == pos) {
                break;
            }
            pos++;
            h = h.next;
        }
        // now, let data's node as the next of h;
        Node<Z> originNext = h.next;

        Node<Z> item = new Node<>();
        item.data = data;
        item.next = originNext;
        item.prev = h;
        originNext.prev = item;
        h.next = item;
        length++;

        return true;
    }

    public boolean remove(int index) {
        if (length == 0 || index < 0 || index >= length) {
            return false;
        }
        int pos = -1;
        Node<Z> h = head;
        while (h.next != tail) {
            h = h.next;
            pos++;
            if (index == pos) {
                break;
            }
        }
        // now h is the target node, which is going to del;
        h.prev.next = h.next;
        h.next.prev = h.prev;
        length--;
        return true;
    }

    public void clear() {
        while (size() > 0) {
            removeFirst();
        }
    }

    private String format(boolean hasIndex) {
        StringBuilder sb = new StringBuilder("{ ");
        int pos = -1;
        Node<Z> h = head;
        while (h.next != tail) {
            h = h.next;
            pos++;
            if (pos == length) {
                continue;
            }
            if (hasIndex) {
                sb.append("[").append(pos).append("]-> ");
            }
            sb.append(h.data).append(", ");
        }

        int last = sb.lastIndexOf(", ");
        if (last != -1) {
            sb.delete(last, last + 2);
        }
        sb.append(" }");
        return sb.toString().replaceAll(" {2}", "");
    }

    @Override
    public String toString() {
        return new StringJoiner(", ",
                LinkedList.class.getSimpleName() + "[", "]")
                .add("length=" + length)
                .add("data=" + format(false))
                .toString();
    }

}

这里整体的实现思路是,定义头结点及尾结点作为标记,然后进行数据结点的增删改查。

然后说一下双向链表的反转:

    public void reverse() {
        if (head.next == tail) {
            return;
        }
        // _ 2 3 4 5 6 _
        Node<Z> rh = new Node<>();
        rh.next = tail;
        Node<Z> cur = head.next;
        Node<Z> cn;
        while (cur != tail) {
            cn = cur.next;
            cur.next = rh.next;
            rh.next.prev = cur;
            cur.prev = rh;
            rh.next = cur;
            cur = cn;
        }
        rh.next.prev = head;
        head.next = rh.next;
    }

这里的反转思路其实跟单链表的反转思路是一样的。

详见 java 单链表实现 及 反转单链表

也是通过从头结点开始遍历这个链表,然后把取到的每个数据结点插入到临时头结点的后面;在遍历中不断去把取到的数据节点一直插入到同一个位置,就得到了一个由这个临时头结点链接的链表,然后再把当前链表的头结点关联到这个临时头结点的首个元素节点即可。

说一下反转的思路误区:

  • 既然这个链表是双向的了,直接把头结点当成尾节点,尾节点当成头结点不就直接反转了吗?

从逻辑上看,这样确实就算是反转了。但是要注意,那么对于每个数据节点,之前的prevnext 的含义也正好相反了。那在执行遍历等操作的时候,就要反过来执行了。就是这样会影响到其他操作的内部实现。 为了避免对其他操作的影响,重新排列节点的位置会好一点。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值