反轉單鏈表II

原題

  Reverse a linked list from position m to n. Do it in-place and in one-pass.
  For example:
  Given 1->2->3->4->5->NULL, m = 2 and n = 4,
  return 1->4->3->2->5->NULL.
  Note:
  Given m, n satisfy the following condition:
  1 ≤ m ≤ n ≤ length of list.java

題目大意

  給定一個單鏈表,將第m到第n個之間的元素進行轉。
  給定的n和m都是合法的,使用原地方法進行解決(使用常量輔助空間)node

解題思路

  先找到第一個要反轉的元素的前驅(prev),再計算要進行反轉的元素個數,對元素進行頭插法,插在prev後面,同時保持鏈表不斷開。算法

代碼實現

鏈表結點類緩存

public class ListNode {
    int val;
    ListNode next;
    ListNode(int x) { val = x; }
}

 

算法實現類app

public class Solution {
    public ListNode reverseBetween(ListNode head, int m, int n) {

        ListNode root = new ListNode(0);
        ListNode p = root;
        root.next = head;

        for (int i = 1; i < m && p != null; i++) {
            p = p.next;
        }

        if (p != null) {
            ListNode q = p.next;
            ListNode r;

            // 若是m爲負數就認爲是從第一個開始交換
            if (m < 1) {
                m = 1;
            }

            n = n - m + 1; // n爲要換的結點數目
            // 有兩個結點時纔要使用尾插法,尾插的個數爲n-1
            for (int i = 1; i < n && q.next != null ; i++) {
                // 爲要進行尾插的結點
                r = q.next;

               // 在q結點的後面進行尾插操做 
                q.next = r.next;
                r.next = p.next;
                p.next = r;
            }

            head = root.next;
        }

        return head;
    }
}

 

問題:this

給一個單向鏈表,把它從頭至尾反轉過來。好比: a -> b -> c ->d 反過來就是 d -> c -> b -> a 。spa

分析:.net

假設每個node的結構是:指針

 

[java] view plain copycode

 

  1. class Node {  
  2.     char value;  
  3.     Node next;  
  4. }  

 

由於在對鏈表進行反轉的時候,須要更新每個node的「next」值,可是,在更新 next 的值前,咱們須要保存 next 的值,不然咱們沒法繼續。因此,咱們須要兩個指針分別指向前一個節點和後一個節點,每次作完當前節點「next」值更新後,把兩個節點往下移,直到到達最後節點。

代碼以下:

 

[java] view plain copy

 

  1. public Node reverse(Node current) {  
  2.     //initialization  
  3.     Node previousNode = null;  
  4.     Node nextNode = null;  
  5.       
  6.     while (current != null) {  
  7.         //save the next node  
  8.         nextNode = current.next;  
  9.         //update the value of "next"  
  10.         current.next = previousNode;  
  11.         //shift the pointers  
  12.         previousNode = current;  
  13.         current = nextNode;           
  14.     }  
  15.     return previousNode;  
  16. }  


上面代碼使用的是非遞歸方式,這個問題也能夠經過遞歸的方式解決。代碼以下:

 

 

[java] view plain copy

 

  1. public Node reverse(Node current)  
  2.  {  
  3.      if (current == null || current.next == null) return current;  
  4.      Node nextNode = current.next;  
  5.      current.next = null;  
  6.      Node reverseRest = reverse(nextNode);  
  7.      nextNode.next = current;  
  8.      return reverseRest;  
  9.  }  

遞歸的方法實際上是很是巧的,它利用遞歸走到鏈表的末端,而後再更新每個node的next 值 (代碼倒數第二句)。 在上面的代碼中, reverseRest 的值沒有改變,爲該鏈表的最後一個node,因此,反轉後,咱們能夠獲得新鏈表的head。

 

 

