当前位置:   article > 正文

【数据结构】二叉树的链式结构

【数据结构】二叉树的链式结构

目录

一.二叉树的遍历

1.前序遍历

2.中序遍历

3.后序遍历

4.层序遍历

二.二叉树查询的基本操作

1.二叉树节点的个数

2.二叉树叶子节点的个数

3.二叉树的高度

4.二叉树第k层节点的个数

5.二叉树查询值为x的节点

6.判断二叉树是否为完全二叉树

7.二叉树基础oj练习

三.二叉树的创建和销毁

1.创建

2.销毁


一.二叉树的遍历

学习二叉树结构,最简单的方式就是遍历。所谓二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉 树中的节点进行相应的操作,并且每个节点只操作一次。访问结点所做的操作依赖于具体的应用问题。 遍历 是二叉树上最重要的运算之一,也是二叉树上进行其它运算的基础。

为了使遍历更加的形象,在这里我们先受搓一颗二叉树来说明二叉树的遍历。

  1. typedef int BTDataType;
  2. typedef struct BinaryTreeNode
  3. {
  4. BTDataType data;
  5. struct BinaryTreeNode* left;
  6. struct BinaryTreeNode* right;
  7. }BTNode;
  8. BTNode* BuyNode(BTDataType x)
  9. {
  10. BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
  11. if (newnode == NULL)
  12. {
  13. perror("malloc");
  14. return;
  15. }
  16. newnode->data = x;
  17. newnode->left = NULL;
  18. newnode->right = NULL;
  19. return newnode;
  20. }
  21. BTNode* CreateBinaryTree()
  22. {
  23. BTNode* node1 = BuyNode(1);
  24. BTNode* node2 = BuyNode(2);
  25. BTNode* node3 = BuyNode(3);
  26. BTNode* node4 = BuyNode(4);
  27. BTNode* node5 = BuyNode(5);
  28. BTNode* node6 = BuyNode(6);
  29. node1->left = node2;
  30. node1->right = node4;
  31. node2->left = node3;
  32. node4->left = node5;
  33. node4->right = node6;
  34. return node1;
  35. }

注意:上述代码并不是创建二叉树的方式 

再看二叉树基本操作前,再回顾下二叉树的概念,二叉树是:

1. 空树

2. 非空:根节点,根节点的左子树、根节点的右子树组成的。

从概念中可以看出,二叉树定义是递归式的,因此后序基本操作中基本都是按照该概念实现的。 

1.前序遍历

前序遍历是以根———左子树——右子树的顺序进行遍历的。

这里的N表示的是NULL。

用代码表示:

  1. void PreOrder(BTNode* root)
  2. {
  3. if (root == NULL)
  4. {
  5. printf("N ");
  6. return;
  7. }
  8. printf("%d ", root->data);
  9. PreOrder(root->left);
  10. PreOrder(root->right);
  11. }

2.中序遍历

前序遍历是以左子树———根——右子树的顺序进行遍历的。

用代码表示:

  1. void MiddleOrder(BTNode* root)
  2. {
  3. if (root == NULL)
  4. {
  5. printf("N ");
  6. return;
  7. }
  8. MiddleOrder(root->left);
  9. printf("%d ", root->data);
  10. MiddleOrder(root->right);
  11. }

3.后序遍历

前序遍历是以左子树———右子树——根的顺序进行遍历的。

用代码表示:

  1. void PostOrder(BTNode* root)
  2. {
  3. if (root == NULL)
  4. {
  5. printf("N ");
  6. return;
  7. }
  8. PostOrder(root->left);
  9. PostOrder(root->right);
  10. printf("%d ", root->data);
  11. }

4.层序遍历

层序遍历需要用到队列的代码,所以我们要将之前队列的代码【数据结构】栈和队列-CSDN博客移动到现在所在的工程文件中。

思路:首先创建一个队列,将二叉树的根节点插入到队列当中。接着用while循环判断队列是否为空作为判断条件,pop掉队头的数据,然后将队头数据的左右子树分别带出来,前提是左右子树都不为空。最后销毁队列就可以了。

  1. void TreeLevelOrder(BTNode* root)
  2. {
  3. Queue pq;
  4. QueueInit(&pq);
  5. if (root)
  6. {
  7. QueuePush(&pq, root);
  8. }
  9. while (!QueueEmpty(&pq))
  10. {
  11. BTNode* front = QueueFront(&pq);
  12. QueuePop(&pq);
  13. printf("%d ", front->data);
  14. if (front->left)
  15. {
  16. QueuePush(&pq, front->left);
  17. }
  18. if (front->right)
  19. {
  20. QueuePush(&pq, front->right);
  21. }
  22. }
  23. QueueDestroy(&pq);
  24. }

二.二叉树查询的基本操作

1.二叉树节点的个数

  1. int BinaryTreeSize(BTNode* root)
  2. {
  3. if (root == NULL)
  4. {
  5. return 0;
  6. }
  7. int left = BinaryTreeSize(root->left);
  8. int right = BinaryTreeSize(root->right);
  9. return left + right + 1;
  10. }

在这里,我们采用递归的方法,递归的结束条件是节点为NULL,子问题是左右子树在加上根节点的数量(也就是1)。

