二叉树(二)

一、二叉树链式结构

//二叉树链式存储结构定义:
typedef int BTDataType;
typedef struct BT {
	struct BT* pleft;
	struct BT* pright;
	BTDataType val;
}BTNode;

//二叉树节点创建:
BTNode* BuyNode(BTDataType val) {
	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	if (node == NULL) {
		printf("malloc fail\n");
		exit(-1);
	}
	node->val = val;
	node->pleft = node->pright = NULL;
	return node;
}

//将创建的节点连接:
BTNode* Test() {
	BTNode* n1 = BuyNode(1);
	BTNode* n2 = BuyNode(2);
	BTNode* n3 = BuyNode(3);
	BTNode* n4 = BuyNode(4);
	BTNode* n5 = BuyNode(5);
	BTNode* n6 = BuyNode(6);
	n1->pleft = n2;
	n2->pleft = n3;
	n1->pright = n4;
	n4->pleft = n5;
	n4->pright = n6;

	return n1;
}

二、二叉树遍历方式

  1. 前序遍历:根节点 =》 左节点 =》右节点;
  2. 中序遍历:左节点 =》 根节点 =》右节点;
  3. 后序遍历:左节点 =》 右节点 =》 根节点;
  4. 层序遍历:
//n:表示链式结构的二叉树的根节点

//前序遍历: 根  左  右
void prevOrder(BTNode* n) {
	if (n == NULL) {
		printf("NULL ");
		return;
	}

	printf("%d ", n->val);
	prevOrder(n->pleft);
	prevOrder(n->pright);

}

//中序遍历: 左  根  右
void MidOrder(BTNode* n) {
	if (n == NULL) {
		printf("NULL ");
		return;
	}

	MidOrder(n->pleft);
	printf("%d ", n->val);
	MidOrder(n->pright);

}

//后序遍历: 左  右  中
void BehOrder(BTNode* n) {
	if (n == NULL) {
		printf("NULL ");
		return;
	}
	BehOrder(n->pleft);
	BehOrder(n->pright);
	printf("%d ", n->val);
}

上述三种遍历方法均使用递归的方法实现,接下来一前序遍历为例详细解释代码实现:

//层序遍历通过队列实现,将树中的数据按“一定顺序”放入队列中
//再将队列数据拿出来:

//这里涉及到队列的函数方法:
//https://blog.csdn.net/qq_61847875/article/details/134344642?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22134344642%22%2C%22source%22%3A%22qq_61847875%22%7D

//先将根节点放在队列中:当队列不为空的时候,拿到队列的头节点放在node中,并将头节点删除后
//再将node的左右节点放进队列中。
void LevelOrder(BNode * root) {
	Queue q;
	QueueInit(&q);
	if (root != NULL)
		QueuePush(&q, root);
	while (!QueueEmpty(&q)) {
		BNode* head = QueueHead(&q);
		QueuePop(&q);
		printf("%d ", head->val);
		if (head->left)
			QueuePush(&q, head->left);
		if (head->right)
			QueuePush(&q, head->right);
	}
	QueueDestory(&q);
}

每从队列中拿出一个节点,该节点的左右孩子就会被放进去:当1被pop出去时,其左右孩子2,3就会被放进去;2被pop出来时,其左右孩子4,5就会被push进去,如此一来,树中的节点会一一push进去,在被pop出来,实现层序遍历。

求二叉树节点个数

// 节点个数

//方法一:count作为全局变量
int count = 0;
void BTSize(BTNode* n) {
	if (n == NULL)
		return 0;
	count++;
	BTSize(n->pleft);
	BTSize(n->pright);
}

//方法二:
int BTSize(BTNode* n) {

	return n == NULL ? 0 : BTSize(n->pleft) + BTSize(n->pright) + 1;
}

 方法二的详细图解,对递归来说,最重要就是理解过程。

求二叉树叶子结点个数

int BTleafSize(BTNode* n) {
	if (n == NULL)
		return 0;
	if (n->pleft == NULL && n->pright == NULL)
		return 1;
	return BTleafSize(n->pleft) + BTleafSize(n->pright);
}

求二叉树k层节点个数

int BTlevelKSize(BTNode* n, int k) {
	assert(k >= 1);
	if (n == NULL)
		return 0;
	if (k == 1)
		return 1;

	return BTlevelKSize(n->pleft, k - 1) + BTlevelKSize(n->pright, k - 1);
}

求二叉树高度

int BTDepth(BTNode* n) {
	assert(n);
	if (n == NULL)
		return 0;
	int leftDepth = BTDepth(n->pleft);
	int rightDepth = BTDepth(n->pright);
	return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;

}

查找二叉树节点

