遞迴路徑問題

只有菜的小白發表於2024-04-27

最近寫一個矩陣連乘的問題,在列印括號的時候遇到了難題,不知道括號和序列怎麼輸出才能得到標準的加括號序列,在網上查到了一個部落格發現是對的,在此記錄一下,順便和floyed列印路徑的方式作對比,以此來加深對二叉樹遍歷的理解。
首先上矩陣連乘的圖和程式碼

void Traceback(vector<int>p,int m,int n)  //表示的是矩陣的值,這裡好像沒什麼用,因為實際上用的是s矩陣
{
	if (m == n) {
		cout << "A"<<m; return;
	}
	cout << "(";
	Traceback(p, m, s[m][n]);
	Traceback(p, s[m][n]+1, n);
	cout << ")";
	
}

這裡的s陣列就是指在哪個地方加上括號。畫個圖來方便理解:

兩個問題:一是遇到葉結點直接返回,只要輸出值即可。
二是左括號和右括號的時機,分別是在第一次遇到結點,和離開結點的時候加上。類似先序和後序遍歷。
em,想了半天也不知道啥時候該輸出值,啥時候該輸出括號。記住遇到葉結點的時候直接返回了,不會深入葉結點的空間,而且每個葉結點只遇見一次,所以在葉節點列印值是最合理的。
對於每一個開裂的非葉子空間就要在進入空間時加左括號,離開時加右括號。這個確實不知道怎麼切入。

void Traceback(vector<int>p,int m,int n)
{
	if (m == n) {
		cout << "A"<<m; return;
	}
	cout << "(";
	Traceback(p, m, s[m][n]);
	cout << ")";
	cout << "(";
	Traceback(p, s[m][n]+1, n);
	cout << ")";
}

這裡給每個中序的地方加上了左括號和右括號,也是對的,但是出現了很多的冗餘,因為即使有一個元素也被加上了括號。
結果如下:

兩相對比,就發現這個加括號在我看來很古怪。你想啊,就單從函式本身來看,在兩個遞迴之間斷開加上括號不是很合理嗎,s[m][n]也確實是其中的一個分割點。但是這麼加就會有很多冗餘,反而不如第一種標準的加法,雖然用二叉樹的遍歷方式可以理解,但是在自己思考的時候還是覺得遞迴可讀性可理解性確實差。
Floyd演算法程式碼:

void floyed(){

    for(int k=1;k<=n;k++){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
                 p[i][j]=k;  //記錄插點
            }
        }
    }
}

//列印路徑的程式碼
void path(int i,int j)
{
    if(p[i][j]==0) return ; //沒有插點就返回
    int k=p[i][j];
    path(i,k);    //列印插點
    cout<<"->"<<k<<"->";
    path(k,j);
}

int main()
{
    cout<<a<<"->"; 。//第一個點和最後一個點是不會被輸出的,記得加上
    path(a,b);
    cout<<b;
}

這裡的輸出路徑就是遞迴搜尋兩個點之間的插點,也就是中序遍歷了,看下面的圖也可以理解。

總結一下,這種遞迴二叉樹的遍歷最好還是畫個圖理解一下,搞清楚在葉結點和非葉子結點分別要幹什麼事,其實也不是很難( 不難才怪 ···)

相關文章