1. 程式人生 > >劍指offer面試題25-二叉樹中和韋某一值的路徑

劍指offer面試題25-二叉樹中和韋某一值的路徑

question:給定一顆二叉樹,一個值。我們希望輸出和為該值的所有路徑。

假設樹的結構如下


思路:使用一個基於先序遍歷的遞迴過程來遍歷樹中每個點一次,每遍歷一個點就要獲得從根節點到被訪問的點的累加和,並儲存從根節點到當前點的路徑。然後進行判斷,

case1如果當前點的左右孩子都為空(葉子節點)並且累加和等於我們期望的和,那麼就打印出路徑;

case2如果左孩子為空,遞迴到最孩子;

case3如果右孩子為空,遞迴到右孩子;

case4如果是葉子並且當前和不等於期望和,網上回退

試下程式碼:

引數為值傳遞的程式碼

#include<vector>
#include<iostream>
using namespace std;
typedef struct BinaryTreeNode
{
	int data;
	struct BinaryTreeNode *lchild;
	struct BinaryTreeNode *rchild;
}*BinTreeRoot;


void createTree1(BinaryTreeNode *&root)
{
	root = (BinaryTreeNode *)malloc(sizeof(BinaryTreeNode));
	root->data = 8;
	root->lchild = NULL;
	root->rchild = NULL;

	BinaryTreeNode *p = (BinaryTreeNode *)malloc(sizeof(BinaryTreeNode));
	p->data = 8;
	p->lchild = NULL;
	p->rchild = NULL;
	root->lchild = p;

	p = (BinaryTreeNode *)malloc(sizeof(BinaryTreeNode));
	p->data = 7;
	p->lchild = NULL;
	p->rchild = NULL;
	root->rchild = p;

	p = (BinaryTreeNode *)malloc(sizeof(BinaryTreeNode));
	p->data = 9;
	p->lchild = NULL;
	p->rchild = NULL;
	root->lchild->lchild = p;

	p = (BinaryTreeNode *)malloc(sizeof(BinaryTreeNode));
	p->data = 2;
	p->lchild = NULL;
	p->rchild = NULL;
	root->lchild->rchild = p;

	p = (BinaryTreeNode *)malloc(sizeof(BinaryTreeNode));
	p->data = 4;
	p->lchild = NULL;
	p->rchild = NULL;
	root->lchild->rchild->lchild = p;

	p = (BinaryTreeNode *)malloc(sizeof(BinaryTreeNode));
	p->data = 7;
	p->lchild = NULL;
	p->rchild = NULL;
	root->lchild->rchild->rchild = p;
}


void findPath(BinaryTreeNode *root, int expectedSum, int curSum, vector<int>path)
{
	if (root == NULL)
		return;
	curSum += root->data;
	path.push_back(root->data);
	if (root->lchild == NULL && root->rchild == NULL && curSum == expectedSum)
	{
		for (auto iter = path.begin(); iter != path.end();  ++iter)
		{
			if (iter + 1 == path.end())
			{
				cout << *iter << endl;
			}
			else
			{
				cout << *iter << "->";
			}
		}
	}
	if (root->lchild != NULL)
	{
		findPath(root->lchild, expectedSum, curSum, path);
	}
	if (root->rchild != NULL)
	{
		findPath(root->rchild, expectedSum, curSum, path);
	}
//	curSum -= root->data;
//	path.pop_back();
}


int main()
{
	BinaryTreeNode *root = NULL;
	createTree1(root);
	if (root == NULL)
	{
		cout << "the tree is empty!" << endl;
		return 0;
	}
	int curSum = 0;//存放從根節點到當前節點的路徑和
	int expectedSum;//我們期待的值
	cin >> expectedSum;
	vector<int>path;//存放路徑
	findPath(root, expectedSum, curSum, path);
	return 0;
}
注意:在這個程式碼中存放累加和curSum、路徑path的變數都是使用的值傳遞,而不是引用傳遞。因為該方法是一個遞迴的過程,在每一個遞迴棧中都有一個臨時變數curSum和path。如果遞迴返回到上一層時,本次計算的沒有影響。相反,如果使用了引用傳遞的,需要手動修改資料的值:

