有关树的代码操作

有关树的代码操作

二叉树的概念回顾

在这里插入图片描述

二叉树的遍历
  • 所谓遍历(Traversal)是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问。访问结点所做的操作依赖于具体的应用问题。
  • 遍历是二叉树上最重要的运算之一,是二叉树上进行其它运算之基础。
    在这里插入图片描述
三种遍历的代码操作
BinaryTree.c
#include"BinaryTree.h"


void PreOrder(BTNode* root)
{
	if (root)
	{
		printf("%d", root->data);
		PreOrder(root->left);
		PreOrder(root->right);
	}
}

void InOrder(BTNode* root)
{
	if (root)
	{
		InOrder(root->left);
		printf("%d", root->data);
		InOrder(root->right);
	}
}

void PostOrder(BTNode* root)
{
	if (root)
	{
		PostOrder(root->left);
		PostOrder(root->right);
		printf("%d", root->data);
	}
}
接下来用代码来验证一下遍历的结果
BinaryTree.h
#pragma once 


#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<string.h>


typedef int BTNDataTye;


typedef struct BTNode
{
	BTNDataTye data;
	struct BTNode* left;
	struct BTNode* right;
}BTNode;


void PreOrder(BTNode* root);

void InOrder(BTNode* root);

void PostOrder(BTNode* root);

BTNode* CreateNode(BTNDataTye data);




void TestBinTree();
BinaryTree.c
#include"BinaryTree.h"


void PreOrder(BTNode* root)
{
	if (root)
	{
		printf("%d", root->data);
		PreOrder(root->left);
		PreOrder(root->right);
	}
}

void InOrder(BTNode* root)
{
	if (root)
	{
		InOrder(root->left);
		printf("%d", root->data);
		InOrder(root->right);
	}
}

void PostOrder(BTNode* root)
{
	if (root)
	{
		PostOrder(root->left);
		PostOrder(root->right);
		printf("%d", root->data);
	}
}

//那么,现在,如果我们想要验证一下这几种方法是否是正确的,那么我们就可以先
//利用一种不那么正规的创建树的形式,我们先创建出来一棵树,从而对遍历的结果进行验证的操作
BTNode* CreateNode(BTNDataTye data)
{
	BTNode* pNewNode = (BTNode*)malloc(sizeof(BTNode));
	if (NULL == pNewNode)
	{
		assert(0);
		return NULL;
	}
	pNewNode->data = data;
	pNewNode->left = NULL;
	pNewNode->right = NULL;
	return pNewNode;
}

BTNode* CreateBinaryTree()
{
	BTNode* root = NULL;
	BTNode* n1 = CreateNode(1);
	BTNode* n2 = CreateNode(2);
	BTNode* n3 = CreateNode(3);
	BTNode* n4 = CreateNode(4);
	BTNode* n5 = CreateNode(5);
	BTNode* n6 = CreateNode(6);

	root = n1;
	root->left = n2;
	n2->left = n3;

	root->right = n4;
	n4->left = n5;
	n4->right = n6;

	return root;
}



//
//二叉树先简单的构造好之后就可以进行一系列的操作了

void TestBinTree()
{
	BTNode* root = CreateBinaryTree();
	printf("前序遍历结果为:\n");
	PreOrder(root);
	printf("\n");

	printf("中序遍历结果为:\n");
	InOrder(root);
	printf("\n");

	printf("后序遍历结果为:\n");
	PostOrder(root);
	printf("\n");

}
二叉树的层序遍历

在这里插入图片描述

  • 一开始我们传参数的时候,我们先把rooot放在1的位置,然后我们把root传入,那么我们这个时候就先打印root的值,当我们把root的值打印完成的时候,那么,我们就需要去打印root的左孩子的值和root的右孩子的值(那么,问题来了,在层序遍历里面,我们可不可以使用递归的方法进行遍历呢?----答案是不可以的,因为,如果继续使用递归的方式进行遍历的话,那么我们其实上使用的遍历方式,就和我们之前所使用的遍历方式是一样的了),那么我们要怎么去打印层序遍历的结果呢?—我们现在有两种处理的方式,在我们打印完1,2,4,三个结点之后,我们要去打印结点2的左孩子和结点2的右孩子,当然,结点4也是同样的处理方式;我们还有另外一种处理的方式,在我们打印结点2和结点4的时候,我们需要把结点2和结点4的左孩子和右孩子全部都保存起来,后续,既然我们已经把结点保存了,那么我们直接去遍历就可以了(现在,其实还是有问题的,我们现在应该采用什么样的结构来保存每一层中的结点呢?----得出的结论是我们需要用队列去保存每一层中的结点,因为先保存的结点需要先打印,类似于队列先进先出的特性,所以我们用队列来保存)
  • 过程如下所示:
    在这里插入图片描述
    在这里插入图片描述
