二叉树的相关学习

本文详细介绍了二叉树的创建及多种遍历方法,包括递归与非递归实现的前序、中序、后序遍历及层次遍历,并提供了具体的C++代码示例。此外还讲解了如何计算节点数、叶子节点数和树的高度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二叉树是树中比较重要的一个部分,对于二叉树的建立,还有遍历方式,主要分后序,中序,前序的遍历,而这个的前中后主要是根节点的访问顺序的不同,左子树和右子树的访问顺序是一样的,这其实是一个递归的顺序,因为访问到一个根节点的时候,又可以把下面的节点看成是一颗树,也可以用非递归,也就是队列或栈的方式来访问树,还有ACM的一道题目是已知前序,中序遍历,来叫你写出后序遍历的题目,只有知道两种访问顺序,才能构造出一颗完整的树!



采用先序遍历的方式来创建树 先是输入根节点,随后输入左子树再输入右子树,若为空格,则表示左子树不存在或右子树不存在 因此 本次实验报告的输入为

ABD11G111CE11FH111 1代表空格

//先序创建二叉树 输入时候只读入一个字符,所以用getchar,
treePointer CreateTree() {
	treePointer ptree = NULL;
	char ch;
	ch = getchar();
	if (ch==' ')
		ptree = NULL;
	else {
		ptree = (treePointer)malloc(sizeof(node));
		ptree->data = ch;
		ptree->leftChild = CreateTree();
		ptree->rightChild = CreateTree();
	}
	return ptree;
}

之后是递归的前序后序中序来遍历这棵树 代码比较简单

//先序遍历的递归,先访问根节点,再访左子树,随后访问右子树
void Recursive_Preorder(treePointer ptr)
{
	if (ptr) {
		cout << ptr->data << " ";
		Recursive_Preorder(ptr->leftChild);
		Recursive_Preorder(ptr->rightChild);
	}
}
//中序遍历的递归,先访问左子树,再访问根节点,随后访问右子树
void Recursive_Inorder(treePointer ptr) {
	if (ptr) {
		Recursive_Inorder(ptr->leftChild);
		cout << ptr->data << " ";
		Recursive_Inorder(ptr->rightChild);
	}
}
//后序遍历的递归,先访问左子树,再访右子树,随后访问根节点
void  Recursive_Postorder(treePointer ptr) {
	if (ptr) {
		Recursive_Preorder(ptr->leftChild);
		Recursive_Preorder(ptr->rightChild);
		cout << ptr->data << " ";
	}
}
之后是层次的遍历,类似于广搜,用到了队列,如果左孩子存在,左孩子入队列,右孩子存在,右孩子入队列

//层次遍历的递归调用,要用到队列的操作
<pre name="code" class="cpp">void Level_Order(treePointer ptr) {
	rear = -1;
	front = -1;
	queue q[10000];
	if (!ptr)
		return;
	q[++rear].key = ptr;
	while (front < rear) {
		ptr = q[++front].key;
		if (ptr) {
			cout << ptr->data << " ";
			if (ptr->leftChild)
				q[++rear].key = ptr->leftChild;
			if (ptr->rightChild)
				q[++rear].key = ptr->rightChild;
		}
		else
			break;
	}
}



非递归的代码明天再补上

非递归前序 主要是当栈不为空的前提下,先把根的结果输出,随后压入栈时注意,先把右子树压入,再左子树压入,因为是后进先出

//先序非递归的遍历
void iter_Preorder(treePointer ptr) {
	top = -1;
	stack s[1000];
	if (!ptr)
		return;
	s[++top].key = ptr;
	while (top != -1) {
		treePointer cur = s[top].key;
		cout << cur->data << " ";
		top--; 
		if (cur->rightChild)
			s[++top].key = cur->rightChild;
		if (cur->leftChild)
			s[++top].key = cur->leftChild;
	}
}

非递归的中序,也是在栈不为空的前提下,先让左子树的节点全部入栈,随后弹出栈,输出结果,再变成他的右子树