引數為引用傳遞的程式碼:

#include<vector>
#include<iostream>
using namespace std;
typedef struct BinaryTreeNode
{
	int data;
	struct BinaryTreeNode *lchild;
	struct BinaryTreeNode *rchild;
}*BinTreeRoot;


void createTree1(BinaryTreeNode *&root)
{
	root = (BinaryTreeNode *)malloc(sizeof(BinaryTreeNode));
	root->data = 8;
	root->lchild = NULL;
	root->rchild = NULL;

	BinaryTreeNode *p = (BinaryTreeNode *)malloc(sizeof(BinaryTreeNode));
	p->data = 8;
	p->lchild = NULL;
	p->rchild = NULL;
	root->lchild = p;

	p = (BinaryTreeNode *)malloc(sizeof(BinaryTreeNode));
	p->data = 7;
	p->lchild = NULL;
	p->rchild = NULL;
	root->rchild = p;

	p = (BinaryTreeNode *)malloc(sizeof(BinaryTreeNode));
	p->data = 9;
	p->lchild = NULL;
	p->rchild = NULL;
	root->lchild->lchild = p;

	p = (BinaryTreeNode *)malloc(sizeof(BinaryTreeNode));
	p->data = 2;
	p->lchild = NULL;
	p->rchild = NULL;
	root->lchild->rchild = p;

	p = (BinaryTreeNode *)malloc(sizeof(BinaryTreeNode));
	p->data = 4;
	p->lchild = NULL;
	p->rchild = NULL;
	root->lchild->rchild->lchild = p;

	p = (BinaryTreeNode *)malloc(sizeof(BinaryTreeNode));
	p->data = 7;
	p->lchild = NULL;
	p->rchild = NULL;
	root->lchild->rchild->rchild = p;
}


void findPath(BinaryTreeNode *root, int expectedSum, int &curSum, vector<int>&path)//引用傳遞
{
	if (root == NULL)
		return;
	curSum += root->data;
	path.push_back(root->data);
	if (root->lchild == NULL && root->rchild == NULL && curSum == expectedSum)
	{
		for (auto iter = path.begin(); iter != path.end();  ++iter)
		{
			if (iter + 1 == path.end())
			{
				cout << *iter << endl;
			}
			else
			{
				cout << *iter << "->";
			}
		}
	}
	if (root->lchild != NULL)
	{
		findPath(root->lchild, expectedSum, curSum, path);
	}
	if (root->rchild != NULL)
	{
		findPath(root->rchild, expectedSum, curSum, path);
	}
	curSum -= root->data;//curSum和path是引用傳遞,所以如果遞迴返回到上一層的時候,需要減去本次的累加
	path.pop_back();
}


int main()
{
	BinaryTreeNode *root = NULL;
	createTree1(root);
	if (root == NULL)
	{
		cout << "the tree is empty!" << endl;
		return 0;
	}
	int curSum = 0;//存放從根節點到當前節點的路徑和
	int expectedSum;//我們期待的值
	cin >> expectedSum;
	vector<int>path;//存放路徑
	findPath(root, expectedSum, curSum, path);
	return 0;
}

過程:假設我們希望輸出和為25的所有路徑;

設定以下變數:int curSum = 0;//存放當前累加和

                         int expectedSum = 25;//期待和

                         vector<int>path;//用於存放路徑

                         BinaryTreeNode *root;//指向樹中根節點的指標

(1)首先從根節點出發,curSum = 8,並且不是葉子節點,並且值不為35。


(2)由於是基於先序遍歷的,接下來我們訪問左孩子,累加和為8+8=16,仍然不是葉子節點。


(3)再訪問8的右孩子9,累加和為25,並且是葉子節點。此時打印出路徑


路徑為8->8->9

(4)使用一個遞迴的過程,然後向上回退到節點8,並且訪問8的右孩子2


(5)訪問2的左孩子4,此時累加和為22.


(6)當前訪問到的點4是一個葉子節點,並且累加和為22,不是我們所期待的,所以向上回退到2,並且訪問2的右孩子7,此時7是葉子節點。並且和為25,所以滿足要求,打印出路徑


路徑為:8->8->2->7