您的位置:首页 > 其它

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

2018-02-27 10:44 417 查看
面试中经常问到双向链表的反转问题,下面参考《数据结构与算法分析》给出个
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
,现在讨论一下如何实现反转。

如何反转

图解一下反转过程,如下图:



反转链表需要两个指针向前推进,同时记录第三个节点。由于我们的链表结构是带有头节点和尾节点的,所以需要特殊处理一下头尾部节点。

方法一 循环遍历法

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

/**
* 循环遍历实现反转
*/
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: