• 数据结构之二叉树的基本实现


    在我们之前已经了解的堆这样的完全二叉树的实现,也对树型结构有了一些了解,那么今天我们来看看二叉树的一些性质。

    因为二叉树是一种每个节点至多只有两个子树(即二叉树的每个节点的度不大于2),并且二叉树的子树有左右之分,其次序不能任意颠倒,因此它的结构也是比较独特的。

    目录

    1.二叉树的结构定义

    2.节点构造

    3.节点生成树

    3.二叉树的遍历方式

    先序遍历:

    中序遍历:

    后序遍历

    层次遍历:

    4.求树的所有节点个数

    5.求叶子节点个数

    6.求二叉树树深度

    7.二叉树第K层节点个数

    8.返回值为x的节点


    1.二叉树的结构定义

    二叉树是一种每个节点至多只有两个子树(即二叉树的每个节点的度不大于2),并且二叉树的子树有左右之分,其次序不能任意颠倒。

    1. //定义树的节点
    2. typedef int DATAtype;
    3. typedef struct TreeNode
    4. {
    5. DATAtype data;
    6. struct TreeNode* leftchild;
    7. struct TreeNode* rightchild;
    8. }BTnode;

    2.节点构造

    简单的节点构造,如同链表的结点,不同的是这里有两个节点表示左孩子与右孩子。

    1. //构造树的节点
    2. BTnode* CreateNode(DATAtype x)
    3. {
    4. BTnode* newnode = (BTnode*)malloc(sizeof(BTnode));
    5. if (newnode == NULL)
    6. {
    7. perror("malloc fali");
    8. return NULL;
    9. }
    10. newnode->data = x;
    11. newnode->leftchild = NULL;
    12. newnode->rightchild = NULL;
    13. return newnode;
    14. }

    3.节点生成树

    我们是通过链接节点之间形成树的逻辑关系,这里的树如图:

     先链接了六个节点,之后又添加了一个节点

    1. //利用节点生成一个树
    2. BTnode* TreeCreat()
    3. {
    4. BTnode* node1=CreateNode(1);
    5. BTnode* node2=CreateNode(2);
    6. BTnode* node3=CreateNode(3);
    7. BTnode* node4=CreateNode(4);
    8. BTnode* node5=CreateNode(5);
    9. BTnode* node6=CreateNode(6);
    10. BTnode* node7 = CreateNode(6);
    11. //建立连接关系
    12. node1->leftchild = node2;
    13. node1->rightchild = node4;
    14. node2->leftchild = node3;
    15. node4->leftchild = node5;
    16. node4->rightchild = node6;
    17. node6->leftchild = node7;
    18. //返回根
    19. return node1;
    20. }

    3.二叉树的遍历方式

    二叉树的遍历方式主要有四种,分别是先序遍历、中序遍历、后序遍历和层次遍历。123

    先序遍历:

    先访问根节点,再访问左子树,最后访问右子树。

    1. //前序遍历
    2. void Preverorder(BTnode*root)
    3. {
    4. //根 左子树 右子树
    5. if (root == NULL)
    6. {
    7. return;
    8. }
    9. printf("%d ", root->data);
    10. Preverorder(root->leftchild);
    11. Preverorder(root->rightchild);
    12. }


    中序遍历:

    先访问左子树,再访问根节点,最后访问右子树。

    1. void Inorder(BTnode* root)
    2. {
    3. // 左子树 根 右子树
    4. if (root == NULL)
    5. {
    6. return;
    7. }
    8. Preverorder(root->leftchild);
    9. printf("%d ", root->data);
    10. Preverorder(root->rightchild);
    11. }


    后序遍历

    :先访问左子树,再访问右子树,最后访问根节点。

    1. void Postorder(BTnode* root)
    2. {
    3. // 左子树 右子树 根
    4. if (root == NULL)
    5. {
    6. return;
    7. }
    8. Preverorder(root->leftchild);
    9. Preverorder(root->rightchild);
    10. printf("%d ", root->data);
    11. }


    层次遍历:

    按照从上到下、从左到右的顺序依次访问每个节点。

    层序遍历我们使用队列实现,思路:先进先出,上一层出队时带下一层节点入队。

    1. #include<stdio.h>
    2. #include<stdlib.h>
    3. #include<assert.h>
    4. #include"queue.h"
    5. #define CRT_SECURE_NO_WARNINGS 1
    6. //定义树的节点
    7. typedef int DATAtype;
    8. typedef struct TreeNode
    9. {
    10. DATAtype data;
    11. struct TreeNode* leftchild;
    12. struct TreeNode* rightchild;
    13. }BTnode;
    14. //构造树的节点
    15. BTnode* CreateNode(DATAtype x)
    16. {
    17. BTnode* newnode = (BTnode*)malloc(sizeof(BTnode));
    18. if (newnode == NULL)
    19. {
    20. perror("malloc fali");
    21. return NULL;
    22. }
    23. newnode->data = x;
    24. newnode->leftchild = NULL;
    25. newnode->rightchild = NULL;
    26. return newnode;
    27. }
    28. //利用节点生成一个树
    29. BTnode* TreeCreat()
    30. {
    31. BTnode* node1=CreateNode(1);
    32. BTnode* node2=CreateNode(2);
    33. BTnode* node3=CreateNode(3);
    34. BTnode* node4=CreateNode(4);
    35. BTnode* node5=CreateNode(5);
    36. BTnode* node6=CreateNode(6);
    37. BTnode* node7 = CreateNode(6);
    38. //建立连接关系
    39. node1->leftchild = node2;
    40. node1->rightchild = node4;
    41. node2->leftchild = node3;
    42. node4->leftchild = node5;
    43. node4->rightchild = node6;
    44. node6->leftchild = node7;
    45. //返回根
    46. return node1;
    47. }

     层序遍历:

    1. //层序遍历
    2. void leverorder(BTnode* root)
    3. {
    4. LTnode p;
    5. Queueinit(&p);
    6. Queuedestroy(&p);
    7. //先入根节点
    8. if (root)
    9. {
    10. LTpush(&p, root);
    11. }
    12. while (!LTempety(&p))
    13. {
    14. //队中数据全是树节点指针型
    15. BTnode* front = LTfront(&p);
    16. LTpop(&p);//出队头
    17. printf("%d", front->data);
    18. //判断孩子节点
    19. if (front->leftchild)
    20. {
    21. LTpush(&p, front->leftchild);
    22. }
    23. if (front->rightchild)
    24. {
    25. LTpush(&p, front->rightchild);
    26. }
    27. }
    28. printf("\n");
    29. }

    4.求树的所有节点个数

    这里有两种方法,除了定义全局变量利用计数的方法来计算树的节点个数,但还需注意全局变量使用后需置零,其次我们也是利用递归的返回值累加计算出节点个数。

    1. //求树的所有节点个数
    2. int size = 0;
    3. int Binarytreesize(BTnode* root)
    4. {
    5. /*分治思想 从左子树到右子树再到根*/
    6. if (root == NULL)
    7. {
    8. return 0;
    9. }
    10. return (1 + Binarytreesize(root->leftchild) + Binarytreesize(root->rightchild));
    11. /*if (root)
    12. {
    13. size++;
    14. Binarytreesize(root->leftchild);
    15. Binarytreesize(root->rightchild);
    16. }
    17. return size;*/
    18. }

    5.求叶子节点个数

    寻找递归条件,叶子节点没有左右孩子,否则就不返回一,符合条件的返回一相加。注意递归中返回值的设定。

    1. //求叶子节点个数
    2. int BTreeleavessize(BTnode* root)
    3. {
    4. //自己的左子树与左右子树为空
    5. if (root == NULL)
    6. {
    7. return 0;
    8. }
    9. if (root->leftchild == NULL && root->rightchild == NULL)
    10. {
    11. return 1;
    12. }
    13. else
    14. {
    15. return BTreeleavessize(root->leftchild) + BTreeleavessize(root->rightchild);
    16. }
    17. }

    6.求二叉树树深度

    分治思想,两边同时遍历,每有一层加一,左孩子层数与右孩子层数中较大的那个就是深度。

    1. //求二叉树的深度
    2. int BTreeheight(BTnode* root)
    3. {
    4. //左右同时遍历,选最大的哪一个
    5. if (root == NULL)
    6. {
    7. return 0;
    8. }
    9. //这里注意用变量保存一下左 右子树的数目
    10. int left = BTreeheight(root->leftchild) + 1;
    11. int right= BTreeheight(root->rightchild) + 1;
    12. if (left > right)
    13. {
    14. return left;
    15. }
    16. else
    17. {
    18. return right;
    19. }
    20. }

    7.二叉树第K层节点个数

    这里的递归主要是找的第k层,利用k==1作为递归返回条件。

    1. //二叉树第k层结点的个数
    2. int BTree_knumber(BTnode* root,int k)
    3. {
    4. //分情况讨论
    5. if (root == NULL)
    6. {
    7. return 0;
    8. }
    9. if (k==1)
    10. {
    11. return 1;
    12. }
    13. return BTree_knumber(root->leftchild, k - 1) +
    14. BTree_knumber(root->rightchild, k - 1);
    15. }

    8.返回值为x的节点

    这里的难度在与返回值,我们知道在递归里面函数返回值不能直接返回,我们需要判断,对于返回值是需要我们好好检查的,在这里,我们从根,左孩子,右孩子的顺序逐个判断,对于左右孩子并保存返回值,来确定是当前节点。

    1. //返回为x的树节点
    2. BTnode* BTreenode(BTnode* root, DATAtype x)
    3. {
    4. if (root == NULL)
    5. {
    6. return NULL;
    7. }
    8. if (root->data == x)
    9. {
    10. return root;
    11. }
    12. BTnode* left = BTreenode(root->leftchild,x);
    13. if (left->data==x)
    14. {
    15. return left;
    16. }
    17. BTnode* right = BTreenode(root->rightchild,x);
    18. if (right->data==x)
    19. {
    20. return right;
    21. }
    22. return NULL;
    23. }

    一些测试用例:

    1. int main()
    2. {
    3. BTnode* root = TreeCreat();
    4. /*Preverorder(root);
    5. printf("\n");
    6. Inorder(root);
    7. printf("\n");
    8. Postorder(root);*/
    9. //Binarytreesize(root);
    10. // BTreeleavessize(root);//BTreeheight(root);
    11. int x = BTree_knumber(root, 2);
    12. printf("%d ", BTreenode(root, 2)->data);
    13. //printf("%d", x);
    14. return 0;
    15. }

  • 相关阅读:
    Servlet规范之转发请求
    卷S人的166页精品Java面试手册,17大java面试系列专题让你全方位暴击大厂Java面试官!
    低开开发笔记(八): 低代码编辑器实现撤销回退(命令模式,防抖处理)
    Spring框架(一)Spring核心,设计理念,创建,优缺点,使用场景···
    Spring中Bean的作用域和生命周期
    痞子衡嵌入式:揭秘i.MXRTxxx系列上串行NOR Flash双程序可交替启动设计
    记一次 .NET 某物管后台服务 卡死分析
    Linux重定向
    云备份——服务器业务处理模块以及网络通信模块
    “蔚来杯“2022牛客暑期多校训练营4
  • 原文地址:https://blog.csdn.net/qq_61422622/article/details/130856432