二叉树实现(2)

1、构建二叉树

BTNode* BuyNode(BTDataType x)
{
	BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
	if (newnode == NULL)
	{
		perror("malloc failed");
		exit(1);
	}
	newnode->data = x;
	newnode->right = newnode->left = NULL;

	return newnode;
}

// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int* pi)
{
	
		if (a[*pi] == '#')
		{
			(*pi)++;
			return NULL;
		}

		BTNode* root = BuyNode(a[(*pi)++]);
		root->left = BinaryTreeCreate(a, pi);
		root->right = BinaryTreeCreate(a, pi);
		return root;
}

将一串字符串里面的字符作为二叉树每个节点的元素,构建二叉树;当字符是‘#’的时候就是NULL,其他的元素正常构建;

采用前序遍历的方式构建:先构建根节点,之后再构建左子树和右子树,最后返回root根节点;

无论访问到字符串里面的哪种元素都要让 i++ ,i代表的是存放字符串的数组的下标,通过下标课访问到字符串里面的元素;

 通过前序遍历打印构建好的二叉树;

2 、二叉树销毁

// 二叉树销毁
void BinaryTreeDestory(BTNode** root)
{
	if (*root == NULL)
	{
		return;//销毁到叶子节点的空节点就停止
	}

	BinaryTreeDestory(&((*root)->left));
	BinaryTreeDestory(&((*root)->right));
	free(*root);
}

先销毁左右子树,再销毁根节点;当左右子树都是NULL的时候返回回来就可以开始销毁根节点了;

若先销毁根节点那就找不到左右子树了,还要提前存一份根节点;

3、层序遍历

层序遍历就是先遍历二叉树第一层的再遍历第二层的,依次遍历后面的层;

方法是利用上一层的带动下一层的;

首先将根节点存放在队列里面,设置一个临时变量存放这个根节点,每次把根节点的数据打印之后,就让队列出一个数据,之后再通过临时变量的左右指针找到左右指针指向的左右子树的根节点,若是这两个根节点不是NULL,就把这两个节点插入队列;下一次循环还是先打印队列对头的节点,再删除它,每次都要判断删除掉的节点的左右指针指向的节点是不是空,不是空就插入队列;

这样就实现了上一层的带动下一层的;并且因为上一层是先进入队列的,所以当上一层的数据没有出完的时候,下一层的数据是不会打印并且出队列的,这样就实现了层序遍历;

代码:

// 层序遍历
//上一层带动下一层的;利用队列出数据
void BinaryTreeLevelOrder(BTNode* root)
{
	if (root == NULL) return;

	Queue q;
	QueueInit(&q);
	QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		printf("%c ", front->data);

		if (front->left)
		{
			QueuePush(&q, front->left);
		}
		if (front->right)
		{
			QueuePush(&q, front->right);
		}
	}
}

要把队列的数据类型定义为树节点指针类型;

 4、判断二叉树是否是完全二叉树

完全二叉树的最后一层的节点都是连续摆放的,也就是说,完全二叉树最后一层的节点之间不可能有空节点;

利用这个结构,和层序遍历一样,先将二叉树的根节点放到队列里面,再删除并且带动左右节点;判断删除的元素是不是空,若是空,就跳出循环,若二叉树不是完全二叉树,那么队列里面剩下的节点肯定还有不为空的节点,遍历剩下的节点,有不是空的节点就返回false,说明这个二叉树不是完全二叉树;

为什么不是二叉树的时候,队里里面空节点的数据后面一定还有不为空的节点?首先当遍历到第一个为空的节点就跳出循环,它所在的上一层的节点都已经遍历完,那么它上一层所有节点的左右节点都已经存放到队列里面了(删除队列里面的根节点和存放这个根节点的左右节点的动作是同一次循环进行的),那么这些左右节点一定有放到这个空节点后面的节点吗,若是空节点后面都是空节点,那么就说明最后一层的节点是连续摆放的了,那么二叉树就是完全二叉树,和假设不是二叉树的情况不符合;

// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{
	if (root == NULL) return true;//空也是二叉树

	//利用入出数据,此时是空树节点也入;
	//出数据的时候若是出到空数节点就跳出循环;
	//此时再去看队列后面的节点,若是有不为空树节点的数据就说明这不是完全二叉树
	Queue q;
	QueueInit(&q);
	QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		if (front == NULL)
		{
			break;
		}
		QueuePop(&q);
		//printf("%c ", front->data);

		QueuePush(&q, front->left);
		QueuePush(&q, front->right);
	}

	while (!QueueEmpty(&q))
	{
		BTNode* tmp = QueueFront(&q);
		QueuePop(&q);
		if (tmp != NULL)
		{
			return false;
		}
	}
	return true;
}

画出这行字符串构建好的二叉树,可以发现最后一层只有一个节点H,并且最后一层H节点的前面只有空节点,所以它不是完全二叉树;。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值