這次介紹經常在面試中被問到的單向鏈表的反轉問題,問題的解決方法有多種
- 最普通的是從頭到尾掃描鏈表,然后對鏈表進行反轉。
- 使用單個參數的遞歸方法;使用單個參數是相當於不斷的往鏈表后部深入,並且在每次深入的遞歸中保存了下一個節點和當前節點的信息,再調用遞歸后處理當前節點和下一個節點的關系;其中比較有特點的處理過程是返回值的處理,每次遞歸后返回的指針為同一個;
- 使用兩個參數的遞歸方法,外加一個當前鏈表頭節點的前一個結點的指針,在進一步遞歸之前處理好頭節點和其前一個節點的關系。
1 #include <iostream> 2 #include <string> 3 using namespace std; 4 struct Node{ 5 int value; 6 Node* next; 7 }; 8 9 //使用非遞歸的鏈表反轉方法 10 Node* ReverseList1(Node *Ptr) 11 { 12 Node *pre = NULL; 13 Node *Current = Ptr; 14 Node *pnext = NULL; 15 while ( Current != NULL){ 16 pnext = Current->next; 17 Current->next = pre; 18 pre = Current; 19 Current = pnext; 20 } 21 return pre; 22 } 23 // 一個參數的遞歸反轉方法 24 // 將當前節點的下一個節點保存好,並將當前節點從鏈表中取出,再遞歸處理以后的鏈表 25 // 同時reverseRest沒有改變,一直保存了鏈表的最后一個節點的指針 26 Node* ReverseList2(Node *ptr){ 27 if (ptr->next == NULL) 28 return ptr; 29 Node *nextNode = ptr-> next; 30 ptr->next = NULL; 31 Node *reverseRest = ReverseList2(nextNode); 32 nextNode->next = ptr; 33 return reverseRest; 34 35 36 } 37 38 // 遞歸實現2:兩個參數的遞歸調用方法 39 // 傳遞一個當前鏈表頭節點的前一個節點的指針,在函數中將當前頭節點的next改為其前一個節點,並遞歸調用 40 Node* ReverseList3(Node *ptr, Node *pre){ 41 if (ptr->next == NULL){ 42 ptr->next = pre; 43 return ptr; 44 } 45 else{ 46 Node *next = ptr->next; 47 ptr->next = pre; 48 ReverseList3(next, ptr); 49 } 50 } 51 52 53 void printList(Node *Ptr){ 54 Node * Current = Ptr; 55 while (Current != NULL){ 56 cout << Current->value << " "; 57 Current = Current->next; 58 } 59 cout << endl; 60 } 61 62 int main(){ 63 Node *head = NULL; 64 65 for (int i = 9; i > 0; i--){ 66 Node *p = new Node; 67 p->next = head; 68 p->value = i; 69 head = p; 70 } 71 cout << "The Lsit:" << endl; 72 printList(head); 73 74 head = ReverseList1(head); 75 cout << "After reverseList1():" << endl; 76 printList(head); 77 78 79 head = ReverseList2(head); 80 cout << "After reverseList2():" << endl; 81 printList(head); 82 83 Node * tmp = NULL; 84 head = ReverseList3(head, tmp); 85 cout << "After reverseList3():" << endl; 86 printList(head); 87 88 return 1; 89 90 }