#include"BT.h"


void PreOrder(BTNode* root)
{
	if (root)
	{
		printf("%d", root->data);
		PreOrder(root->left);
		PreOrder(root->right);
	}
}

void InOrder(BTNode* root)
{
	if (root)
	{
		InOrder(root->left);
		printf("%d", root->data);
		InOrder(root->right);
	}
}

void PostOrder(BTNode* root)
{
	if (root)
	{
		PostOrder(root->left);
		PostOrder(root->right);
		printf("%d", root->data);
	}
}

//void LevelOrder(BTNode* root)
//{
//	Queue q;
//
//	//一进来之后,我们需要先检测一下树是不是为空的
//	if (root==NULL)
//	{
//		return;
//	}
//
//	//不空的话,正式开始操作
//	QueueInit(&q);
//	QueuePush(&q, root);
//
//	while (!QueueEmpty(&q))
//	{
//		BTNode* cur = QueueFront(&q);
//		printf("%d ", cur->data);
//		QueuePop(&q);
//		if (cur->left)
//		{
//			QueuePush(&q, cur->left);
//		}
//		if (cur->right)
//		{
//			QueuePush(&q, cur->right);
//		}
//	}
//	//循环走完之后,说明遍历结束
//	//记得最后要销毁
//	QueueDestroy(&q);
//}


//那么,现在,如果我们想要验证一下这几种方法是否是正确的,那么我们就可以先
//利用一种不那么正规的创建树的形式,我们先创建出来一棵树,从而对遍历的结果进行验证的操作
BTNode* CreateNode(BTNDataTye data)
{
	BTNode* pNewNode = (BTNode*)malloc(sizeof(BTNode));
	if (NULL == pNewNode)
	{
		assert(0);
		return NULL;
	}
	pNewNode->data = data;
	pNewNode->left = NULL;
	pNewNode->right = NULL;
	return pNewNode;
}

BTNode* CreateBinaryTree()
{
	BTNode* root = NULL;
	BTNode* n1 = CreateNode(1);
	BTNode* n2 = CreateNode(2);
	BTNode* n3 = CreateNode(3);
	BTNode* n4 = CreateNode(4);
	BTNode* n5 = CreateNode(5);
	BTNode* n6 = CreateNode(6);

	root = n1;
	root->left = n2;
	n2->left = n3;

	root->right = n4;
	n4->left = n5;
	n4->right = n6;

	return root;
}


//
//二叉树先简单的构造好之后就可以进行一系列的操作了

void TestBinTree()
{
	BTNode* root = CreateBinaryTree();
	printf("前序遍历结果为:\n");
	PreOrder(root);
	printf("\n");

	printf("中序遍历结果为:\n");
	InOrder(root);
	printf("\n");

	printf("后序遍历结果为:\n");
	PostOrder(root);
	printf("\n");

}
#pragma once 


#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<string.h>

typedef int BTNDataTye;


typedef struct BTNode
{
	BTNDataTye data;
	struct BTNode* left;
	struct BTNode* right;
}BTNode;

void PreOrder(BTNode* root);

void InOrder(BTNode* root);

void PostOrder(BTNode* root);

void LevelOrder(BTNode* root);

BTNode* CreateNode(BTNDataTye data);

void TestBinTree();

二叉树的销毁操作
  • 我们在进行二叉树的销毁操作的时候,是要先去销毁根节点,还是要先去销毁根节点的左右子树,答案是我们需要先去销毁根节点的左右子树,然后再去销毁根节点,因为,如果我们先去销毁根节点的话,那么我们就找不到根节点的左右孩子了,所以,我们需要先去销毁根节点的左右子树,最后再去销毁根节点
    在这里插入图片描述
  • 那么,我们就可以很轻松的写出下面的代码,但是其实下面的代码是有问题的代码
    在这里插入图片描述
  • 上面的代码,问题所在,是因为,我们在代码的内部,修改了参数的值,而且,这个参数的值是我们需要代出去的值,所以我们传递一级指针是不可以了,因为如果使用一级指针的话,我们同时在代码的内部修改了变量的内容,那么这个变量的内容其实是不可以被代出代码块外部的,所以,我们在对树进行销毁的时候,我们必须要传递二级指针才可以,所以代码需要写成下面的样子
    在这里插入图片描述
  • 最终的销毁结果如下所示:
    在这里插入图片描述