BTNode* BTreeFind(BTNode* root, BTDataType val) {
	if (root == NULL)
		return NULL;
	if (root->val == val)
		return root;

	BTNode* leftRet = BTreeFind(root->pleft, val);
	if (leftRet)
		return leftRet;
	
	BTNode* rightRet = BTreeFind(root->pright, val);
	if (rightRet)
		return rightRet;
	
	return NULL;
}

判断是否为完全二叉树

//依然用到队列的某些函数方法:
void isCompleteBTree(BNode* root) {
	Queue q;
	QueueInit(&q);
	if (root)
		QueuePush(&q, root);

	while (!QueueEmpty(&q)) {
		BNode* node = QueueHead(&q);
		QueuePop(&q);
		if (node)
			break;
		QueuePush(&q, node->left);
		QueuePush(&q, node->right);
	}

	while (!QueueEmpty(&q)) {
		BNode* tmp = QueueHead(&q);
		QueuePop(&q);
		if (tmp)
			QueueDestory(&q);
			return false;
	}
	return true;
}

如上图,第一个while循环里面。不管节点是否为空都放入队列中,当出现node为NULL时,跳出第一个while,也就是说node前面的节点都是非空的,都是可以构成完全二叉树的;

第二个while循环里面,只有当后半段队列中全是NULL时,才能构成完全二叉树,否则就不是。

三、力扣OJ 

965. 单值二叉树 - 力扣(LeetCode)

bool isUnivalTree(struct TreeNode* root) {
    if(root==NULL)
        return true;
    
    //如果数据符合就继续往下走
    //不符合就返回false

    //左孩子存在且数据不符合:
    if(root->left && root->left->val != root->val)
        return false;

    //右孩子存在且数据不符合:
    if(root->right && root->right->val != root->val)
        return false;
        
    return isUnivalTree(root->right) && isUnivalTree(root->left);
}

 

100. 相同的树 - 力扣(LeetCode)

bool sameBTree(BTNode* root1, BTNode* root2) {
    //两棵树都为空
	if (root1 == NULL && root2 == NULL)
		return true;
    
    //一个不为空,一个为空
	if (root1 == NULL || root2 == NULL)
		return false;

    //都不为空:不相等的时候返回
    //         相等返回true没有意义
	if (root1->val != root2->val)
		return false;

    //各自递归比较root1和root2的左右子树
	return sameBTree(root1->pleft, root2->pleft) 
		&& sameBTree(root1->pright, root2->pright);
}

101. 对称二叉树 - 力扣(LeetCode)

bool issymmetricTree(BTNode* root1, BTNode* root2) {
    //左右子树为空
	if (root1 == NULL && root2 == NULL)
		return true;

    //左右子树有一个为空
	if (root1 == NULL || root2 == NULL)
		return false;

    //左子树跟右子树比:
	return root1->val == root2->val
		&& issymmetricTree(root1->pleft, root2->pright)
		&& issymmetricTree(root1->pright, root2->pleft);
}
bool isSymmetric(BTNode* root) {
    //空树:直接返回
	if (root == NULL)
		return true;

    //将左右子树各自看作单独的数:
	return isSymmetricTree(root->pleft, root->pright);
}

144. 二叉树的前序遍历 - 力扣(LeetCode)

//计算数的大小用于开辟数组空间
int Treesize(struct TreeNode* root){
    return root == NULL ? 0 : Treesize(root->left)+Treesize(root->right) + 1;
}

//通过前序遍历的方式将数中数据放入数组中
void preorder(struct TreeNode* root,int* a,int*p){
    if(root ==NULL)
        return;
    a[(*p)++] = root->val;
    preorder(root->left,a,p);
    preorder(root->right,a,p);
}

int* preorderTraversal(struct TreeNode* root, int* returnSize) {
    int size = Treesize(root);
    int *a = malloc(sizeof(int)*size);
    *returnSize = size;
    int i=0;
    preorder(root,a,&i);
    return a;
}

572. 另一棵树的子树 - 力扣(LeetCode)

bool isSameTree(struct TreeNode*root1,struct TreeNode*root2){
    if(root1==NULL&&root2==NULL)
        return true;

    if(root1==NULL||root2==NULL)
        return false;

    if(root1->val!=root2->val)
        return false;

    return isSameTree(root1->left,root2->left)
        &&isSameTree(root1->right,root2->right);

}

//root树中的每个子树都与sunRoot进行比较
bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot){
    //root为空直接返回
    if(root==NULL)
    return false;
    
    //第一次判断根root与子根subRoot是不是子树
    //第二次判断左子树
    //第三次判断右子树
    return isSameTree(root,subRoot)||
        isSubtree(root->left,subRoot)||
        isSubtree(root->right,subRoot);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值