2.二叉树叶子节点的个数

  1. int BinaryTreeLeafSize(BTNode* root)
  2. {
  3. if (root == NULL)
  4. {
  5. return 0;
  6. }
  7. if (root->left == NULL && root->right == NULL)
  8. {
  9. return 1;
  10. }
  11. int left = BinaryTreeLeafSize(root->left);
  12. int right = BinaryTreeLeafSize(root->right);
  13. return left + right;
  14. }

递归的结束条件是左右子树都为空,且结束时需要返回1。

3.二叉树的高度

  1. int BinaryTreeHeight(BTNode* root)
  2. {
  3. if (root == NULL)
  4. {
  5. return 0;
  6. }
  7. int left = BinaryTreeHeight(root->left);
  8. int right = BinaryTreeHeight(root->right);
  9. return left > right ? left + 1 : right + 1;
  10. }

递归的结束条件是节点为空,子问题是计算左右子树的高度并且返回高度比较高的子树。

4.二叉树第k层节点的个数

  1. int BinaryTreeLevelKSize(BTNode* root, int k)
  2. {
  3. if (root == NULL)
  4. {
  5. return 0;
  6. }
  7. if (k == 1)
  8. {
  9. return 1;
  10. }
  11. int left = BinaryTreeLevelKSize(root->left, k - 1);
  12. int right = BinaryTreeLevelKSize(root->right, k - 1);
  13. return left + right;
  14. }

递归的结束条件是k==1,并且返回1。

如果k的值为3,则可以得到如下流程图:

5.二叉树查询值为x的节点

  1. BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
  2. {
  3. if (root == NULL)
  4. {
  5. return NULL;
  6. }
  7. if (root->data == x)
  8. {
  9. return root;
  10. }
  11. BTNode* left = BinaryTreeFind(root->left, x);
  12. if (left)
  13. {
  14. return left;
  15. }
  16. BTNode* right = BinaryTreeFind(root->right, x);
  17. if (right)
  18. {
  19. return right;
  20. }
  21. return NULL;
  22. }

这里思路是遍历一遍二叉树,若找到,则返回给上一层。最后,若左子树或者右子树不为空,则说明找到了指定的节点。若没有找到,则返回NULL。

6.判断二叉树是否为完全二叉树

思路:这道题需要我们用到层序遍历,与层序遍历不同的是,我们要将NULL也带入到队列之中。当遇到第一个NULL时,break跳出来。然后判断之后队列之中的指针是否为空,若有空指针,返回假。若循环完,则返回真。

  1. // 判断二叉树是否是完全二叉树
  2. bool BinaryTreeComplete(BTNode* root)
  3. {
  4. Queue pq;
  5. QueueInit(&pq);
  6. if (root)
  7. {
  8. QueuePush(&pq, root);
  9. }
  10. while (!QueueEmpty(&pq))
  11. {
  12. BTNode* front = QueueFront(&pq);
  13. QueuePop(&pq);
  14. if (front == NULL)
  15. {
  16. break;
  17. }
  18. QueuePush(&pq, front->left);
  19. QueuePush(&pq, front->right);
  20. }
  21. while (!QueueEmpty(&pq))
  22. {
  23. BTNode* front = QueueFront(&pq);
  24. QueuePop(&pq);
  25. if (front!=NULL)
  26. {
  27. QueueDestroy(&pq);
  28. return false;
  29. }
  30. }
  31. QueueDestroy(&pq);
  32. return true;
  33. }

7.二叉树基础oj练习

接下来,我们根据刚才介绍的几种基本操作为基础完成几道oj练习:

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

思路:为了方便操作,我们可以在创建一个函数,将根节点的值作为参数传给所创建的函数。依然采用递归的方法,结束条件是root为空或者root的值不等于val值。子问题是左右子树是否为单值二叉树。

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

思路:用递归,结束条件是两个节点都为空,返回true,或者一个为空一个不为空,返回false,或者两个节点的值不相等,返回false。子问题是左右子树是否相等。

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

 思路:这道题同样是先创建一个新的函数,将左右子树的根节点传过去,再使用递归解决问题,结束条件是两个节点都为空,返回true,或者一个为空一个不为空,返回false,或者两个节点的值不相等,返回false。子问题是左子树的右节点是否跟右子树的左节点是否相等。

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

思路:先用递归将二叉树遍历一遍,计算出二叉树节点的个数returnSize。在开辟returnSize个整形的空间,然后使用前序遍历将二叉树中的节点放到开辟的空间里面。

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

思路:先创建一个函数,作用是判断两颗二叉树是否相等,参数是两颗二叉树的根节点。然后使用递归的方法,结束条件是节点为空,返回NULL,或者判断两颗是相等的,返回true。子问题是遍历一遍二叉树,判断是否有子树和指定的数相等。

三.二叉树的创建和销毁

1.创建

关于二叉树的创建,我们利用一道OJ题目来展示:

二叉树遍历_牛客题霸_牛客网 (nowcoder.com)

这道题输入的数据展开的数据所组成的二叉树为上图。

思路:将输入的数组组成一颗二叉树,再将二叉树一中序遍历的方法输出出来。

2.销毁

  1. void TreeDestory(BTNode* root)
  2. {
  3. if (root == NULL)
  4. return;
  5. TreeDestory(root->left);
  6. TreeDestory(root->right);
  7. free(root);
  8. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/727033
推荐阅读
相关标签
  

闽ICP备14008679号