数据结构笔记:叶子结点的路径

柔情痞子 提交于 2020-01-20 08:15:12

一棵树的根结点到每个叶子结点之间经过的结点序列叫做叶子结点的路径,与图中两个结点的路径不同,叶子结点的路径有且只有一条。本博客主要讨论用程序实现打印二叉树中叶子结点路径的问题。

基本方法

根结点到达叶子结点都是通过有限次的找左子树或找右子树的操作实现的,到达叶子结点时,一路上经过的所有结点所形成的序列就是这个树叶的路径。这就是找一个叶子结点路径的方法。我们规定,所有的叶子结点都从左子树开始寻找,这样一来,我们也就确定了所有叶子结点的寻找顺序,即先打印输出左子树的叶子结点,在去寻找并打印输出右子树的叶子结点。

为了得到一个叶子结点的路径,我们就需要选定一种线性表来存储这种具有先后顺序的序列。这样一来,打印路径的过程就变成了遍历线性表的过程。显然,栈和队列都是遍历操作受限的线性表,因而这类数据结构无法满足要求,本人在此推荐一种可遍历的线性表容器(C++)——vector(向量)。

vector既有数组的特点,又具有类似栈的某些操作,其基本的操作如下:
size():取得当前vector的长度;
empty():判断当前的vector是否为空向量;
push_back(varType var):在向量的尾部插入元素(类似入栈操作);
pop_back():在向量的尾部删除元素(类似出栈操作);
back():取得向量尾部的元素;
front():取得向量首部的元素;
at(u_int i):取得向量中下标为i的元素(与数组元素的引用类似);

结点的数据域

class binTree{
public:
	char				element;
	bool				isPass;
	binTree				*lchild, *rchild;
};

算法流程

算法的步骤如下:

  1. 将当前所在结点push入向量vector;
  2. 判断当前结点是否为叶子结点,是叶子结点时,遍历此时的vector得到的序列,就是当前叶子结点的路径;若当前的结点不是叶子结点,则转此结点的左孩子,若此节点无左孩子,则转其右孩子;
  3. 跳转至步骤1,直到找到一个叶子结点
  4. 打印完一个叶子结点的路径之后,从向量的尾部开始一直pop,直到遇到一个度为2的结点,此时先判断结点的数据域中isPass是否为true(程序开始时先将所有节点的isPass置为false),不为true时,将isPass置为true,并转该节点的右子树,跳转至步骤1;否则,将该结点pop,vector中元素数量为0时,表示所有叶子结点路径都已找出并打印

在结点的数据域中设置isPass的原因在于,一个度为2的结点是分支节点,对vector进行pop的操作中,一定会两次遇见这种分支节点,第二次遇见这种结点时才能pop。为了防止分支节点不被重复访问且被轻易pop,因此必须设置一个标志位isPass来表示之前pop时路过此结点一次。

程序源码

基于上面所讲的算法步骤,可以很快写出相关的代码。此算法的源码如下(包含测试用例)。

下面是打印叶子结点路径的函数:

void pathPrinter(vector<binTree *> path){
	if(!path.back()->lchild && !path.back()->rchild){
		cout << path.back()->element << ": ";
		for(int i=0; i<path.size(); i++)
			cout << path.at(i)->element;
		cout << endl;
	}
}

以下的函数就是找叶子结点并打印其路径的相关代码:

void leafPath(binTree *root){
	
	binTree				*node = root;
	vector<binTree *>	path;
	
	if(!root){
		cout << "This is an empty tree!" << endl;
		return ;
	}
	
	cout << "The path for each leaf node is:" << endl;
	while(node || !path.empty()){
		while(node){
			path.push_back(node);
			if(node->lchild || !node->rchild&&!node->lchild)
				node = node->lchild;
			else
				node = node->rchild;
		}
		
		pathPrinter(path);
		
		if(path.back()->lchild && path.back()->rchild && !path.back()->isPass){
			path.back()->isPass = true;
			node = path.back()->rchild;
		}
		else
			path.pop_back();
	}
}

创建二叉树(前序)的代码如下:

binTree *createBinTree(){
	
	binTree 			*root;
	char				element;
	
	cin >> element; 
	if(element == '#')					//'#'表示此结点为空
		return NULL;
	else{
		root = new binTree;
		root->element = element;
		root->isPass = false;
		root->lchild = createBinTree();
		root->rchild = createBinTree();
	}
}

用于输入的测试用例:

//Samples: 
/* AB#C##DG#H##E#F## */
/* A#BCD#E##F##GHI#J###K## */

代码的整合见链接:
代码整合

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!