一些其他的操作:

在这里插入图片描述

  • 想要获取二叉树中结点的个数的话,那么我们直接求的话,其实是不好求的,但是我们只要知道了根节点左子树结点的个数,并且我们知道了根节点右子树的个数的话,那么我们只要将左子树结点的个数+右子树结点的个数,然后之后再+1就可以算出二叉树中结点的个数了
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
BinTree.h
#pragma once 


#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<string.h>

typedef int BTNDataTye;


typedef struct BTNode
{
	BTNDataTye data;
	struct BTNode* left;
	struct BTNode* right;
}BTNode;

void PreOrder(BTNode* root);

void InOrder(BTNode* root);

void PostOrder(BTNode* root);

//层序遍历需要用到队列的结构
//void LevelOrder(BTNode* root);

//获取二叉树中结点的个数
int GetNodeCount(BTNode* root);

//获取二叉树中叶子结点的个数
int GetLeafNodeCount(BTNode* root);

//获取二叉树第k层结点的个数
int GetKLevelNodeCount(BTNode* root);

//在二叉树中进行结点的查找
BTNode* Find(BTNode* root, BTNDataTye data);

//二叉树中结点的创建
BTNode* CreateNode(BTNDataTye data);

//二叉树的销毁操作
void DestroyTree(BTNode** root);

void TestBinTree();

BinTree.c
#include"BinTree.h"


void PreOrder(BTNode* root)
{
	if (root)
	{
		printf("%d", root->data);
		PreOrder(root->left);
		PreOrder(root->right);
	}
}

void InOrder(BTNode* root)
{
	if (root)
	{
		InOrder(root->left);
		printf("%d", root->data);
		InOrder(root->right);
	}
}

void PostOrder(BTNode* root)
{
	if (root)
	{
		PostOrder(root->left);
		PostOrder(root->right);
		printf("%d", root->data);
	}
}

//void LevelOrder(BTNode* root)
//{
//	Queue q;
//
//	//一进来之后,我们需要先检测一下树是不是为空的
//	if (root==NULL)
//	{
//		return;
//	}
//
//	//不空的话,正式开始操作
//	QueueInit(&q);
//	QueuePush(&q, root);
//
//	while (!QueueEmpty(&q))
//	{
//		BTNode* cur = QueueFront(&q);
//		printf("%d ", cur->data);
//		QueuePop(&q);
//		if (cur->left)
//		{
//			QueuePush(&q, cur->left);
//		}
//		if (cur->right)
//		{
//			QueuePush(&q, cur->right);
//		}
//	}
//	//循环走完之后,说明遍历结束
//	//记得最后要销毁
//	QueueDestroy(&q);
//}

//获取二叉树中结点的个数
int GetNodeCount(BTNode* root)
{
	/*if (root == NULL)
		return 0;
	int leftSize = GetNodeCount(root->left);
	int rightSize = GetNodeCount(root->right);
	return leftSize + rightSize + 1;*/

	if (root == NULL)
		return 0;
	else
		return GetNodeCount(root->left) + GetNodeCount(root->right) + 1;

	//当然还可以使用计数器的方法
}

//获取二叉树中叶子结点的个数
int GetLeafNodeCount(BTNode* root)
{

}

//获取二叉树第k层结点的个数
int GetKLevelNodeCount(BTNode* root);

//在二叉树中进行结点的查找
BTNode* Find(BTNode* root, BTNDataTye data);

//那么,现在,如果我们想要验证一下这几种方法是否是正确的,那么我们就可以先
//利用一种不那么正规的创建树的形式,我们先创建出来一棵树,从而对遍历的结果进行验证的操作
BTNode* CreateNode(BTNDataTye data)
{
	BTNode* pNewNode = (BTNode*)malloc(sizeof(BTNode));
	if (NULL == pNewNode)
	{
		assert(0);
		return NULL;
	}
	pNewNode->data = data;
	pNewNode->left = NULL;
	pNewNode->right = NULL;
	return pNewNode;
}

