遍历和递归实现双向链表反转

面试中经常问到双向链表的反转问题,下面参考《数据结构与算法分析》给出个LinkedList实现,同时讨论双向链表的反转实现。

public class LinkedList<E> {
    private Node<E> head;
    private Node<E> foot;
    private int modCount;
    private int size;

    public LinkedList() {
        clear();
    }

    private void clear() {
        head = new Node<E>(null, null, null);
        foot = new Node<E>(null, head, null);
        head.next = foot;
        modCount++;
        size = 0;
    }

    public int size() {
        return size;
    }

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

    private void addBefore(int index, E e) {
        Node<E> node = getNode(index);
        Node<E> newNode = new Node<E>(e, node.prev, node);
        node.prev.next = newNode;
        node.prev = newNode;
        size++;
        modCount++;
    }

    private Node<E> getNode(int index) {
        return getNode(index, 0, size());
    }

    private Node<E> getNode(int index, int lower, int upper) {
        Node<E> pNode;
        if (index < lower || index > upper) {
            throw new ArrayIndexOutOfBoundsException();
        }
        if (index < size() / 2) {
            pNode = head.next;
            for (int i = 0; i < index; i++) {
                pNode = pNode.next;
            }
        } else {
            pNode = foot;
            for (int i = size(); i > index; i--) {
                pNode = pNode.prev;
            }
        }
        return pNode;
    }

    public void remove(int index) {
        remove(getNode(index));
    }

    private void remove(Node<E> node) {
        node.prev.next = node.next;
        node.next.prev = node.prev;
        size--;
        modCount++;
    }

    public E set(int index, E e) {
        Node<E> node = getNode(index);
        E oldValue = node.element;
        node.element = e;
        return oldValue;
    }

    public E get(int index) {
        return getNode(index).element;
    }

    private static class Node<E> {
        Node<E> prev;
        Node<E> next;
        E element;

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

LinkedList 中分别保存了头节点head和尾节点foot,现在讨论一下如何实现反转。

如何反转

图解一下反转过程,如下图:
这里写图片描述
反转链表需要两个指针向前推进,同时记录第三个节点。由于我们的链表结构是带有头节点和尾节点的,所以需要特殊处理一下头尾部节点。

方法一 循环遍历法

要实现反转,我们就要反转每一个Nodenextprev 的指向。

    /**
     * 循环遍历实现反转
     */
    public void reverse1() {
        Node<E> cur = head.next;
        //第一个节点反转后next指向foot
        Node<E> pre = foot;
        while (cur != foot) {
            Node<E> temp = cur;
            //cur指针后移,记录下一个节点
            cur = cur.next;
            //反转
            temp.next = pre;
            pre.prev = temp;
            //pre指针后移
            pre = temp;
        }
        pre.prev = head;
        head.next = pre;
    }

方法二 递归法

    /**
     * 递归实现反转
     */
    public void reverse2() {
        Node<E> temp = reverse(head.next);

        head.next.next = foot;
        foot.prev = head.next;

        head.next = temp;
        temp.prev = head;
    }

    private Node<E> reverse(Node<E> cur) {
        if (cur == null || cur.next == foot) {
            return cur;
        }
        //反转后的头指针(foot的prev)
        Node<E> tail = reverse(cur.next);
        //反转,和循环遍历思想一致
        cur.next.next = cur;
        cur.prev = cur.next;
        return tail;
    }

猜你喜欢

转载自blog.csdn.net/momo_ibeike/article/details/79384171