二叉树的创建&遍历1:创建二叉树

二叉树的创建&遍历1:创建二叉树

谈二叉树,如果二叉树都没有正确的创建出来,那岂不是纸上谈兵!!

创建方法1:由括号表达式创建

括号表达式:

在这里插入图片描述

表示方法:

1.括号:括号内的东西是括号前的元素的孩子
2.逗号:逗号是为了区分左右孩子

算法分析:

给出一个如上的括号表达式:A(B(D(,G)),(E,F)),再利用栈这个数据结构,分析一下:
扫描整个括号表示的字符串,这个字符串中只有四种字符:'(',')',',','other'
①:如果遇到了’(’:表示前面刚刚创建的节点是有孩子节点的,需要把它压入栈中,因为我们的栈的功能实际上是为了保存父节点而便于去寻找孩子节点,然后开始创建孩子节点,第一个创建的一定是左孩子,所以设一个控制左右孩子的变量:k = 0;//k = 0 时是左孩子,k = 1 是右孩子
②:如果遇到了’)’:表示以栈顶元素为根节点的子树创建完毕,退出栈中
③:如果遇到了’,’:表示左孩子创建完毕,需要创建右孩子,此时k = 1//改变创建对象的状态
④:如果遇到了其他元素,也就是遇到了节点的内容,此时我们应该创建节点,并且根据当前需要创建的是左孩子还是右孩子,有选择有方向的去创建当前的节点并准确与其父节点链接

核心代码展示:

const int maxn = 1005;
char str[maxn];
struct BTNode{
	char data;
	BTNode* Lchild;
	BTNode* Rchild;
};

BTNode* CreatBT(BTNode *&Root){
	char ch;
	int book = 0, j = 0, top = -1;
	BTNode *pNode = Root = NULL, *Stack[maxn];
	ch = str[j];
	while('\0' != ch){
		switch(ch){
			case '(':
				Stack[++top] = pNode;
				book = 0;
				break;
			case ')':
				--top;
				break;
			case ',':
				book = 1;
				break;
			default:
				pNode = new BTNode;
				pNode->data = ch;
				pNode->Lchild = pNode->Rchild = NULL;
				if(NULL == Root)
					Root = pNode;
				else{
					if(book)
						Stack[top]->Rchild = pNode;
					else
						Stack[top]->Lchild = pNode;
				}
		}
		ch = str[++j];
	}
	return Root;
}

代码分析:

这里贯彻了一个思想:栈与队列在二叉树的操作中起到的作用就是保存根节点以便于查找子节点
然后注意一下指针操作:一开始初始化的时候,一定要把所有未操作却已经定义了的指针指向NULL!

创建方法二:层次创建二叉树

之前括号表示法创建二叉树利用了栈的结构,这里我们要运用队列的结构

问题引入:

在这里插入图片描述
上面这幅图,用层序遍历得到的结果是:5 4 8 11 # 13 4 7 2 # # # 1
那如果我们得到上面这个序列,如何还原创建出二叉树呢?

算法分析:

给出一个层序结果,为空的地方是用‘#’表示,我们可以借助一个队列,来保存根节点,以便于链接它的对应子树,然后设置一个判定当前子树是左还是右的标记:book,如果book % 2 = 0则是左子树,反之则是右子树,算法步骤如下:
①:先让5入队,建立起第一层(根),然后把book设为0,表示接下来该创建左子树了
②:在队列不为空的情况下,取出队首元素,然后开始准备连上它的左右孩子,这时会有两种情况,一种是当前的book是奇数,这种情况是要添加左孩子,否则添加右孩子,然后在添加孩子的时候还需要判断这个孩子是否是存在的,如果是‘#’则是不存在,给当前的这个孩子赋予一个NULL,否则就连上这个孩子,并且把这个孩子push入队,因为它还可能是其他孩子的父亲!然后处理完左右孩子之后,我们才pop队首!

核心代码展示:

BTNode* CreatBT2(BTNode *&Root){
	queue<BTNode* > q;
	int book = 0;
	Root->data = str2[book++];
	Root->Lchild = Root->Rchild = NULL;
	q.push(Root);
	while(!q.empty()){
		BTNode *temp = q.front();
		if(book % 2){
			if('#' == str2[book])
				temp->Lchild = NULL;
			else{
				BTNode *p = new BTNode;
				p->data = str2[book];
				p->Lchild = p->Rchild = NULL;
				temp->Lchild = p;
				q.push(p);
			}
		}
		else{
			if('#' == str2[book])
				temp->Rchild = NULL;
			else{
				BTNode *p = new BTNode;
				p->data = str2[book];
				p->Lchild = p->Rchild = NULL;
				temp->Rchild = p;
				q.push(p);
			}
			q.pop();
		}
		book++;
	}
	return Root;
}

创建方法三:根据某两序遍历唯一建树

只能通过:
①:已知前序序列 + 已知中序序列 => 唯一建树
②:已知中序序列 + 已知后序序列 => 唯一建树
然而,已知前序和后序是不能唯一建树的,这个随便举个例子就能得出,不做赘述

算法分析:

建树的过程如下:以已知前中序推导后序为例
前序遍历的一个数是整棵树的根,然后在中序序列中找到根的对应位置,分治递归,找到每一个节点,建树

核心代码展示:

void CreatBT3(BTNode *&Root, int &pos, int l, int r){
	int flag = -1;
	for(int i = l;i <= r;i++){
		if(in[i] == pre[pos])
			break;// pos 就是当前子树的根 
	}
	if(-1 == flag)	return ;
	Root = new BTNode;
	Root->data = in[flag];
	Root->Lchild = Root->Rchild = NULL;
	pos++;
	if(flag > l)
		CreatBT3(Root->Lchild, pos, l, flag - 1);`
	if(flag < r)
		CreatBT3(Root->Rchild, pos, flag + 1, r);
}
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页