void DestroyTree(BTNode** root)
{
	//你要销毁一棵树的话,那么这棵树,首先是要存在的
	//然后,你才能去销毁他
	assert(root);   //root中的内容其实就是外部实参的地址
	if (*root)      //*root才是外部的实参
	{
		DestroyTree(&(*root)->left);    //先解引用拿到值,然后再取地址,就得到地址了
		DestroyTree(&(*root)->right);
		free(*root);
		*root = NULL;
	}
}


BTNode* CreateBinaryTree()
{
	BTNode* root = NULL;
	BTNode* n1 = CreateNode(1);
	BTNode* n2 = CreateNode(2);
	BTNode* n3 = CreateNode(3);
	BTNode* n4 = CreateNode(4);
	BTNode* n5 = CreateNode(5);
	BTNode* n6 = CreateNode(6);

	root = n1;
	root->left = n2;
	n2->left = n3;

	root->right = n4;
	n4->left = n5;
	n4->right = n6;

	return root;
}


//
//二叉树先简单的构造好之后就可以进行一系列的操作了

void TestBinTree()
{
	BTNode* root = CreateBinaryTree();
	printf("前序遍历结果为:\n");
	PreOrder(root);
	printf("\n");

	printf("中序遍历结果为:\n");
	InOrder(root);
	printf("\n");

	printf("后序遍历结果为:\n");
	PostOrder(root);
	printf("\n");

	printf("树中结点的个数为:%d\n", GetNodeCount(root));

	DestroyTree(&root);
}

  • 获取二叉树中叶子节点的个数
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 获取二叉树中第k层结点的个数
  • 那么现在有一个问题了,假设说,我这棵树,现在一共就只有3层的高度,我现在想要去求一下这棵树第10层一共有多少个结点,上面的代码还能正常运行吗?
  • 经过验证之后,发现代码返回的结果是0,如果要求第10层的话,那么就是求3哪个结点的第8层,那很显而易见,第8层是没有结点的,所以肯定会返回0
    在这里插入图片描述
  • 在二叉树中查找某个节点
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 获取二叉树的高度
    在这里插入图片描述
    在这里插入图片描述
  • 判断一棵树是不是完全二叉树
    在这里插入图片描述
    在这里插入图片描述
BinaryTree.h
#pragma once 


#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<string.h>

typedef int BTNDataTye;


typedef struct BTNode
{
	BTNDataTye data;
	struct BTNode* left;
	struct BTNode* right;
}BTNode;

void PreOrder(BTNode* root);

void InOrder(BTNode* root);

void PostOrder(BTNode* root);

//层序遍历需要用到队列的结构
//void LevelOrder(BTNode* root);

//获取二叉树中结点的个数
int GetNodeCount(BTNode* root);

//获取二叉树中叶子结点的个数
int GetLeafNodeCount(BTNode* root);

//获取二叉树第k层结点的个数
int GetKLevelNodeCount(BTNode* root,unsigned int k);

//获取二叉树的高度
int GetHeight(BTNode* root);

//判断一棵树是否是完全二叉树
int BinaryTreeComplete(BTNode* root);

//在二叉树中进行结点的查找
BTNode* Find(BTNode* root, BTNDataTye data);

//二叉树中结点的创建
BTNode* CreateNode(BTNDataTye data);

//二叉树的销毁操作
void DestroyTree(BTNode** root);

void TestBinTree();

BinaryTree.c
#include"BinTree.h"


void PreOrder(BTNode* root)
{
	if (root)
	{
		printf("%d", root->data);
		PreOrder(root->left);
		PreOrder(root->right);
	}
}

void InOrder(BTNode* root)
{
	if (root)
	{
		InOrder(root->left);
		printf("%d", root->data);
		InOrder(root->right);
	}
}

void PostOrder(BTNode* root)
{
	if (root)
	{
		PostOrder(root->left);
		PostOrder(root->right);
		printf("%d", root->data);
	}
}

//void LevelOrder(BTNode* root)
//{
//	Queue q;
//
//	//一进来之后,我们需要先检测一下树是不是为空的
//	if (root==NULL)
//	{
//		return;
//	}
//
//	//不空的话,正式开始操作
//	QueueInit(&q);
//	QueuePush(&q, root);
//
//	while (!QueueEmpty(&q))
//	{
//		BTNode* cur = QueueFront(&q);
//		printf("%d ", cur->data);
//		QueuePop(&q);
//		if (cur->left)
//		{
//			QueuePush(&q, cur->left);
//		}
//		if (cur->right)
//		{
//			QueuePush(&q, cur->right);
//		}
//	}
//	//循环走完之后,说明遍历结束
//	//记得最后要销毁
//	QueueDestroy(&q);
//}

