• 数据结构-链式二叉树


    目录

    链式二叉树的概念及结构

    概念

    结构

    链式二叉树的遍历

    前序遍历

    中序遍历

    后序遍历

    层序遍历

    链式二叉树的基本操作

    求结点个数BTreeSize

    求叶子结点个数BTreeLeafSize

    求某一层的结点个数BTreeKLevelSize

    求链式二叉树的深度BTreeDepth

    判断两棵链式二叉树是否相同BTreeIsSame

    链式二叉树的创建与销毁

    创建BTreeCreate

    销毁BTreeDestroy

    代码


    链式二叉树的概念及结构

    概念

       对于那些非完全二叉树,由于顺序存储结构的空间利用率低,因此二叉树一般都采用链式存储结构,用链表结点来存储二叉树中的每一个结点。在链式二叉树中,结点结构通常包括数据域和若干个指针域。a7492c11e4d74e05b8cd0c4333605c7f.png

    结构

       链式二叉树的结构一般分为两种,一种是二叉链,另一种是三叉链。二叉链的结点包含存储数据的变量,存储左孩子的指针以及存储右孩子的指针。而三叉链的结点除了包含存储数据的变量,存储左孩子的指针以及存储右孩子的指针,还包含存储双亲的指针。特别的在二叉链中,若有n个结点,则一定会有n+1个空指针。5726e2ac8c3b4632825191c56d3a5b0b.png

    链式二叉树的遍历

       二叉树的遍历是指按某条搜索路径访问树中每个结点,使得每个结点均被访问一次,而且仅被访问一次。因为二叉树是递归定义的,遍历一棵二叉树便要决定对根结点,左子树和右子树的访问顺序。根据访问根结点的顺序不同可以分为前序遍历,中序遍历和后序遍历。以下面这颗二叉树为例:89be033d455341f896e038bc4aac5f43.png

     

    1. BinaryTreeNode* BuyBinaryTreeNode(BTDataType x) // 创建二叉链结点
    2. {
    3. BinaryTreeNode* node = (BinaryTreeNode*)malloc(sizeof(BinaryTreeNode));
    4. if (node == NULL) // 检查结点是否开辟成功
    5. {
    6. perror("malloc fail");
    7. return NULL;
    8. }
    9. node->data = x; // 先将左右指针置空
    10. node->left = NULL;
    11. node->right = NULL;
    12. return node;
    13. }
    14. int main()
    15. {
    16. BinaryTreeNode* node1 = BuyBinaryTreeNode(1);
    17. BinaryTreeNode* node2 = BuyBinaryTreeNode(2);
    18. BinaryTreeNode* node3 = BuyBinaryTreeNode(3);
    19. BinaryTreeNode* node4 = BuyBinaryTreeNode(4);
    20. BinaryTreeNode* node5 = BuyBinaryTreeNode(5);
    21. BinaryTreeNode* node6 = BuyBinaryTreeNode(6);
    22. BinaryTreeNode* node7 = BuyBinaryTreeNode(7);
    23. node1->left = node2;
    24. node1->right = node3;
    25. node2->left = node4;
    26. node2->right = node5;
    27. node5->left = node6;
    28. node3->right = node7;
    29. BinaryTreeNode* root = node1;
    30. }

    前序遍历

       先访问根结点,再访问左子树,最后访问右子树。fa1267719f3f4b76913ef5e882b661b4.png

    中序遍历

       先访问左子树,再访问根结点,最后访问右子树。233f72138b414a60901937e8f1da4e5c.png

    后序遍历

       先访问左子树,再访问右子树,最后访问根结点。e8cfe075684e4c53a003212212aa7b71.png

    层序遍历

       进行层序遍历,需要借助队列。先将根结点入队,然后出队,若不为空,则将它的左右结点入队,然后继续入队出队直到队列为空。

    1. // 队列
    2. #include "BinaryTree.h"
    3. typedef struct BinaryTreeNode* QueueDataType; // 存储的数据类型
    4. typedef struct QueueNode
    5. {
    6. struct QueueNode* next; // 指向下一个结点
    7. QueueDataType data; // 存储数据
    8. }QueueNode;
    9. typedef struct Queue
    10. {
    11. QueueNode* head; // 头指针
    12. QueueNode* tail; // 尾指针
    13. }Queue;
    14. extern void QueueInit(Queue* pq);
    15. extern void QueueDestroy(Queue* pq);
    16. extern void QueuePush(Queue* pq, QueueDataType x);
    17. extern void QueuePop(Queue* pq);
    18. extern QueueDataType QueueFront(Queue* pq);
    19. extern QueueDataType QueueBack(Queue* pq);
    20. extern size_t QueueSize(Queue* pq);
    21. extern bool QueueEmpty(Queue* pq);

    9853c343aca4429d85bf205c0c6a54ce.png   利用层序遍历可以判断链式二叉树是否为完全二叉树,其思路为:在层序遍历的过程中,如果遇到结点为空则跳出循环,将剩下没有出队的结点依次出队,如果有非空结点出队,则说明该链式二叉树为非完全二叉树;如果剩下没有出队的结点都为空则说明为完全二叉树。079122fa40da40439c89e4738d3b5a1c.png

    1. bool BTreeComplete(BinaryTreeNode* root) // 判断是否为完全二叉树
    2. {
    3. Queue q;
    4. QueueInit(&q);
    5. QueuePush(&q, root);
    6. while (!QueueEmpty(&q))
    7. {
    8. QueueDataType front = QueueFront(&q);
    9. QueuePop(&q);
    10. if (front)
    11. {
    12. /*printf("%d ", front->data);*/
    13. QueuePush(&q, front->left);
    14. QueuePush(&q, front->right);
    15. }
    16. else
    17. {
    18. break; // 遇到空结点跳出循环
    19. }
    20. }
    21. while (!QueueEmpty(&q))
    22. {
    23. if (QueueFront(&q)!=NULL) // 遇到非空结点,返回false,说明为非完全二叉树
    24. {
    25. QueueDestroy(&q);
    26. return false;
    27. }
    28. QueuePop(&q);
    29. }
    30. QueueDestroy(&q);
    31. return true; // 后面没有非空结点,说明是完全二叉树,返回true
    32. }

    链式二叉树的基本操作

    d7f41e22858a4443992d4cca5de66d16.png

    求结点个数BTreeSize

    61875477ef684eedbe1f211d227e10f5.png

    求叶子结点个数BTreeLeafSize

    0d5e4d4518934037b706d688517bafd8.png

    求某一层的结点个数BTreeKLevelSize

    86a72c1fa5be4e8b8d3d805ee78b5117.png

    求链式二叉树的深度BTreeDepth

    5f2e53e3eef14daaa560df9d66c9fa72.png

    判断两棵链式二叉树是否相同BTreeIsSame

    b99590c91a7e44c6af42da2b45df7d6e.png

    链式二叉树的创建与销毁

    创建BTreeCreate

       创建链接

    1. #include
    2. typedef struct TreeNode
    3. {
    4. struct TreeNode* left;
    5. struct TreeNode* right;
    6. char ch;
    7. }TreeNode;
    8. TreeNode* TreeCreate(char* p,int* pi)
    9. {
    10. if(p[*pi]!='\0')
    11. {
    12. if(p[*pi]!='#')
    13. {
    14. TreeNode* node=(TreeNode*)malloc(sizeof(TreeNode));
    15. if(node==NULL)
    16. {
    17. perror("malloc");
    18. return NULL;
    19. }
    20. node->ch=p[*pi];
    21. (*pi)++;
    22. node->left=TreeCreate(p,pi);
    23. node->right=TreeCreate(p,pi);
    24. return node;
    25. }
    26. else
    27. {
    28. (*pi)++;
    29. return NULL;
    30. }
    31. }
    32. return NULL;
    33. }
    34. void TreeInOrder(TreeNode* root)
    35. {
    36. if(root==NULL)
    37. return;
    38. TreeInOrder(root->left);
    39. printf("%c ",root->ch);
    40. TreeInOrder(root->right);
    41. }
    42. int main()
    43. {
    44. char str[101];
    45. scanf("%s",str);
    46. int i=0;
    47. TreeInOrder(TreeCreate(str, &i));
    48. return 0;
    49. }

    销毁BTreeDestroy

       链式二叉树的销毁应该采用后序遍历的思想,也就是先销毁左子树,再销毁右子树,最后销毁根节点。避免先销毁根节点,左右子树找不到了。fdd1b6cc3b0b440696ed52ff8d3193a7.png

    代码

    1. // 头文件
    2. typedef int BTDataType;
    3. typedef struct BinaryTreeNode
    4. {
    5. struct BinaryTreeNode* left;
    6. struct BinaryTreeNode* right;
    7. BTDataType data;
    8. }BinaryTreeNode;
    9. extern BinaryTreeNode* BuyBinaryTreeNode(BTDataType x);
    10. extern void PrevOrder(BinaryTreeNode* root);
    11. extern void InOrder(BinaryTreeNode* root);
    12. extern void PostOrder(BinaryTreeNode* root);
    13. extern int BTreeSize(BinaryTreeNode* root);
    14. extern int BTreeLeafSize(BinaryTreeNode* root);
    15. extern int BTreeKLevelSize(BinaryTreeNode* root, int k);
    16. extern int BTreeDepth(BinaryTreeNode* root);
    17. extern BinaryTreeNode* BTreeFind(BinaryTreeNode* root, BTDataType x);
    18. extern void LevelOrder(BinaryTreeNode* root);
    19. extern bool BTreeComplete(BinaryTreeNode* root);
    20. extern void BTreeDestroy(BinaryTreeNode* root);
    21. // 源文件
    22. void PrevOrder(BinaryTreeNode* root) // 前序遍历---根左右
    23. {
    24. if (root == NULL)
    25. {
    26. printf("N ");
    27. return;
    28. }
    29. printf("%d ", root->data);
    30. PrevOrder(root->left);
    31. PrevOrder(root->right);
    32. }
    33. void InOrder(BinaryTreeNode* root) // 中序遍历---左根右
    34. {
    35. if (root == NULL)
    36. {
    37. printf("N ");
    38. return;
    39. }
    40. InOrder(root->left);
    41. printf("%d ", root->data);
    42. InOrder(root->right);
    43. }
    44. void PostOrder(BinaryTreeNode* root) // 后序遍历---左右根
    45. {
    46. if (root == NULL)
    47. {
    48. printf("N ");
    49. return;
    50. }
    51. PostOrder(root->left);
    52. PostOrder(root->right);
    53. printf("%d ", root->data);
    54. }
    55. BinaryTreeNode* BuyBinaryTreeNode(BTDataType x) // 创建二叉链结点
    56. {
    57. BinaryTreeNode* node = (BinaryTreeNode*)malloc(sizeof(BinaryTreeNode));
    58. if (node == NULL) // 检查结点是否开辟成功
    59. {
    60. perror("malloc fail");
    61. return NULL;
    62. }
    63. node->data = x; // 先将左右指针置空
    64. node->left = NULL;
    65. node->right = NULL;
    66. return node;
    67. }
    68. int BTreeSize(BinaryTreeNode* root) // 求链式二叉树的结点个数
    69. {
    70. if (root == NULL)
    71. {
    72. return 0;
    73. }
    74. return 1 + BTreeSize(root->left) + BTreeSize(root->right);
    75. }
    76. int BTreeLeafSize(BinaryTreeNode* root) // 求链式二叉树的叶子结点个数
    77. {
    78. if (root == NULL)
    79. {
    80. return 0;
    81. }
    82. if (root->left == NULL && root->right == NULL)
    83. {
    84. return 1;
    85. }
    86. return BTreeLeafSize(root->left) + BTreeLeafSize(root->right);
    87. }
    88. int BTreeKLevelSize(BinaryTreeNode* root, int k) // 求链式二叉树某一层结点的个数 k+3
    89. {
    90. if (root == NULL)
    91. {
    92. return 0;
    93. }
    94. if (k == 1)
    95. {
    96. return 1;
    97. }
    98. return BTreeKLevelSize(root->left, k - 1) + BTreeKLevelSize(root->right, k - 1);
    99. }
    100. int BTreeDepth(BinaryTreeNode* root) // 求链式二叉树的层数
    101. {
    102. if (!root)
    103. {
    104. return 0;
    105. }
    106. int leftDepth = BTreeDepth(root->left)+1;
    107. int rightDepth = BTreeDepth(root->right)+1;
    108. return leftDepth > rightDepth ? leftDepth : rightDepth;
    109. }
    110. BinaryTreeNode* BTreeFind(BinaryTreeNode* root, BTDataType x) // 按值查找
    111. {
    112. if (!root)
    113. {
    114. return NULL;
    115. }
    116. if (root->data == x)
    117. {
    118. return root;
    119. }
    120. BinaryTreeNode* left = BTreeFind(root->left, x);
    121. if (left)
    122. return left;
    123. BinaryTreeNode* right = BTreeFind(root->right, x);
    124. if (right)
    125. return right;
    126. return NULL;
    127. }
    128. void LevelOrder(BinaryTreeNode* root) // 层序遍历
    129. {
    130. Queue q;
    131. QueueInit(&q);
    132. QueuePush(&q, root); // 先将根结点入队
    133. while (!QueueEmpty(&q))
    134. {
    135. QueueDataType front = QueueFront(&q); // 获取队头元素
    136. QueuePop(&q); // 出队
    137. if (front) // 不为空则将左右结点入队
    138. {
    139. printf("%d ", front->data);
    140. QueuePush(&q, front->left);
    141. QueuePush(&q, front->right);
    142. }
    143. }
    144. QueueDestroy(&q);
    145. }
    146. bool BTreeComplete(BinaryTreeNode* root) // 判断是否为完全二叉树
    147. {
    148. Queue q;
    149. QueueInit(&q);
    150. QueuePush(&q, root);
    151. while (!QueueEmpty(&q))
    152. {
    153. QueueDataType front = QueueFront(&q);
    154. QueuePop(&q);
    155. if (front)
    156. {
    157. /*printf("%d ", front->data);*/
    158. QueuePush(&q, front->left);
    159. QueuePush(&q, front->right);
    160. }
    161. else
    162. {
    163. break; // 遇到空结点跳出循环
    164. }
    165. }
    166. while (!QueueEmpty(&q))
    167. {
    168. if (QueueFront(&q)!=NULL) // 遇到非空结点,返回false,说明为非完全二叉树
    169. {
    170. QueueDestroy(&q);
    171. return false;
    172. }
    173. QueuePop(&q);
    174. }
    175. QueueDestroy(&q);
    176. return true; // 后面没有非空结点,说明是完全二叉树,返回true
    177. }
    178. void BTreeDestroy(BinaryTreeNode* root) // 链式二叉树的销毁
    179. {
    180. if (!root)
    181. {
    182. return;
    183. }
    184. BTreeDestroy(root->left);
    185. BTreeDestroy(root->right);
    186. free(root);
    187. }
    188. bool isSameTree(BinaryTreeNode* p, BinaryTreeNode* q) // 相同返回true否则返回false
    189. {
    190. if (p == NULL && q == NULL)
    191. return true;
    192. if (p == NULL || q == NULL)
    193. return false;
    194. if (p->data != q->data)
    195. return false;
    196. return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
    197. }

     

     

  • 相关阅读:
    信息学奥赛一本通:1167:再求f(x,n)
    汉字风格迁移篇----EasyFont:一个基于风格学习的系统,可以轻松构建大规模手写字体
    Structure Padding / Memory align
    2. HarmonyOS工程结构
    【简单易操作】图漾TM460-E2深度网络相机在ROS-melodic环境下的配置过程
    Qt学习总结之QToolButton
    新华三与中国移动完成IPv6随流检测互通测试
    2023年计算机毕设选题推荐
    安装使用electron
    【Java面试】@Resource 和 @Autowired 的区别
  • 原文地址:https://blog.csdn.net/m0_61433144/article/details/126116768