蘋果 macOS Monterey 12.2 Beta 釋出,重構 Apple Music :效能更強更流暢
阿新 • • 發佈:2021-12-17
遞迴反轉
本文介紹遞迴反轉單鏈表,和之前的迴圈遍歷反轉單鏈表方式略有不同,遞迴的方式要寫出推到遞迴公式。並且在遞迴的同時修改指標的指向。
先定義Node節點
class Node
{
public:
Node(int dt, Node *nt = nullptr) : data(dt), next(nt) {}
Node() = default;
int data;
Node *next;
};
Node節點構成的連結串列如下圖
基本思路是實現recursive_reverse函式
Node* recursive_reverse(Node* p){ //判斷p為空或者是單節點直接返回 if(p == nullptr || p->next==nullptr){ return ; } //遞迴查詢,直到返回隊尾元素作為頭節點 //否則繼續遞迴處理下一個節點 auto nextnode = recursive_reverse(p->next); return nextnode; }
上述程式碼最終會將連結串列的尾節點返回。但是我們沒有完成連結串列的逆轉,需要改變連結串列節點Node的next指標。
假設有兩個節點
node1節點為p節點
p->next
指向的就是node2節點
p->next->next
指向的就是末尾的空指標。
所以當有兩個節點的時候我們可以如下操作完成p和p->next
兩個節點指向的修改,也就是node1和node2兩個節點的修改。
我們將p->next->next = p->next
就是將node2的next指向了node1.
我們將p->next = nullptr
就是將node1->next
而之前的遞迴保證了最後返回的是node2節點,此時node2節點就作為頭節點,從而完成了逆轉。
圖解為下圖
這是兩個節點的情況,如果是三個節點呢,那就依次類推,依次完成
node3->next
指向node2,node2->next
指向node1,node1->next
指向空地址。所以n>=2的情況都是和兩個節點類似的,那麼我們補全recursive_reverse函式
Node *recursive_reverse(Node *p) { //如果連結串列為空或者為單節點,直接返回 if (p == nullptr || p->next == nullptr) { return p; } //否則繼續遞迴處理下一個節點 auto nextnode = recursive_reverse(p->next); //改變p的下一個節點next指向,連結串列逆轉 p->next->next = p; //改變p的next指向 p->next = nullptr; return nextnode; }
接下來我們實現一個建立連結串列的函式用來測試
Node *createList()
{
auto node1 = new Node(1);
auto node2 = new Node(2);
auto node3 = new Node(3);
node1->next = node2;
node2->next = node3;
return node1;
}
然後實現銷燬連結串列回收記憶體的函式
void delocateList(Node *p)
{
while (p != nullptr)
{
auto temp = p;
p = p->next;
delete temp;
}
}
然後實現列印節點的函式
void printList(Node *p)
{
while (p != nullptr)
{
cout << p->data << " -> ";
p = p->next;
}
cout << " nullptr " << endl;
}
最後我們在main函式中測試
auto list = createList();
printList(list);
list = recursive_reverse(list);
printList(list);
delocateList(list);
程式輸出如下
1 -> 2 -> 3 -> nullptr
3 -> 2 -> 1 -> nullptr
可以看到連結串列被逆轉了。
原始碼連結https://gitee.com/secondtonone1/algorithms
我的公眾號,謝謝關注