//获取二叉树中结点的个数
int GetNodeCount(BTNode* root)
{
	/*if (root == NULL)
		return 0;
	int leftSize = GetNodeCount(root->left);
	int rightSize = GetNodeCount(root->right);
	return leftSize + rightSize + 1;*/

	if (root == NULL)
		return 0;
	else
		return GetNodeCount(root->left) + GetNodeCount(root->right) + 1;

	//当然还可以使用计数器的方法
}

//获取二叉树中叶子结点的个数
int GetLeafNodeCount(BTNode* root)
{
	if (root == NULL)
		return 0;
	if (root->left == NULL && root->right == NULL)
		return 1;
	return GetLeafNodeCount(root->left) + GetLeafNodeCount(root->right);
}

//获取二叉树第k层结点的个数
int GetKLevelNodeCount(BTNode* root, unsigned int k)
{
	if (root == NULL || k == 0)
		return 0;
	if (k == 1)
		return 1;
	//如果现在想直接求二叉树第k层中结点的个数,那么其实是不好求的
	//所以我们讲其转换为子问题来进行求解
	//那么其实就是再求子树中第k-1层结点的个数
	return GetKLevelNodeCount(root->left, k - 1) + GetKLevelNodeCount(root->right, k - 1);
}

//在二叉树中进行结点的查找
BTNode* Find(BTNode* root, BTNDataTye data)
{
	if (root == NULL)
		return NULL;
	if (root->data == data)
		return root;
	return Find(root->left, data) || Find(root->right, data);
}

int GetHeight(BTNode* root)
{
	if (root == NULL)
		return 0;
	int leftheigth = 0;
	int rightheight = 0;
	leftheigth = GetHeight(root->left);
	rightheight = GetHeight(root->right);
	return leftheigth > rightheight ? leftheigth + 1 : rightheight + 1;
}

int BinaryTreeComplete(BTNode* root)
{
	Queue q;

	int flag = 0;
	int ret = 0;


	//空树也是完全二叉树
	if (root == NULL)
		return 1;

	//如果非空的话,那么就先把根节点放进去
	QueueInit(&q);
	QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* cur = QueueFront(&q);

		if (flag)
		{
			//后续的结点都不能有孩子
			if (cur->left || cur->right)
				break;
		}
		else   //就去找第一个不饱和的结点
		{
			if (cur->left && cur->right)
			{
				QueuePush(&q, cur->left);
				QueuePush(&q, cur->right);
			}
			else if (cur->left)
			{
				//cur只有左孩子,那么现在临界的条件就找到了
				QueuePush(cur->left);
				flag = 1;
			}
			else if (cur->right)
			{
				//cur 只有右孩子
				 break;
			}
			else
			{
				flag = 1;
			}
		}

		QueuePop(&q);//把元素拿出来之后,让循环继续进行
	}
	
	if (QueueEmpty(&q))
		ret = 1;

	QueueDestroy(&q);

	return ret;
}


//那么,现在,如果我们想要验证一下这几种方法是否是正确的,那么我们就可以先
//利用一种不那么正规的创建树的形式,我们先创建出来一棵树,从而对遍历的结果进行验证的操作
BTNode* CreateNode(BTNDataTye data)
{
	BTNode* pNewNode = (BTNode*)malloc(sizeof(BTNode));
	if (NULL == pNewNode)
	{
		assert(0);
		return NULL;
	}
	pNewNode->data = data;
	pNewNode->left = NULL;
	pNewNode->right = NULL;
	return pNewNode;
}

void DestroyTree(BTNode** root)
{
	//你要销毁一棵树的话,那么这棵树,首先是要存在的
	//然后,你才能去销毁他
	assert(root);   //root中的内容其实就是外部实参的地址
	if (*root)      //*root才是外部的实参
	{
		DestroyTree(&(*root)->left);    //先解引用拿到值,然后再取地址,就得到地址了
		DestroyTree(&(*root)->right);
		free(*root);
		*root = NULL;
	}
}


BTNode* CreateBinaryTree()
{
	BTNode* root = NULL;
	BTNode* n1 = CreateNode(1);
	BTNode* n2 = CreateNode(2);
	BTNode* n3 = CreateNode(3);
	BTNode* n4 = CreateNode(4);
	BTNode* n5 = CreateNode(5);
	BTNode* n6 = CreateNode(6);

	root = n1;
	root->left = n2;
	n2->left = n3;

	root->right = n4;
	n4->left = n5;
	n4->right = n6;

	return root;
}


