《劍指offer》-- (7)二叉樹中和爲某一值的路徑

題目描述:輸入一顆二叉樹和一個整數,打印出二叉樹中結點值的和爲輸入整數的所有路徑。從樹的根結點開始往下一直到葉結點所經過的結點形成一條路徑。

定義的樹:

typedef int elemtype;
#define END -1
typedef struct BtNode
{
	struct BtNode* leftchild;
	struct BtNode* rightchild;
	elemtype data;
}BtNode,*pBtNode;

舉例:


如上圖中的一顆樹,假如目標值爲22,則結果應該輸出的路徑爲:

path1:10  5   7

path2:10 12  0

解題思路:

1、可以利用遞歸遍歷解決,每訪問一個結點就將當前的值(cursum)進行累加,直到訪問到葉子節點,如果與目標值相等則打印,不相等則剔除最後一個加入的,再進行計算。

static void Path1(BtNode* ptr,int target,int &cursum,vector<BtNode*>& vec)
{
	if(ptr!=NULL)
	{
		cursum+=ptr->data;//累加
		vec.push_back(ptr);

		Path2(ptr->leftchild,target,cursum,vec);

		if(cursum==target && ptr->leftchild==NULL && ptr->rightchild==NULL)
		{
			vector<BtNode*>::iterator it=vec.begin();
			for(;it!=vec.end();++it)
			{
				cout<<(*it)->data<<" ";
			}
			cout<<endl;
			//cout<<cursum<<endl;
		}

		Path2(ptr->rightchild,target,cursum,vec);

		cursum-=ptr->data;//一定要放在該位置!保證當前結點的左右孩子都能訪問到。將不滿足的葉結點的值剔除。
		vec.pop_back();
	}
}
void FindPath1(BtNode* ptr,int target)
{
	if(NULL==ptr)
		return ;
	int cursum=0;
	vector<BtNode*> vec;//用該容器來保存路徑
	Path1(ptr,target,cursum,vec);
}

2、非遞歸:

思路一:利用中序遍歷非遞歸進行修改-》不行

思路二:先序遍歷非遞歸代碼修改-》存儲路徑上的值有很好的切入點(在打印的地方),刪除做不到-》拋棄之

思路三:採用層序遍歷來進行修改,不需要一個隊列,只需要一個vector容器即可。核心思想是利用數組的下標來對整顆樹進行處理。-》妙哉,Do it!

實現過程:是一個怎樣的vector(數組)呢?看下圖:


代碼:

typedef struct newNode
{
	int parentindex;
	BtNode* p;
public:
	newNode(int i=-1,BtNode* q=NULL):parentindex(i),p(q){}
}newNode;

void PrintPath(vector<newNode>& vec,int i)//打印路徑
{
	int k=i;stack<elemtype> s;
	for(;k!=-1;k=vec[k].parentindex)
	{
		s.push(vec[k].p->data);
	}
	while(!s.empty())
	{
		elemtype out=s.top();s.pop();
		cout<<out<<" ";
	}
	cout<<endl;
}
void TheOkPath(vector<newNode>& vec,int target)//找到符合要求的路徑
{
	for(int i=0;i<vec.size();i++)//遍歷整個vec容器
	{
		if(vec[i].p->leftchild==NULL && vec[i].p->rightchild==NULL)//從葉子結點處查找符合要求的路徑
		{
			int j=i;//j表示當前結點的下標
			int cursum=0;
			for(;j!=-1;j=vec[j].parentindex)//求當前葉子結點到樹根路徑的元素之和
			{
				cursum+=vec[j].p->data;
			}
			//cursum+=vec[0].p->data;//此句不需要
			if(cursum==target)//如果和與目標值相等,則打印該路徑中的元素
			{
				PrintPath(vec,i);
			}
		}
	}

}
static void Path2(BtNode* ptr,int target)//將每個結點都保存在vec中
{
	vector<newNode> vec;
	int pi=-1;//根結點的雙親索引
	vec.push_back(newNode(pi,ptr));
	int depth=Depth_Tree(ptr);
	//將樹中的所有元素都存儲到vector容器中
	while(pi<depth)
	{
		pi+=1;
		if(vec[pi].p->leftchild)
		{
			vec.push_back(newNode(pi,vec[pi].p->leftchild));
		}
		if(vec[pi].p->rightchild)
		{
			vec.push_back(newNode(pi,vec[pi].p->rightchild));
		}
	}
	TheOkPath(vec,target);
	
}
void FindPath2(BtNode* ptr,int target)
{
	if(NULL==ptr)
		return ;
	Path2(ptr,target);
}

打印:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章