鏈表的反轉

import java.util.ArrayList;
import java.util.Stack;

    /**
     * 鏈表的反轉
     */
public class ReverseLinkedList {

/**
 * 非遞歸地反轉鏈表:
 *
 *  特色:沒有進行節點間的兩兩反轉,而是採用依次插入到新鏈表的方式來實現反轉。
 *
 *  過程:遍歷一次鏈表,將遍歷的節點依次插入到新鏈表的頭部便可實現鏈表的反轉。
 *
 *  複雜度:時間複雜度爲O(N),輔助的空間複雜度爲O(1)
 *
 * [@param](https://my.oschina.net/u/2303379) head
 *
 * [@return](https://my.oschina.net/u/556800) 將反轉後的新鏈表的頭節點返回。
 */
public static Node reverseByInsertToNewList(Node head) {

    Node current = head; // 正在遍歷的節點
    Node next = null;    // 下一個要遍歷的節點
    Node newHead = null; // 新鏈表頭節點的引用(指向新鏈表頭節點的指針)

    while (null != current) {

        next = current.next; // 將下一個要遍歷的節點暫存起來

        /**
         * 將當前節點放到新鏈表的頭部:
         *    1>將當前節點指向新鏈表的頭部
         *    2>更新newHead
         */
        current.next = newHead;
        newHead = current;

        current = next; // 向後繼續遍歷
    }

    return newHead;
}


/**
 * 遞歸地反轉鏈表:
 *
 *  特色:從後往前兩兩反轉。
 *
 *  過程:遞歸地將當前節點(current)和它的後繼節點(current.next)反轉。
 *
 *  注意:
 *      1)最後一個節點沒有後繼節點,故最後一個節點不須要進行反轉操做,只需將最後一個節點(做爲新鏈表的頭節點)直接返回便可。
 *      2)當前節點爲鏈表倒數第二個節點時,開始第一次的反轉操做。
 *      3)每次的反轉操做都不會對新鏈表的頭節點形成影響,只是將新的頭結點返回而已。
 *
 *  解析:
 *      1)將 A->B->C->D 反轉的操做能夠分爲:
 *          1>將 C->D 反轉 ==> A->B->C  D->C->null
 *          2>將 B->C 反轉 ==> A->B     D->C->B->null
 *          3>將 A->B 反轉 ==>          D->C->B->A->null
 *
 *      2)將 A->B 反轉的操做:
 *          1>將B的後繼節點指向A,      即 B.next = A    即 A.next.next = A
 *          2>將A的後繼節點設爲null,   即 A.next = null
 *
 * [@param](https://my.oschina.net/u/2303379) current
 *
 * [@return](https://my.oschina.net/u/556800) 將反轉後的新鏈表的頭節點返回。
 */
private static Node reverseByRecursion(Node current) {

    if (null == current) {      // 若該鏈表爲空鏈表,則直接返回
        return current;
    }

    if (null == current.next) { // 當前結點是尾結點時,直接返回。注:鏈表的尾節點即新鏈表的頭節點
        return current;
    }

    Node newHead = reverseByRecursion(current.next); // newHead是鏈表的尾節點,即新鏈表的頭節點。

    // 反轉操做:將current和current.next進行反轉,即:將當前節點放到新鏈表的尾部,故在遞歸的過程當中新鏈表的頭部不會變。
    current.next.next = current;
    current.next = null;

    // 將新鏈表的頭節點返回。
    return newHead;
}


// -------

/**
 * 利用棧的先進後出特性來完成鏈表的反轉。
 *
 * 時間複雜度爲O(N),輔助的空間複雜度也爲O(N)
 *
 * [@param](https://my.oschina.net/u/2303379) head
 * @return 將反轉後的新鏈表的頭節點返回。
 */
public static Node reverseWithStack(Node head) {

    Stack<Node> stack = new Stack<Node>();
    while (null != head) {
        stack.push(head);
        head = head.next;
    }
    return stack.peek();
}


/**
 * 反轉雙向鏈表
 *
 *  複雜度:時間複雜度爲O(N),輔助的空間複雜度爲O(1)
 *
 * @param head
 * @return 將反轉後的新鏈表的頭節點返回。
 */
public static Node reverseBidirectionalList(Node head) {

    if (null == head) { // 若該鏈表爲空鏈表,則直接返回
        return null;
    }

    Node current = head;
    Node next = null;
    Node newHead = null;

    while (null != current) {

        // 反轉
        next = current.next;    // 將當前節點的後繼節點暫存起來
        current.next = current.prev;
        current.prev = next;

        if (null == next) {     // 若下一個要遍歷的節點爲null,則說明已經到達鏈表的尾部,此時current即鏈表的尾節點
            newHead = current;
        }

        current = next;         // 繼續向後遍歷
    }

    return newHead;
}


// -------

/**
 * 將鏈表從頭至尾依次打印出來
 *
 * @param head
 */
public static void print(Node head) {

    ArrayList<Object> list = new ArrayList<>();
    while (null != head.next) {
        list.add(head.value);
        head = head.next;
    }
    list.add(head.value);
    System.out.println(list.toString());
}

/**
 * 將雙向鏈表從尾到頭依次打印出來
 *
 * @param tail
 */
public static void printBidirectionList(Node tail) {

    ArrayList<Object> list = new ArrayList<>();
    while (null != tail.prev) {
        list.add(tail.value);
        tail = tail.prev;
    }
    list.add(tail.value);
    System.out.println(list.toString());
}

/**
 * 初始化鏈表
 *
 * @return
 */
public static Node init() {

    Node head = new Node(5);
    Node node1 = new Node(3);
    Node node2 = new Node(2);
    Node node3 = new Node(6);
    Node node4 = new Node(7);
    Node node5 = new Node(17);
    Node node6 = new Node(9);

    head.next = node1;

    node1.prev = head;
    node1.next = node2;

    node2.prev = node1;
    node2.next = node3;

    node3.prev = node2;
    node3.next = node4;

    node4.prev = node3;
    node4.next = node5;

    node5.prev = node4;
    node5.next = node6;

    node6.prev = node5;
    node6.next = null;
    return head;
}


public static void main(String[] args) {

    Node head = init();
    print(head);

    // 反轉單向鏈表
//        Node newHead = reverseByInsertToNewList(head);
//        Node newHead = reverseByRecursion(head);

    // 反轉雙向鏈表
    Node newHead = reverseBidirectionalList(head);

    print(newHead);

    // 利用stack反轉雙向鏈表
    Node newHeadByStack = reverseWithStack(head);
    printBidirectionList(newHeadByStack);

}

}java

相關文章
相關標籤/搜索