//
//二叉树先简单的构造好之后就可以进行一系列的操作了

void TestBinTree()
{
	BTNode* root = CreateBinaryTree();
	printf("前序遍历结果为:\n");
	PreOrder(root);
	printf("\n");

	printf("中序遍历结果为:\n");
	InOrder(root);
	printf("\n");

	printf("后序遍历结果为:\n");
	PostOrder(root);
	printf("\n");

	printf("树中结点的个数为:%d\n", GetNodeCount(root));

	printf("树中叶子结点的个数为:%d\n", GetLeafNodeCount(root));

	printf("树中第k层结点的个数为:%d\n", GetKLevelNodeCount(root,3));

	BTNode* cur = Find(root, 4);
	if (cur != NULL)
	{
		printf("4 is in the tree\n");
	}
	else
	{
		printf("4 is not in the tree\n");
	}

	printf("树的高度为:%d\n", GetHeight(root));

	DestroyTree(&root);
}
二叉树的拷贝
  • 拷贝的操作其实和我们前面所给出二叉树的遍历操作是一个概念
  • 根据二叉树的概念可以得知,空树也是属于二叉树的,如果二叉树非空的话,那么二叉树就是由根节点,根节点的左子树以及根节点的右子树组成,那么我们在进行二叉树的拷贝的时候,就去先拷贝二叉树的根节点
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
二叉树的创建
  • 因为之前虽然说我们把树给出来了,但是当时所给出的二叉树的创建方式并不是真正的二叉树的创建方式,现在需要给出真正的二叉树的创建方式(当时只是给出了一种简单的方式把那颗二叉树模拟出来了)
  • 一开始创建的时候我需要先去创建根节点,我们要先把根节点创建出来,然后去创建根节点的左子树和根节点的右子树
  • 按照上面的思路,可以写出像下面这样的代码
//array数组中保存的是二叉树中所有结点的值域
BTNode* CreateBinTree(int array[], int size,int index)
{
	BTNode* root = NULL;

	if (index < size)
	{
		root = CreateNode(array[index]);
		//然后去创建根节点的左子树
		root->left = CreateBinTree(array, size, ++index);
		//然后去创建根节点的右子树
		root->right = CreateBinTree(array, size, ++index);
	}
	return root;
}
  • 那我们现在写好了代码之后,就需要对我们所写好的代码来进行验证,那么我现在需要创建一棵二叉树,我就需要把二叉树中的结点全部保存在数组中,那么,现在问题又来了,我们数组中元素的序列应该如何给出呢?
    在这里插入图片描述
    在这里插入图片描述
  • 但是像上面那样写的话,其实是有问题的,因为上面的代码会给我们创建出来一棵单支树,因为从该序列中无法确定某个结点的子树是否存在,所以我们需要对之前所给出的序列来进行一系列的调整,如果某个结点是没有左右子树的,那么我们需要对其来进行标记,从而表明这个结点时没有左右子树的
    在这里插入图片描述
  • #表示这个结点并不存在,如果遇到#就表示这个结点是没有的。
    在这里插入图片描述
  • 所以我们需要对上面所写出的代码进行一些调整
    在这里插入图片描述
  • 但是按照上图这样改完代码之后,其实这个代码还是有问题的,问题出现在index参数上,原因如下图所示
    在这里插入图片描述
    在这里插入图片描述
//array数组中保存的是二叉树中所有结点的值域
BTNode* CreateBinaryTree(int array[], int size, int *index,int invalid)
{
	BTNode* root = NULL;

	if (*index < size && invalid != array[*index])
	{
		root = CreateNode(array[*index]);

		//然后去创建根节点的左子树
		++(*index);
		root->left = CreateBinaryTree(array, size, index,invalid);

		//然后去创建根节点的右子树
		++(*index);
		root->right = CreateBinaryTree(array, size, index,invalid);
	}
	return root;
}
BinTree.h
#pragma once 


#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<string.h>

typedef int BTNDataTye;


typedef struct BTNode
{
	BTNDataTye data;
	struct BTNode* left;
	struct BTNode* right;
}BTNode;

void PreOrder(BTNode* root);

void InOrder(BTNode* root);

void PostOrder(BTNode* root);

//层序遍历需要用到队列的结构
//void LevelOrder(BTNode* root);

//获取二叉树中结点的个数
int GetNodeCount(BTNode* root);