(一)單鏈表的結點結構: 

      data域:存儲數據元素信息的域稱爲數據域; 
    next域:存儲直接後繼位置的域稱爲指針域,它是存放結點的直接後繼的地址(位置)的指針域(鏈域)。
    data域+ next域:組成數據ai的存儲映射,稱爲結點

    注意:①鏈表經過每一個結點的鏈域將線性表的n個結點按其邏輯順序連接在一塊兒的。   
          ②每一個結點只有一個鏈域的鏈表稱爲單鏈表(Single Linked List)。
     所謂的鏈表就好像火車車箱同樣,從火車頭開始,每一節車箱以後都連着後一節車箱。
     要實現單鏈表存儲,首先是建立一結點類,其Java代碼以下:

[java] view plain copy

在CODE上查看代碼片派生到個人代碼片

  1. class Node {  
  2.     private int Data;// 數據域  
  3.     private Node Next;// 指針域  
  4.     public Node(int Data) {  
  5.         // super();  
  6.         this.Data = Data;  
  7.     }  
  8.     public int getData() {  
  9.         return Data;  
  10.     }  
  11.     public void setData(int Data) {  
  12.         this.Data = Data;  
  13.     }  
  14.   
  15.     public Node getNext() {  
  16.         return Next;  
  17.     }  
  18.     public void setNext(Node Next) {  
  19.         this.Next = Next;  
  20.     }  
  21. }  

(二)實現反轉的方法:
  (1)遞歸反轉法
:在反轉當前節點以前先反轉後續節點。這樣從頭結點開始,層層深刻直到尾結點纔開始反轉指針域的指向。簡單的說就是從尾結點開始,逆向反轉各個結點的指針域指向,其過程圖以下所示:
   head:是前一結點的指針域(PS:前一結點的指針域指向當前結點)
   head.getNext():是當前結點的指針域(PS:當前結點的指針域指向下一結點)
   reHead:是反轉後新鏈表的頭結點(即原來單鏈表的尾結點)

Java代碼實現:

[java] view plain copy

在CODE上查看代碼片派生到個人代碼片

  1. package javatest1;  
  2. public class javatest1 {  
  3.     public static void main(String[] args) {  
  4.         Node head = new Node(0);  
  5.         Node node1 = new Node(1);  
  6.         Node node2 = new Node(2);  
  7.         Node node3 = new Node(3);  
  8.         head.setNext(node1);  
  9.         node1.setNext(node2);  
  10.         node2.setNext(node3);  
  11.   
  12.         // 打印反轉前的鏈表  
  13.         Node h = head;  
  14.         while (null != h) {  
  15.             System.out.print(h.getData() + " ");  
  16.             h = h.getNext();  
  17.         }  
  18.         // 調用反轉方法  
  19.         head = Reverse1(head);  
  20.   
  21.         System.out.println("\n**************************");  
  22.         // 打印反轉後的結果  
  23.         while (null != head) {  
  24.             System.out.print(head.getData() + " ");  
  25.             head = head.getNext();  
  26.         }  
  27.     }  
  28.   
  29.     /** 
  30.      * 遞歸,在反轉當前節點以前先反轉後續節點 
  31.      */  
  32.     public static Node Reverse1(Node head) {  
  33.         // head看做是前一結點,head.getNext()是當前結點,reHead是反轉後新鏈表的頭結點  
  34.         if (head == null || head.getNext() == null) {  
  35.             return head;// 若爲空鏈或者當前結點在尾結點,則直接還回  
  36.         }  
  37.         Node reHead = Reverse1(head.getNext());// 先反轉後續節點head.getNext()  
  38.         head.getNext().setNext(head);// 將當前結點的指針域指向前一結點  
  39.         head.setNext(null);// 前一結點的指針域令爲null;  
  40.         return reHead;// 反轉後新鏈表的頭結點  
  41.     }  
  42. }  
  43.   
  44.     class Node {  
  45.         private int Data;// 數據域  
  46.         private Node Next;// 指針域  
  47.   
  48.         public Node(int Data) {  
  49.             // super();  
  50.             this.Data = Data;  
  51.         }  
  52.   
  53.         public int getData() {  
  54.             return Data;  
  55.         }  
  56.   
  57.         public void setData(int Data) {  
  58.             this.Data = Data;  
  59.         }  
  60.   
  61.         public Node getNext() {  
  62.             return Next;  
  63.         }  
  64.   
  65.         public void setNext(Node Next) {  
  66.             this.Next = Next;  
  67.         }  
  68.     }  

 

