zoukankan      html  css  js  c++  java
  • 二叉树备忘

    二叉树基本概念及性质


    二叉树(binary tree)是一棵树,每个结点最多有两个儿子(0/1/2),本质上就是图(graph);根据定义,二叉树有以下五种形态:

    二叉树的特点如下图:

    特殊的二叉树有斜二叉树,满二叉树和完全二叉树,
    • 斜二叉树:每一层只有一个结点,每个结点仅有左子树的称为左斜树,反之称为右斜树;
    • 满二叉树:所有的分支结点都有左子树和右子树,所有的叶结点都处在同一层;
    • 完全二叉树:树中的结点按层编号,与满二叉树对应编号的结点位置相同,即完全二叉树“是满二叉树的一部分”,因此满二叉树一定是完全二叉树,但是完全二叉树不一定是满的;

    二叉树可以表示多叉树
    在多叉树中,“长子-兄弟法”用firstChild()表示父结点的长子结点【左子树】,<子结点>用nextSibling()依次指向【右子树】,



    二叉树的存储结构


    二叉树的存储结构分为顺序存储结构(数组)和链式存储结构,其中顺序存储结构只适用于存储完全二叉树

    二叉树非递归遍历


    1. 先(根)序遍历(“根左右”)

    1.2 迭代实现 & 两种版本:
    迭代版本一:根结点入栈,根据栈FILO的特性,先遍历的左孩子后入先出,后遍历的右孩子先入后出;


    迭代版本二:先自上而下访问左侧链上的节点,将每个左侧链节点的右孩子入栈,再自下而上访问它们的右子树;


    2. 中根)序遍历(“左根右”)

    2.2 迭代遍历:
    借用辅助栈,沿着左侧链下行,自下而上访问左侧链结点,并遍历对应的右子树;
    时间复杂度为O(n),空间复杂度线性正比于二叉树的高度,最坏情况下与结点总数相当;

    3. 后根)序遍历(“左右”)

    3.2 迭代遍历方法:
    访问当前结点,遍历以其右兄弟(若存在)为根的子树,向上回溯至父结点(若存在),转入下一个片段;



    4. 层序遍历

    从根结点开始,自上而下逐层遍历,同一层中从左到右遍历;




    二叉树重构

    已知先序序列中序序列可确定一棵唯一的二叉树;
    已知后序序列中序序列可确定一棵唯一的二叉树;

    仅凭借先序序列和后序序列不能确定一棵唯一的二叉树,当左子树或者右子树有空树情况时,无法判断左右子树哪一方为空树,引起歧义,从而重构二叉树不唯一;
    重构二叉树为真二叉树(结点的度为0或者2),左右子树同时为空或者不为空,凭借先序序列和后序序列可以确定唯一的真二叉树;



    二叉树创建&遍历完整代码部分

     
    1. 前序序列: 1 2 4 7 -1 -1 8 -1 -1 -1 3 5 -1 9 -1 -1 6 -1 -1
    2. 前序遍历: 1 2 4 7 # # 8 # # # 3 5 # 9 # # 6 # #
    3. 中序遍历: # 7 # 4 # 8 # 2 # 1 # 5 # 9 # 3 # 6 #
    4. 后序遍历: # # 7 # # 8 4 # 2 # # # 9 5 # # 6 3 1
    1. /*
    2. * File name:BinaryTreeByList.c
    3. * Description: 前序序列创建二叉树,前序/中序/后序递归遍历二叉树
    4. * Author: yzwall
    5. * Data: 2016/9/19 20:12
    6. */
    7. #include <stdio.h>
    8. #include <stdlib.h>
    9. //////////////////////////////////////////////////////////
    10. typedef int ElementType;
    11. // 二叉树结点结构
    12. typedef struct BiTreeNode {
    13. ElementType element;
    14. struct BiTreeNode *lchild; // 左孩子结点指针
    15. struct BiTreeNode *rchild; // 右孩子结点指针
    16. } BiTreeNode;
    17. //////////////////////////////////////////////////////////
    18. // 前序递归遍历preorder recursive traversal
    19. void traversalPreOrder(BiTreeNode *bt) {
    20. if(bt == NULL) {
    21. printf("# ");
    22. return; // 递归无返回值,可通过return;返回上次递归位置
    23. } else {
    24. printf("%d ", bt->element); // 遍历根结点
    25. traversalPreOrder(bt->lchild); // 遍历左子树
    26. traversalPreOrder(bt->rchild); // 遍历右子树
    27. }
    28. }
    29. // 中序递归遍历inorder recursive traversal
    30. void traversalInOrder(BiTreeNode *bt) {
    31. if(bt == NULL) {
    32. printf("# ");
    33. return;
    34. } else {
    35. traversalInOrder(bt->lchild); // 遍历左子树
    36. printf("%d ", bt->element); // 遍历根结点
    37. traversalInOrder(bt->rchild); // 遍历右子树
    38. }
    39. }
    40. // 后序递归遍历postorder recursive traversal
    41. void traversalPostOrder(BiTreeNode *bt) {
    42. if(bt == NULL) {
    43. printf("# ");
    44. return;
    45. } else {
    46. traversalPostOrder(bt->lchild); // 遍历左子树
    47. traversalPostOrder(bt->rchild); // 遍历右子树
    48. printf("%d ", bt->element); // 遍历根结点
    49. }
    50. }
    51. /*
    52. * 前序输入二叉树结点值(单字符输入,#表示空结点)根据前序输入构造二叉链表表示二叉树
    53. * note: 将结点指针作为返回值,直接将结点指针作为参数传入,传值传递了bt的一个备份,开辟新结点时malloc会赋值给备份
    54. * note: 二级指针可解决该问题,代码可读性差
    55. */
    56. BiTreeNode *createBiTreeFirstOrder() {
    57. BiTreeNode *bt;
    58. ElementType element;
    59. scanf("%d", &element);
    60. if(element == -1) {
    61. bt = NULL; // 空结点
    62. //return; // 递归已有出口return bt, return;会使得空结点值赋值null值失效;
    63. } else {
    64. bt = (BiTreeNode *)malloc(sizeof(BiTreeNode));
    65. if(bt == NULL) {
    66. exit(-1);
    67. printf("BiTreeNode memory allocate failed. ");
    68. } else {
    69. bt->element = element; // 构造根结点
    70. bt->lchild = createBiTreeFirstOrder(); // 构造左子树
    71. bt->rchild = createBiTreeFirstOrder(); // 构造右子树
    72. }
    73. }
    74. return bt;
    75. }
    76. //////////////////////////////////////////////////////////
    77. int main() {
    78. setvbuf(stdout,NULL,_IONBF,0);
    79. setvbuf(stderr, NULL, _IONBF, 0);
    80. BiTreeNode *bt;
    81. bt = createBiTreeFirstOrder(); // 根据前序输入构造二叉树
    82. printf(" 前序遍历: ");
    83. traversalPreOrder(bt); // 前序递归遍历二叉树
    84. printf(" 中序遍历: ");
    85. traversalInOrder(bt); // 前序递归遍历二叉树
    86. printf(" 后序遍历: ");
    87. traversalPostOrder(bt); // 前序递归遍历二叉树
    88. return 0;
    89. }



  • 相关阅读:
    P2802 【回家】
    P1706 【全排列问题】
    P1936 【水晶灯火灵】
    P1319 【压缩技术】
    P2670 【扫雷游戏】
    P1097 【统计数字】
    P1820 【寻找AP数】
    P1020 【导弹拦截】
    链表反转
    队列:队列在有限线程池中的应用
  • 原文地址:https://www.cnblogs.com/yzwall/p/6637195.html
Copyright © 2011-2022 走看看