//获取二叉树中叶子结点的个数
int GetLeafNodeCount(BTNode* root);

//获取二叉树第k层结点的个数
int GetKLevelNodeCount(BTNode* root, unsigned int k);

//获取二叉树的高度
int GetHeight(BTNode* root);

//判断一棵树是否是完全二叉树
int BinaryTreeComplete(BTNode* root);

//在二叉树中进行结点的查找
BTNode* Find(BTNode* root, BTNDataTye data);

//二叉树中结点的创建
BTNode* CreateNode(BTNDataTye data);

//二叉树的销毁操作
void DestroyTree(BTNode** root);

//二叉树的拷贝操纵
BTNode *CopyBinTree(BTNode* root);

//二叉树的创建
BTNode* CreateBinaryTree(int array[], int size, int* index, int invalid);


/
void TestBinTree();
BinTree.c
#include"Tree.h"


void PreOrder(BTNode* root)
{
	if (root)
	{
		printf("%d ", root->data);
		PreOrder(root->left);
		PreOrder(root->right);
	}
}

void InOrder(BTNode* root)
{
	if (root)
	{
		InOrder(root->left);
		printf("%d ", root->data);
		InOrder(root->right);
	}
}

void PostOrder(BTNode* root)
{
	if (root)
	{
		PostOrder(root->left);
		PostOrder(root->right);
		printf("%d ", root->data);
	}
}

//void LevelOrder(BTNode* root)
//{
//	Queue q;
//
//	//一进来之后,我们需要先检测一下树是不是为空的
//	if (root==NULL)
//	{
//		return;
//	}
//
//	//不空的话,正式开始操作
//	QueueInit(&q);
//	QueuePush(&q, root);
//
//	while (!QueueEmpty(&q))
//	{
//		BTNode* cur = QueueFront(&q);
//		printf("%d ", cur->data);
//		QueuePop(&q);
//		if (cur->left)
//		{
//			QueuePush(&q, cur->left);
//		}
//		if (cur->right)
//		{
//			QueuePush(&q, cur->right);
//		}
//	}
//	//循环走完之后,说明遍历结束
//	//记得最后要销毁
//	QueueDestroy(&q);
//}

//获取二叉树中结点的个数
int GetNodeCount(BTNode* root)
{
	/*if (root == NULL)
		return 0;
	int leftSize = GetNodeCount(root->left);
	int rightSize = GetNodeCount(root->right);
	return leftSize + rightSize + 1;*/

	if (root == NULL)
		return 0;
	else
		return GetNodeCount(root->left) + GetNodeCount(root->right) + 1;

	//当然还可以使用计数器的方法
}

//获取二叉树中叶子结点的个数
int GetLeafNodeCount(BTNode* root)
{
	if (root == NULL)
		return 0;
	if (root->left == NULL && root->right == NULL)
		return 1;
	return GetLeafNodeCount(root->left) + GetLeafNodeCount(root->right);
}

//获取二叉树第k层结点的个数
int GetKLevelNodeCount(BTNode* root, unsigned int k)
{
	if (root == NULL || k == 0)
		return 0;
	if (k == 1)
		return 1;
	//如果现在想直接求二叉树第k层中结点的个数,那么其实是不好求的
	//所以我们讲其转换为子问题来进行求解
	//那么其实就是再求子树中第k-1层结点的个数
	return GetKLevelNodeCount(root->left, k - 1) + GetKLevelNodeCount(root->right, k - 1);
}

//在二叉树中进行结点的查找
BTNode* Find(BTNode* root, BTNDataTye data)
{
	BTNode* ret = NULL;
	if (root == NULL)
		return NULL;
	if (root->data == data)
		return root;
	(ret = Find(root->left, data)) || (ret = Find(root->right, data));
	return ret;
}

int GetHeight(BTNode* root)
{
	if (root == NULL)
		return 0;
	int leftheigth = 0;
	int rightheight = 0;
	leftheigth = GetHeight(root->left);
	rightheight = GetHeight(root->right);
	return leftheigth > rightheight ? leftheigth + 1 : rightheight + 1;
}