(2)遍歷反轉法:遞歸反轉法是從後往前逆序反轉指針域的指向,而遍歷反轉法是從前日後反轉各個結點的指針域的指向。

   基本思路是:將當前節點cur的下一個節點 cur.getNext()緩存到temp後,而後更改當前節點指針指向上一結點pre。也就是說在反轉當前結點指針指向前,先把當前結點的指針域用tmp臨時保存,以便下一次使用,其過程可表示以下:
   pre:上一結點
   cur: 當前結點
   tmp: 臨時結點,用於保存當前結點的指針域(即下一結點)

 

Java代碼實現:

[java] view plain copy

在CODE上查看代碼片派生到個人代碼片

  1. package javatest1;  
  2. public class JavaTest1 {  
  3.     public static void main(String[] args) {  
  4.         Node head = new Node(0);  
  5.         Node node1 = new Node(1);  
  6.         Node node2 = new Node(2);  
  7.         Node node3 = new Node(3);  
  8.   
  9.         head.setNext(node1);  
  10.         node1.setNext(node2);  
  11.         node2.setNext(node3);  
  12.   
  13.         // 打印反轉前的鏈表  
  14.         Node h = head;  
  15.         while (null != h) {  
  16.             System.out.print(h.getData() + " ");  
  17.             h = h.getNext();  
  18.         }  
  19.         // 調用反轉方法  
  20.         // head = reverse1(head);  
  21.         head = reverse2(head);  
  22.   
  23.         System.out.println("\n**************************");  
  24.         // 打印反轉後的結果  
  25.         while (null != head) {  
  26.             System.out.print(head.getData() + " ");  
  27.             head = head.getNext();  
  28.         }  
  29.     }  
  30.   
  31.     /** 
  32.      * 遍歷,將當前節點的下一個節點緩存後更改當前節點指針 
  33.      */  
  34.     public static Node reverse2(Node head) {  
  35.         if (head == null)  
  36.             return head;  
  37.         Node pre = head;// 上一結點  
  38.         Node cur = head.getNext();// 當前結點  
  39.         Node tmp;// 臨時結點,用於保存當前結點的指針域(即下一結點)  
  40.         while (cur != null) {// 當前結點爲null,說明位於尾結點  
  41.             tmp = cur.getNext();  
  42.             cur.setNext(pre);// 反轉指針域的指向  
  43.   
  44.             // 指針往下移動  
  45.             pre = cur;  
  46.             cur = tmp;  
  47.         }  
  48.         // 最後將原鏈表的頭節點的指針域置爲null,還回新鏈表的頭結點,即原鏈表的尾結點  
  49.         head.setNext(null);  
  50.           
  51.         return pre;  
  52.     }  
  53. }  
  54.   
  55. class Node {  
  56.     private int Data;// 數據域  
  57.     private Node Next;// 指針域  
  58.   
  59.     public Node(int Data) {  
  60.         // super();  
  61.         this.Data = Data;  
  62.     }  
  63.   
  64.     public int getData() {  
  65.         return Data;  
  66.     }  
  67.   
  68.     public void setData(int Data) {  
  69.         this.Data = Data;  
  70.     }  
  71.   
  72.     public Node getNext() {  
  73.         return Next;  
  74.     }  
  75.   
  76.     public void setNext(Node Next) {  
  77.         this.Next = Next;  
  78.     }  
  79. }  
相關文章
相關標籤/搜索