遞迴再一次讓哥震驚了

2022-02-27 03:21:23 字數 4220 閱讀 9033

遞迴再一次讓哥震驚了

先說那兩個讓哥震驚的遞迴問題:

1:用遞迴實現單鏈表的倒序輸出

2:從二叉查詢樹中刪除節點,並保證還是二叉查詢樹

同學們可以開始思考這兩個問題了,當然你可能n年前就遇到過這兩個問題,那麼不妨看看,看你是否真的理解了遞迴。實現這兩個問題的**當然很簡單,就在下面。

剛開始學習的遞迴的時候,覺得他好強大,實現某些功能不用遞迴可能要幾十行**,用遞迴可能幾行就搞定了,而且**清晰簡潔。一直以為遞迴也就是自己呼叫自己,有乙個出口條件,讓他停止遞迴,退出函式,其實的特點並非就這些。

遞迴還有乙個非常重要的特點:先進後出,跟棧類似,先遞進去的後遞出來。由於遞迴一直在自己呼叫自己,有時候我們很難清楚的看出,他的返回值到底是哪個,只要你理解了先進後出這個特點,你就會明白,第一次呼叫時,作為返回值的那個變數的值就是遞迴函式的返回值。先進後出嗎,他是第乙個進來,也就是最後出去的那個,當然就是遞迴的返回值啦。

第乙個讓哥震驚的問題:用遞迴實現單鏈表的倒序輸出。

我前段時間寫過一篇部落格《四種方式實現--從尾到頭輸出鍊錶

》,其中一種方法就是用遞迴實現的,當時看見那位高人用遞迴實現了這個功能,哥被震住了,他怎麼可以這麼聰明,他的部落格真的是學演算法的好地方:**如下,這是我那篇部落格的原始碼:

//

用遞迴實現

//很誠實的說盜用了別人的思想,真的太妙了,完全能看出你是否真的體會了遞迴的原理

//正如那位哥們所說,遞迴就是乙個進棧出棧的過程,鍊錶前面的元素先進棧,在棧底,後面的元素後進棧,在棧頂,先出棧,哈哈。。。

void recursion(node* head)

if(head->next!=null)

//如果把這句放在第二個if前面,那就是從頭到尾輸出鍊錶,曾經的你或許是用while或者用for迴圈輸出鍊錶,現在你又多了一種方式

cout

\t";

}

這裡充分運用了遞迴的先進後出的特點。

最近在中看的一些部落格,發現有幾篇文章跟樹聯絡得比較緊,前天晚上,我於是把資料結構與演算法中樹的那一章溫習了一下,哥被二叉查詢樹刪除節點的演算法給震住了,因為我以前也寫過一篇關於二插查詢樹的部落格《演算法學習--二叉查詢樹

》,在這篇部落格中,刪除節點的那個演算法寫得很長,以至於叫我自己現在去看都不是很理解,今天會讓大家看到看到簡潔清晰的**,遞迴寫的嗎,哈哈哈!

先來c++版的吧,好久沒寫了,都生疏了:

view code

#include "

string.h

"#include

using

namespace std;

typedef struct treenode1

} treenode;

class adttree

//查詢指定節點下的最小節點

treenode* findmin(treenode *t)

else

if(t->left==null)

else}//

查詢最小節點

treenode* findmin()

//查詢指定節點下的節點

treenode* find(int element,treenode *t)

if(elementelement)

else

if(element>t->element)

else}//

查詢節點

treenode* find(int element)

//在指定節點下天驕節點

treenode* add(int element,treenode *t)

if(elementelement)

return add(element,t->left);

}else

if(element>t->element)

return add(element,t->right);

}return t;}//

天驕節點

treenode* add(int element)

else}//

刪除指定節點下節點

treenode* delete(int element,treenode *t)

else

if(elementelement)

else

if(element>t->element)

else

else

else

if(t->right==null)

delete tmpnode;}}

return t;}//

刪除節點

treenode* delete(int element)

};

在來c#版:

namespace utils

public treenode left

public treenode right

public treenode(int element)

}/// /// 二插查詢樹

///

public class adttree

public adttree(treenode node)

//根節點

private treenode root;

//新增節點(沒有檢查根節點是否為空,所以設為private)

private void addnode(int element, treenode node)

if (element < node.element)

else

}else if (element > node.element)

else}}

//新增節點

public void add(int element, treenode node)

else

}public void add(int element)

//查詢指定節點下的最小節點

public treenode findmin(treenode node)

if (node.left == null)

else

}//查詢最小節點

public treenode findmin()

//刪除指定節點下的節點

public treenode delete(int element, treenode node)

if (element < node.element)

else if (element > node.element)

else

else

else if (node.right == null)

else }}

return node;

}//刪除節點

public treenode delete(int element)

return delete(element,this.root);}}

}

現在我們重點來看看,刪除節點的演算法:

//刪除指定節點下的節點

public treenode delete(int element, treenode node)

if (element < node.element)

else if (element > node.element)

else

else

else if (node.right == null)

else }}

return node;

}

這裡的重點是怎麼處理,被刪除的那個節點有左右兩棵子樹,其他的都很好處理,處理方式是:

1:找到要刪除節點的右子樹的最小節點,用findmin這個方法就可以搞定;

2:將右子樹的最小節點取代當前刪除的節點,因為右子樹的最小節點比當前節點的左子樹中的所有節點都大,比右子樹的節點都小,它就是符合條件的那個節點來代替當前要刪除的節點

3:由於右子樹的最小節點取代了當前節點,所以要在右子樹中刪除這個最小節點,現在又轉換成同乙個問題,在一棵二叉查詢樹中刪除乙個節點,於是就遞迴咯。

我當時就是沒有想到這裡還可以用遞迴,寫了一堆自己現在都不是很懂的**。

第乙個問題讓我震驚是以前沒有理解遞迴的先進後出的思想,第二個是因為我沒有掌握問題轉換的思想,看似兩個不同的問題,其實是同乙個問題,當然解法也是一樣的,既然把兩個解法一樣的問題放在一起,用遞迴就再好不過了,他同時把你們搞定

部落格:

遞迴再一次讓哥震驚了

先說那兩個讓哥震驚的遞迴問題 1 用遞迴實現單鏈表的倒序輸出 2 從二叉查詢樹中刪除節點,並保證還是二叉查詢樹 同學們可以開始思考這兩個問題了,當然你可能n年前就遇到過這兩個問題,那麼不妨看看,看你是否真的理解了遞迴。實現這兩個問題的 當然很簡單,就在下面。剛開始學習的遞迴的時候,覺得他好強大,實現...

遞迴再一次讓哥震驚了

遞迴再一次讓哥震驚了 先說那兩個讓哥震驚的遞迴問題 1 用遞迴實現單鏈表的倒序輸出 2 從二叉查詢樹中刪除節點,並保證還是二叉查詢樹 同學們可以開始思考這兩個問題了,當然你可能n年前就遇到過這兩個問題,那麼不妨看看,看你是否真的理解了遞迴。實現這兩個問題的 當然很簡單,就在下面。剛開始學習的遞迴的時...

再一次求助

編24點程式時遇到的問題 大佬好呀,python小白又來求助啦!這次的問題是在編24點時遇到的乙個問題 如何將使用者輸入的數字運算出結果?源 import random shuzi str one str random.randint 1,10 shuzi str two str random.ra...