//int BinaryTreeComplete(BTNode* root)
//{
//	Queue q;
//
//	int flag = 0;
//	int ret = 0;
//
//
//	//空树也是完全二叉树
//	if (root == NULL)
//		return 1;
//
//	//如果非空的话,那么就先把根节点放进去
//	QueueInit(&q);
//	QueuePush(&q, root);
//	while (!QueueEmpty(&q))
//	{
//		BTNode* cur = QueueFront(&q);
//
//		if (flag)
//		{
//			//后续的结点都不能有孩子
//			if (cur->left || cur->right)
//				break;
//		}
//		else   //就去找第一个不饱和的结点
//		{
//			if (cur->left && cur->right)
//			{
//				QueuePush(&q, cur->left);
//				QueuePush(&q, cur->right);
//			}
//			else if (cur->left)
//			{
//				//cur只有左孩子,那么现在临界的条件就找到了
//				QueuePush(cur->left);
//				flag = 1;
//			}
//			else if (cur->right)
//			{
//				//cur 只有右孩子
//				break;
//			}
//			else
//			{
//				flag = 1;
//			}
//		}
//
//		QueuePop(&q);//把元素拿出来之后,让循环继续进行
//	}
//
//	if (QueueEmpty(&q))
//		ret = 1;
//
//	QueueDestroy(&q);
//
//	return ret;
//}


//那么,现在,如果我们想要验证一下这几种方法是否是正确的,那么我们就可以先
//利用一种不那么正规的创建树的形式,我们先创建出来一棵树,从而对遍历的结果进行验证的操作
BTNode* CreateNode(BTNDataTye data)
{
	BTNode* pNewNode = (BTNode*)malloc(sizeof(BTNode));
	if (NULL == pNewNode)
	{
		assert(0);
		return NULL;
	}
	pNewNode->data = data;
	pNewNode->left = NULL;
	pNewNode->right = NULL;
	return pNewNode;
}

void DestroyTree(BTNode** root)
{
	//你要销毁一棵树的话,那么这棵树,首先是要存在的
	//然后,你才能去销毁他
	assert(root);   //root中的内容其实就是外部实参的地址
	if (*root)      //*root才是外部的实参
	{
		DestroyTree(&(*root)->left);    //先解引用拿到值,然后再取地址,就得到地址了
		DestroyTree(&(*root)->right);
		free(*root);
		*root = NULL;
	}
}

BTNode *CopyBinTree(BTNode* root)
{
	//进行二叉树的拷贝
	//首先要进行根节点的拷贝
	BTNode* NewRoot = NULL;
	if (root)
	{
		NewRoot = CreateNode(root->data);
		NewRoot->left = CopyBinTree(root->left);
		NewRoot->right = CopyBinTree(root->right);
	}
	return NewRoot;
}

//array数组中保存的是二叉树中所有结点的值域
BTNode* CreateBinaryTree(int array[], int size, int *index,int invalid)
{
	BTNode* root = NULL;

	if (*index < size && invalid != array[*index])
	{
		root = CreateNode(array[*index]);

		//然后去创建根节点的左子树
		++(*index);
		root->left = CreateBinaryTree(array, size, index,invalid);

		//然后去创建根节点的右子树
		++(*index);
		root->right = CreateBinaryTree(array, size, index,invalid);
	}
	return root;
}


//
//二叉树先简单的构造好之后就可以进行一系列的操作了

void TestBinTree()
{
	int array[] = { 1,2,3,-1,-1,-1,4,5,-1,-1,6 };

	int index = 0;

	BTNode* root = CreateBinaryTree(array,sizeof(array)/sizeof(array[0]),&index,-1);

	BTNode* NewRoot = NULL;

	printf("前序遍历结果为:\n");
	PreOrder(root);
	printf("\n");

	printf("中序遍历结果为:\n");
	InOrder(root);
	printf("\n");

	printf("后序遍历结果为:\n");
	PostOrder(root);
	printf("\n");

	printf("树中结点的个数为:%d\n", GetNodeCount(root));

	printf("树中叶子结点的个数为:%d\n", GetLeafNodeCount(root));

	printf("树中第k层结点的个数为:%d\n", GetKLevelNodeCount(root, 3));

	BTNode* cur = Find(root, 4);
	if (cur != NULL)
	{
		printf("4 is in the tree\n");
	}
	else
	{
		printf("4 is not in the tree\n");
	}

	printf("树的高度为:%d\n", GetHeight(root));

	//用root来拷贝这棵新的树

	NewRoot = CopyBinTree(root);

	printf("前序遍历结果为:\n");
	PreOrder(root);
	printf("\n");

	printf("中序遍历结果为:\n");
	InOrder(root);
	printf("\n");

	printf("后序遍历结果为:\n");
	PostOrder(root);
	printf("\n");

	DestroyTree(&root);

	DestroyTree(&NewRoot);

}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值