• 【数据结构】二叉树的链式结构及实现


    目录

    1. 前置说明

    2. 二叉树的遍历

    2.1 前序、中序以及后序遍历

    2.2 层序遍历

    3. 节点个数及高度等

    4. 二叉树的创建和销毁


    1. 前置说明

    在学习二叉树的基本操作前,需先要创建一棵二叉树,然后才能学习其相关的基本操作。由于现在大家对二叉树结构掌握还不够深入,为了降低大家学习成本,此处手动快速创建一棵简单的二叉树,快速进入二叉树操作学习,等二叉树结构了解的差不多时,我们反过头再来研究二叉树真正的创建方式。

    1. typedef int BTDataType;
    2. typedef struct BinaryTreeNode
    3. {
    4. BTDataType _data;
    5. struct BinaryTreeNode* _left;
    6. struct BinaryTreeNode* _right;
    7. }BTNode;
    8. BTNode* CreatBinaryTree()
    9. {
    10. BTNode* node1 = BuyNode(1);
    11. BTNode* node2 = BuyNode(2);
    12. BTNode* node3 = BuyNode(3);
    13. BTNode* node4 = BuyNode(4);
    14. BTNode* node5 = BuyNode(5);
    15. BTNode* node6 = BuyNode(6);
    16. node1->_left = node2;
    17. node1->_right = node4;
    18. node2->_left = node3;
    19. node4->_left = node5;
    20. node4->_right = node6;
    21. return node1;
    22. }

    注意:上述代码并不是创建二叉树的方式,真正创建二叉树方式后序详解重点讲解。

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

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

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

    2. 二叉树的遍历

    2.1 前序、中序以及后序遍历

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

    按照规则,二叉树的遍历有:前序/中序/后序的递归结构遍历

    1. 前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。
    2. 中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。
    3. 后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。

    由于被访问的结点必是某子树的根,所以N(Node)、L(Left subtree)和R(Right subtree)又可解释为根、根的左子树和根的右子树。NLR、LNR和LRN分别又称为先根遍历、中根遍历和后根遍历。

    1. // 二叉树前序遍历
    2. void PrevOrder(BTNode* root);
    3. // 二叉树中序遍历
    4. void InOrder(BTNode* root);
    5. // 二叉树后序遍历
    6. void PostOrder(BTNode* root);
    1. void PrevOrder(BTNode* root)
    2. {
    3. if (root == NULL)
    4. {
    5. printf("NULL ");
    6. return;
    7. }
    8. printf("%d ", root->val);
    9. PrevOrder(root->left);
    10. PrevOrder(root->right);
    11. }
    12. void InOrder(BTNode* root)
    13. {
    14. if (root == NULL)
    15. {
    16. printf("NULL ");
    17. return;
    18. }
    19. InOrder(root->left);
    20. printf("%d ", root->val);
    21. InOrder(root->right);
    22. }
    23. void PostOrder(BTNode* root)
    24. {
    25. if (root == NULL)
    26. {
    27. printf("NULL ");
    28. return;
    29. }
    30. PostOrder(root->left);
    31. PostOrder(root->right);
    32. printf("%d ", root->val);
    33. }

    下面主要分析前序递归遍历,中序与后序图解类似,大家可自己动手绘制。

    前序遍历递归图解:

    前序遍历结果:1 2 3 4 5 6

    中序遍历结果:3 2 1 5 4 6

    后序遍历结果:3 2 5 6 4 1

    2.2 层序遍历

    层序遍历:除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根节点所在层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。

    1. // 层序遍历
    2. void LevelOrder(BTNode* root);
    1. void LevelOrder(BTNode* root)
    2. {
    3. Que q;
    4. QueueInit(&q);
    5. if (root)
    6. QueuePush(&q, root);
    7. while (!QueueEmpty(&q))
    8. {
    9. BTNode* front = QueueFront(&q);
    10. printf("%d ", front->val);
    11. if (front->left)
    12. QueuePush(&q, front->left);
    13. if (front->right)
    14. QueuePush(&q, front->right);
    15. QueuePop(&q);
    16. }
    17. printf("\n");
    18. QueueDestroy(&q);
    19. }

    3. 节点个数及高度等

    1. // 二叉树节点个数
    2. int TreeSize(BTNode* root);
    3. // 二叉树叶子节点个数
    4. int TreeLeafSize(BTNode* root);
    5. // 二叉树第k层节点个数
    6. int TreeKLevel(BTNode* root, int k);
    7. // 二叉树查找值为x的节点
    8. BTNode* TreeFind(BTNode* root, int x);
    9. // 二叉树的高度
    10. int TreeHeight(BTNode* root);
    1. int TreeSize(BTNode* root)
    2. {
    3. return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
    4. }
    5. int TreeLeafSize(BTNode* root)
    6. {
    7. if (root == NULL)
    8. return 0;
    9. if (root->left == NULL && root->right == NULL)
    10. return 1;
    11. return TreeLeafSize(root->left) + TreeLeafSize(root->right);
    12. }
    13. int TreeKLevel(BTNode* root, int k)
    14. {
    15. assert(k > 0);
    16. if (root == NULL)
    17. return 0;
    18. if (k == 1)
    19. return 1;
    20. return TreeKLevel(root->left, k - 1) + TreeKLevel(root->right, k - 1);
    21. }
    22. BTNode* TreeFind(BTNode* root, int x)
    23. {
    24. if (root == NULL)
    25. return NULL;
    26. if (root->val == x)
    27. return root;
    28. BTNode* ret = NULL;
    29. ret = TreeFind(root->left, x);
    30. if (ret)
    31. return ret;
    32. ret = TreeFind(root->right, x);
    33. if (ret)
    34. return ret;
    35. return NULL;
    36. }
    37. int TreeHeight(BTNode* root)
    38. {
    39. if (root == NULL)
    40. return 0;
    41. return fmax(TreeHeight(root->left), TreeHeight(root->right)) + 1;
    42. }

    4. 二叉树的创建和销毁

    1. // 手动构建二叉树
    2. BTNode* BuyNode(int x);
    3. // 二叉树销毁
    4. void TreeDestroy(BTNode* root);
    5. // 判断二叉树是否是完全二叉树
    6. int TreeComplete(BTNode* root);
    1. BTNode* BuyNode(int x)
    2. {
    3. BTNode* node = (BTNode*)malloc(sizeof(BTNode));
    4. if (node == NULL)
    5. {
    6. perror("malloc fail");
    7. exit(-1);
    8. }
    9. node->val = x;
    10. node->left = NULL;
    11. node->right = NULL;
    12. return node;
    13. }
    14. void TreeDestroy(BTNode* root)
    15. {
    16. if (root == NULL)
    17. return;
    18. TreeDestroy(root->left);
    19. TreeDestroy(root->right);
    20. free(root);
    21. }
    22. int TreeComplete(BTNode* root)
    23. {
    24. Que q;
    25. QueueInit(&q);
    26. if (root)
    27. QueuePush(&q, root);
    28. while (!QueueEmpty(&q))
    29. {
    30. BTNode* front = QueueFront(&q);
    31. if (front == NULL)
    32. break;
    33. QueuePush(&q, front->left);
    34. QueuePush(&q, front->right);
    35. QueuePop(&q);
    36. }
    37. // 已经遇到空节点,如果队列中后面的节点还有非空,就不是完全二叉树
    38. while (!QueueEmpty(&q))
    39. {
    40. BTNode* front = QueueFront(&q);
    41. QueuePop(&q);
    42. if (front != NULL)
    43. {
    44. QueueDestroy(&q);
    45. return false;
    46. }
    47. }
    48. QueueDestroy(&q);
    49. return true;
    50. }

    本文完

  • 相关阅读:
    一文搞清楚Java中常见的IO模型
    【黄啊码】MySQL入门—3、我用select *,老板直接赶我坐火车回家去,买的还是站票
    UE4c++ ConvertActorsToStaticMesh & ConvertProceduralMeshToStaticMesh
    [BJDCTF 2020]Easy
    精品SpringCloud的高校招生信息管理系统-微服务分布式
    系统架构设计专业技能 · 计算机组成与结构
    git 把项目托管到码云
    护眼灯有用吗?双十二买什么样的护眼灯真的有效果
    Nmap爆破MySQL弱口令漏洞:解决报错Accounts: No valid accounts found
    【MySQL】数据类型(一)
  • 原文地址:https://blog.csdn.net/m0_73156359/article/details/133776442