1. 程式人生 > >C語言強化(四)求和為某個值的二叉樹路徑

C語言強化(四)求和為某個值的二叉樹路徑

遞迴究竟有多強大,看看這道題就知道了。

通過這道題,你可以掌握

  • 如何使用遞迴
  • 遞迴的本質
  • 如何跳出遞迴死迴圈

題目:輸入一個整數和一棵二元樹。
從樹的【根結點】開始往下訪問一直到【葉結點】所經過的所有結點形成一條路徑。
打印出和與輸入整數相等的所有路徑。

例如,輸入20和如下二叉樹


打印出路徑  10 6 4  

思路

  • 當訪問到某一結點時,把該結點新增到路徑上,並累加當前結點的值。
  • 如果當前結點為葉結點並且當前路徑的和剛好等於輸入的整數,則當前的路徑符合要求, 我們把它打印出來。
  • 如果當前結點不是葉結點, 則繼續訪問它的子結點。 

對於子結點,我們會發現,要執行的操作跟我們上面三點一模一樣!這就是在暗示你,該使用遞迴啦!

在遍歷的時候,我們把一個個結點壓入棧中。這就要求我們,在遍歷後要讓節點出棧,否則函式將永遠不能跳出來。

因此我們在函式退出之前要在路徑上刪除當前結點並減去當前結點的值,以確保返回父結點時路徑剛好是根結點到父結點的路徑。

原始碼

#include <stdio.h>
#include<stdlib.h>
#include <iostream>
#include<sstream>
#include <VECTOR>

using namespace std;

/**
在二叉樹中找出和為某一值的所有路徑

題目:輸入一個整數和一棵二叉樹。
從樹的【根結點】開始往下訪問一直到【葉結點】所經過的所有結點形成一條路徑。
打印出和與輸入整數相等的所有路徑

思路
當訪問到某一結點時,把該結點新增到路徑上,並累加當前結點的值。
如果當前結點為葉結點並且當前路徑的和剛好等於輸入的整數,則當前的路徑符合要求, 我
們把它打印出來。
如果當前結點不是葉結點, 則繼續訪問它的子結點。 
因此我們在函式退出之前要在路徑上刪除當前結點並減去當前結點的值,
以確保返回父結點時路徑剛好是根結點到父結點的路徑。
我們不難看出儲存路徑的資料結構實際上是一個棧結構,因為路徑要與遞迴呼叫狀態一致,
而遞迴呼叫本質就是一個壓棧和出棧的過程。
*/
struct BinaryTreeNode // a node in the binary tree
{
	int m_nValue; // value of node
	BinaryTreeNode *m_pLeft; // left child of node
	BinaryTreeNode *m_pRight;  // right child of node
};

//求和等於某個值的路徑
void findPath(BinaryTreeNode * node,int expectAdd,vector<int> path,int sum){
	if(NULL==node)//結點為空
		return;
	path.push_back(node->m_nValue);
	sum+=node->m_nValue;
	//如果當前結點為葉結點並且當前路徑的和剛好等於輸入的整數,
	//則當前的路徑符合要求,我們把它打印出來。
	if(NULL==node->m_pLeft&&NULL==node->m_pRight&&sum==expectAdd){
		cout<<"找到路徑:"<<endl;
		for(int i =0;i<path.size();i++){
			cout<<path[i]<<"  ";
		}
		cout<<endl;
	}
	//如果當前結點不是葉結點, 則繼續訪問它的子結點。 
	if(NULL!=node->m_pLeft)
		findPath(node->m_pLeft,expectAdd,path,sum);
	if(NULL!=node->m_pRight)
		findPath(node->m_pRight,expectAdd,path,sum);

	//在函式退出之前要在路徑上刪除當前結點並減去當前結點的值,
	//以確保返回父結點時路徑剛好是根結點到父結點的路徑。
	path.pop_back();
	sum-=node->m_nValue;
}

void main()
{
	//生成二叉樹,這裡使用一種比較愚蠢的做法,各位同學可以自行設計
	BinaryTreeNode * root=new BinaryTreeNode();
	root->m_pLeft=new BinaryTreeNode();
	root->m_pRight=new BinaryTreeNode();
	root->m_pLeft->m_pLeft=new BinaryTreeNode();
	root->m_pRight->m_pRight=new BinaryTreeNode();
	root->m_nValue=10;
	root->m_pLeft->m_nValue=6;
	root->m_pRight->m_nValue=2;
	root->m_pLeft->m_pLeft->m_nValue=4;
	root->m_pRight->m_pRight->m_nValue=7;

	//設定引數
	int expectAdd = 20;
	vector<int> path;
	int sum=0;
	//尋找路徑
	findPath(root,expectAdd,path,sum);

	system("pause");
}

執行


對於遞迴,記住這麼一句話,遞迴呼叫本質就是一個壓棧和出棧的過程