資料結構和演算法學習三,之遞迴和堆疊

2021-09-06 23:40:49 字數 1480 閱讀 9847

引自:

函式呼叫主要依靠ebp和esp的堆疊互動來實現的。那麼遞迴呢,最主要的特色就是函式自己呼叫自己。如果乙個函式呼叫的是自己本身,那麼這個函式就是遞迴函式。

我們可以看一下普通函式的呼叫怎麼樣的。試想如果函式a呼叫了函式b,函式b又呼叫了函式c,那麼在堆疊中的資料是怎麼儲存的呢?

函式a    ^

函式b    |    (位址遞減)

函式c    |

如果是遞迴函式呢,舉乙個簡單的遞迴函式為例:

int iterate(int

value)

下面我們使用乙個函式進行呼叫,看看會發生什麼情況?

void

process()

看看此時記憶體堆疊是什麼樣的?

iterate(int

1) line 96

iterate(

int2) line 97 + 12

bytes

iterate(

int3) line 97 + 12

bytes

iterate(

int4) line 97 + 12

bytes

iterate(

int5) line 97 + 12

bytes

iterate(

int6) line 97 + 12

bytes

process() line

102 + 7

bytes

main() line

108maincrtstartup() line

206 + 25

bytes

kernel32! 7c817067()

大家也看到了上面的**,遞迴函式和普通的函式也沒有什麼差別。除了自己呼叫本身之外,他就是乙個普通的函式。那麼這個函式遞迴到什麼時候返回呢?這就是遞迴函式的關鍵了。我們看到iterate函式到1就停止了,所以上面的堆疊在(value == 1)即return。所以乙個遞迴函式最關鍵的部分就是兩點:(1)遞迴策略;(2)函式出口。

看到這裡,大家可能感到遞迴函式不過如此,事實上也是這樣。但是,還有一點大家需要牢記在心,遞迴的深度是我們必須考慮的乙個問題。只有遞迴深度在乙個可控的範圍內,那麼整個遞迴過程都是可控的。那什麼時候不可控呢?那就是遞迴深度超過了一定的數字?這個數字和具體的執行緒堆疊長度有關?等到堆疊溢位了,那麼獲得的資料已經失去了真實性,所以也就沒有意義了。

我們把上面的問題推廣一下,如何用自己定義的堆疊模擬上面的遞迴呼叫呢?這樣既能滿足遞迴的屬性,又能確保函式深度可控。

大家可以先寫一下自己的方案,下面只是我個人的乙個思路。

int iterate(int

value)

return

count;

}

【預告: 下面一篇部落格介紹演算法和記憶體】

資料結構和演算法學習三,之遞迴和堆疊

引自 函式呼叫主要依靠ebp和esp的堆疊互動來實現的。那麼遞迴呢,最主要的特色就是函式自己呼叫自己。如果乙個函式呼叫的是自己本身,那麼這個函式就是遞迴函式。我們可以看一下普通函式的呼叫怎麼樣的。試想如果函式a呼叫了函式b,函式b又呼叫了函式c,那麼在堆疊中的資料是怎麼儲存的呢?函式a 函式b 位址...

資料結構和演算法學習六,之非遞迴排序

在上面一篇部落格當中,我們發現普通查詢和排序查詢的效能差別很大。作為乙個100萬的資料,如果使用普通的查詢方法,那麼每乙個資料查詢平均下來就要幾十萬次,那麼二分法的查詢呢,20多次就可以搞定。這中間的差別是非常明顯的。既然排序有這麼好的效果,那麼這篇部落格中,我們就對排序算做乙個總結。按照我個人的理...

資料結構和演算法學習六,之非遞迴排序

在上面一篇部落格當中,我們發現普通查詢和排序查詢的效能差別很大。作為乙個100萬的資料,如果使用普通的查詢方法,那麼每乙個資料查詢平均下來就要幾十萬次,那麼二分法的查詢呢,20多次就可以搞定。這中間的差別是非常明顯的。既然排序有這麼好的效果,那麼這篇部落格中,我們就對排序算做乙個總結。按照我個人的理...