//中序非递归遍历 先让左子树都入栈,当左子树为空的时候,则弹出栈顶的元素,进行输出,随后他自己变成自己的右孩子
void iter_Inorder(treePointer ptr) {
	top = -1;
	stack s[100];
	if (!ptr)
		return;
	treePointer cur = ptr->leftChild;
	s[++top].key = ptr;
	while (cur || top != -1)
	{
		while (cur) {
		s[++top].key = cur;
		cur = cur->leftChild;
	}
	cur = s[top--].key;
	cout << cur->data << " ";
	cur = cur->rightChild;
}
}

非递归的后序 ,要定义一个指针表示他的右子树是否被访问过,首先也是左子树全部入栈,之后再判断右孩子是否为空或已经被访问过,如果是空的或已经访问过了,则输出当前元素的值,否则他变成他的右子树

//后序非递归遍历
void iter_Postorder(treePointer ptr) {
	stack s[1000];
	 top = -1;
	treePointer cur = ptr;//指向当前要检查的节点
	treePointer preVisited = NULL;//指向前一个被访问的节点
	while (cur || top != -1) {
		//一直向左走直到为空的时候
		while (cur) {
			s[++top].key = cur;
			cur = cur->leftChild;
		}
		cur = s[top].key;
		//当前右孩子如果为空或者已经被访问,则访问当前的节点
		if (cur->rightChild == preVisited||cur->rightChild==NULL) {
			cout << cur->data << " ";
			preVisited = cur;
			top--;
			cur = NULL;
		}
		else
			cur = cur->rightChild;
	}
}


之后是统计节点的个数,也是用到递归的操作,左孩子和右孩子碰到,节点个数就加1 

//统计节点的个数 

//统计节点的个数 
int countTree(treePointer ptr) {
	if (ptr) {  
		return (countTree(ptr->leftChild) + countTree(ptr->rightChild)+1);
}
	return 0;
}

统计叶节点的个数 也用到了递归 当左子树和右子树都不存在的时候,则它就为叶节点

//统计叶节点的个数
int count = 0;
void countLeaf(treePointer ptr) {
	if(!ptr->leftChild&&!ptr->rightChild) {
		count++;
		return;
	}
	else  {
		if(ptr->leftChild)
		countLeaf(ptr->leftChild);
		if(ptr->rightChild)
			countLeaf(ptr->rightChild);
	}
}


统计树的高度

//统计树的高度
int height = 0;
int treeHeight(treePointer ptr) {
		if (ptr->leftChild) {
			return treeHeight(ptr->leftChild) + 1;
		}
		if (ptr->rightChild) {
			return treeHeight(ptr->rightChild) + 1;
		}
if (ptr)
return 1;
}

主函数的测试代码:

int main() {
	treePointer ptr = NULL;
	cout << "先序遍历创建树,空号代表该节点无左子树或右子树:";
	  ptr = CreateTree();
	  cout << "递归前序遍历:";
	Recursive_Preorder(ptr);
	cout << endl;
	cout << "递归中序遍历:";
	Recursive_Inorder(ptr);
	cout << endl;
	cout << "递归后序遍历:";
	Recursive_Postorder(ptr);
	cout << endl;
	cout << "层次遍历:";
   Level_Order(ptr);
	cout << endl;
	cout << "非递归前序:";
		iter_Preorder(ptr);
	cout << endl;
	cout << "非递归中序:";
   iter_Inorder(ptr);
    cout << endl;
	cout << "非递归后序:";
	iter_Postorder(ptr);
	cout << endl;
	cout << "节点个数:";
	cout << countTree(ptr)<<endl;
	cout << "树的高度";
	cout << treeHeight(ptr);
	return 0;
}

结果:



参考的几个博客

http://blog.youkuaiyun.com/fansongy/article/details/6798278

http://blog.youkuaiyun.com/zhaoxianyong/article/details/7165386

http://www.cnblogs.com/dolphin0520/archive/2011/08/25/2153720.html

http://blog.youkuaiyun.com/cxllyg/article/details/7520037

http://blog.youkuaiyun.com/lalor/article/details/7626854

已知前序和中序 求后序的算法

http://www.cr173.com/html/18891_1.html


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值