一、二叉树链式结构
//二叉树链式存储结构定义:
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;
}
二、二叉树遍历方式
- 前序遍历:根节点 =》 左节点 =》右节点;
- 中序遍历:左节点 =》 根节点 =》右节点;
- 后序遍历:左节点 =》 右节点 =》 根节点;
- 层序遍历:
//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
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); }
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); }
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); }
//计算数的大小用于开辟数组空间 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; }
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); }