当前位置:   article > 正文

二叉树创建的两种方法(图解)_数据结构pta6-4 括号表示法创建二叉树

数据结构pta6-4 括号表示法创建二叉树

       

目录

一、括号表示法

(1)括号表示法构建二叉树的算法思路及算法实现

(2)图解括号表示法构建二叉树

(3)测试程序

 二、扩展二叉树

(1)扩展二叉树构建二叉树的算法思路及算法实现

(2)测试程序


        二叉树的创建方法有很多种,在这里我介绍两种:用括号表示法或扩展二叉树来创建二叉树。

一、括号表示法

(1)括号表示法构建二叉树的算法思路及算法实现

        扩号表示法(本质广义表)是树的一种表示。它的表示方法:将树的根结点写在括号的左边,除根结点之外的其余结点写在扩号中,并用逗号隔开。如下图:

解释:

1、A是根结点,写在扩号左边,其左右孩子为B,C,写成A(B,C)

2、B又是D、E的双亲结点(相当于B、D、E构成的树,B为根结点),故写成 B(D,E),带入上面A(B(D,E),C)

3、E有左孩子,但无右孩子,故写成E(G,),带入得A(B(D,E(G,)),C)

4、C有右孩子,但无左孩子,写成C(,F),带入得A(B(D,E(G,)),C(,F))

总结:这种写法总的来说就是,树根(左子树,右子树),其中左子树又有左子树和右子树,同样右子树有左子树和右子树,一直递归下去,直到叶子结点。

        那怎么是用括号表示法的字符序列(上图的A(B(D,E(G,)),C(,F))) 创建二叉树,其算法思路如下:

(1)用str获取括号表示法表示二叉树的字符串

(2)用ch扫描str

(3)ch = '(' ,则将前面刚创建的结点作为双亲结点入栈,并置k = 1,表示其后创建的结点将作为这个结点的左孩子

(4)ch = ',' ,置k = 2,表示其后创建的结点为右孩子结点。

(5)ch = ')',表示栈顶元素的左右孩子结点处理完毕,出栈。

(6)其它情况创建一个结点,并根据 k 值,判断这个结点是栈中栈顶元素的左孩子还是右孩子,进行链接。

(7)一直循环下去直至str处理完成。

算法实现:

  1. /*栈的存储结构*/
  2. typedef struct Stack
  3. {
  4. BiTree data[Maxsize]; // 存放栈中元素
  5. int top; // 栈顶指针
  6. }SqStack;
  1. /*树的存储结构二叉链表*/
  2. typedef struct BiTNode
  3. {
  4. Elemtype data;
  5. struct BiTNode* lchild, * rchild;
  6. }BiTNode, * BiTree;
  1. /*初始化栈*/
  2. void InitStack(SqStack* S)
  3. {
  4. S->top = -1;
  5. }
  1. /*入栈*/
  2. bool Push(SqStack* S, BiTree x)
  3. {
  4. if (S->top == Maxsize - 1) // 栈满
  5. return false;
  6. S->data[++(S->top)] = x;
  7. return true;
  8. }
  1. /*出栈*/
  2. bool Pop(SqStack* S, BiTree* x)
  3. {
  4. if (S->top == -1) // 栈空
  5. return false;
  6. *x = S->data[(S->top)--];
  7. return true;
  8. }
  1. /*利用广义表构建二叉树*/
  2. void CreateBiTree2(BiTree* T, char* str)
  3. {
  4. SqStack S; // 辅助栈
  5. BiTree p = NULL, x; // 辅助指针
  6. InitStack(&S); // 初始化栈
  7. char ch;
  8. int i = 0, k;
  9. ch = str[i];
  10. while (ch != '\0') // str未扫描完时循环
  11. {
  12. switch (ch)
  13. {
  14. case '(': Push(&S, p); // 入栈,准备链接左孩子
  15. k = 1;
  16. break;
  17. case ')': Pop(&S, &x); // 出栈
  18. break;
  19. case ',': k = 2; // 准备链接右孩子
  20. break;
  21. default:
  22. p = (BiTree)malloc(sizeof(BiTNode));
  23. p->data = ch; p->lchild = p->rchild = NULL;
  24. if ((*T) == NULL) // p为二叉树的根结点
  25. (*T) = p;
  26. else // 已建立二叉树的根结点,根据k值链接左孩子还是右孩子
  27. {
  28. switch (k)
  29. {
  30. case 1: S.data[S.top]->lchild = p; break; // 链接左孩子
  31. case 2: S.data[S.top]->rchild = p; break; // 链接右孩子
  32. }
  33. }
  34. }
  35. i++;
  36. ch = str[i]; // 继续扫描str
  37. }
  38. }

(2)图解括号表示法构建二叉树

        我们用上图的括号表示法的字符串(A(B(D,E(G,)),C(,F)))来构建二叉树:

首先扫描到的A直接是其它情况,构建一个结点,并将A赋值给data,且创建的结点赋值给根结点T(由于刚开始树为空即T=NULL)

 下一次扫描为 ( , A入栈,并且 k = 1(为A链接左孩子左准备),再次扫描下一个字符:

扫描的字符为B,创建结点并赋值,此时T != NULL(执行else语句块),根据 k = 1,栈顶元素(A)链接左孩子(即B)

扫描到 ( , 执行B入栈,k = 1

扫描到 D,创建结点赋值,然后根据 k = 1,栈顶(B)将D作为左孩子进行链接

 扫描到 , ,k = 2,为栈顶元素(B)链接右孩子做准备 

然后接着扫描,扫描到E,创建结点并赋值,根据 k = 2,将C作为右孩子,链接到栈顶元素(B)

 扫描到 ( , 将E入栈,k = 1

扫描到 G,创建结点并赋值,根据 k = 1,将G作为左孩子,链接到栈顶元素(E)

 扫描到 ,,k = 2,接着扫描

扫描到 ),栈顶元素(E)退栈,此时栈中有 B、A

又扫描到 ),栈顶元素(B)退栈,此时栈只有 A

扫描到,, k = 2,接着扫描 

扫描到C,创建结点并赋值,根据 k = 2,C作为右孩子链接到栈顶元素(A)

扫描到 ( ,C入栈 k = 1

扫描到 ,k = 2,继续扫描

扫描到 F,创建节点并赋值,根据 k = 2,F作为右孩子链接到栈顶元素(C)

扫描到 (,进行退栈

 又扫描到(,进行退栈 

 至此,扫描结束,栈为空,二叉树构建完成。

(3)测试程序

  1. // 输入 A(B(D,E(G,)),C(,F))
  2. #include <stdio.h>
  3. #include <stdbool.h>
  4. #include <stdlib.h>
  5. #define Maxsize 100
  6. typedef char Elemtype;
  7. /*树的存储结构二叉链表*/
  8. typedef struct BiTNode
  9. {
  10. Elemtype data;
  11. struct BiTNode* lchild, * rchild;
  12. }BiTNode, * BiTree;
  13. /*栈的存储结构*/
  14. typedef struct Stack
  15. {
  16. BiTree data[Maxsize]; // 存放栈中元素
  17. int top; // 栈顶指针
  18. }SqStack;
  19. /*初始化栈*/
  20. void InitStack(SqStack* S);
  21. /*入栈*/
  22. bool Push(SqStack* S, BiTree x);
  23. /*出栈*/
  24. bool Pop(SqStack* S, BiTree* x);
  25. /*利用广义表构建二叉树*/
  26. void CreateBiTree2(BiTree* T, char* str2);
  27. /*先序遍历*/
  28. void PreOrder(BiTree T);
  29. /*输出树结点*/
  30. void visit(BiTree T);
  31. /*以广义表输出二叉树*/
  32. void DispBiTree(BiTree T);
  33. /*获取一个由二叉树构成的广义表字符*/
  34. void GetStr(char* str);
  35. int main(void)
  36. {
  37. BiTree T = NULL;
  38. char str[50];
  39. GetStr(str);
  40. CreateBiTree2(&T, str);
  41. printf("二叉树的先序遍历:\n");
  42. PreOrder(T);
  43. printf("二叉树的括号表示法:");
  44. DispBiTree(T);
  45. return 0;
  46. }
  47. /*初始化栈*/
  48. void InitStack(SqStack* S)
  49. {
  50. S->top = -1;
  51. }
  52. /*入栈*/
  53. bool Push(SqStack* S, BiTree x)
  54. {
  55. if (S->top == Maxsize - 1) // 栈满
  56. return false;
  57. S->data[++(S->top)] = x;
  58. return true;
  59. }
  60. /*出栈*/
  61. bool Pop(SqStack* S, BiTree* x)
  62. {
  63. if (S->top == -1) // 栈空
  64. return false;
  65. *x = S->data[(S->top)--];
  66. return true;
  67. }
  68. /*利用广义表构建二叉树*/
  69. void CreateBiTree2(BiTree* T, char* str)
  70. {
  71. SqStack S; // 辅助栈
  72. BiTree p = NULL, x; // 辅助指针
  73. InitStack(&S); // 初始化栈
  74. char ch;
  75. int i = 0, k;
  76. ch = str[i];
  77. while (ch != '\0') // str未扫描完时循环
  78. {
  79. switch (ch)
  80. {
  81. case '(': Push(&S, p); // 入栈,准备链接左孩子
  82. k = 1;
  83. break;
  84. case ')': Pop(&S, &x); // 出栈
  85. break;
  86. case ',': k = 2; // 准备链接右孩子结点
  87. break;
  88. default:
  89. p = (BiTree)malloc(sizeof(BiTNode));
  90. p->data = ch; p->lchild = p->rchild = NULL;
  91. if ((*T) == NULL) // p为二叉树的根结点
  92. (*T) = p;
  93. else // 已建立二叉树的根结点,根据k值链接左孩子还是右孩子
  94. {
  95. switch (k)
  96. {
  97. case 1: S.data[S.top]->lchild = p; break; // 链接左孩子
  98. case 2: S.data[S.top]->rchild = p; break; // 链接右孩子
  99. }
  100. }
  101. }
  102. i++;
  103. ch = str[i]; // 继续扫描str
  104. }
  105. }
  106. /*先序遍历*/
  107. void PreOrder(BiTree T)
  108. {
  109. if (T != NULL)
  110. {
  111. visit(T);
  112. PreOrder(T->lchild);
  113. PreOrder(T->rchild);
  114. }
  115. }
  116. /*输出树结点*/
  117. void visit(BiTree T)
  118. {
  119. printf("树结点的值:%c\n", T->data);
  120. }
  121. /*获取一个由二叉树构成的广义表字符*/
  122. void GetStr(char* str)
  123. {
  124. printf("请输入由二叉树构成的广义表字符串:");
  125. scanf("%s", str);
  126. }
  127. /*以广义表输出二叉树*/
  128. void DispBiTree(BiTree T)
  129. {
  130. if (T != NULL)
  131. {
  132. printf("%c", T->data);
  133. if (T->lchild != NULL || T->rchild != NULL) //左右子树不为空
  134. {
  135. printf("(");
  136. DispBiTree(T->lchild); // 递归处理左子树
  137. if (T->rchild != NULL)
  138. printf(",");
  139. DispBiTree(T->rchild); //递归处理右子树
  140. printf(")");
  141. }
  142. }
  143. }

 二、扩展二叉树

(1)扩展二叉树构建二叉树的算法思路及算法实现

        扩展二叉树:将二叉树中的每个结点的空指针引出一个虚结点,其值为一特值,比如"#",这种处理后的二叉树为原二叉树的扩展树。扩展二叉树就可以做到一个遍历序列确定一颗二叉树。如下图(前序遍历扩展二叉树,介绍的也是这种):

         上图扩展二叉树的前序序列为:ABD##EG###C#F##.

总结:将二叉树变为扩展二叉树,就是将原二叉树的每一个一件的度都变为2,即都有左、右孩子。

 算法思路:

(1)当 ch = '#',构建空指针,即(*T = NULL)

(2)ch != '#' ,创建新结点赋值,并进行递归构造左、右子树

算法实现:

  1. /*树的存储结构二叉链表*/
  2. typedef struct BiTNode
  3. {
  4. Elemtype data;
  5. struct BiTNode* lchild, * rchild;
  6. }BiTNode, * BiTree;
  1. /*利用一个前序遍历的扩展二叉树的字符串序列*/
  2. void CreateBiTree1(BiTree* T)
  3. {
  4. Elemtype ch;
  5. scanf("%c", &ch); //获取前序遍历的扩展二叉树的字符串的一个字符
  6. if (ch == '#')
  7. *T = NULL; // 空树结点
  8. else
  9. {
  10. *T = (BiTree)malloc(sizeof(BiTNode));
  11. if (!*T) // 未分配到空间
  12. exit(false);
  13. (*T)->data = ch; // 生成根结点
  14. (*T)->lchild = (*T)->rchild = NULL;
  15. CreateBiTree1(&(*T)->lchild); // 构造左子树
  16. CreateBiTree1(&(*T)->rchild); // 构造右子树
  17. }
  18. }

(2)测试程序

  1. // 输入 ABD##EG###C#F##
  2. #include <stdio.h>
  3. #include <stdbool.h>
  4. #include <stdlib.h>
  5. #define Maxsize 100
  6. typedef char Elemtype;
  7. /*树的存储结构二叉链表*/
  8. typedef struct BiTNode
  9. {
  10. Elemtype data;
  11. struct BiTNode* lchild, * rchild;
  12. }BiTNode, * BiTree;
  13. /*利用一个前序遍历的扩展二叉树的字符串序列*/
  14. void CreateBiTree1(BiTree* T);
  15. /*先序遍历*/
  16. void PreOrder(BiTree T);
  17. /*输出树结点*/
  18. void visit(BiTree T);
  19. int main(void)
  20. {
  21. BiTree T = NULL;
  22. printf("请输入前序遍历的扩展二叉树的字符序列:");
  23. CreateBiTree1(&T);
  24. printf("二叉树的先序遍历:\n");
  25. PreOrder(T);
  26. return 0;
  27. }
  28. /*利用一个前序遍历的扩展二叉树的字符串序列*/
  29. void CreateBiTree1(BiTree* T)
  30. {
  31. Elemtype ch;
  32. scanf("%c", &ch); //获取前序遍历的扩展二叉树的字符串的一个字符
  33. if (ch == '#')
  34. *T = NULL; // 空树结点
  35. else
  36. {
  37. *T = (BiTree)malloc(sizeof(BiTNode));
  38. if (!*T) // 未分配到空间
  39. exit(false);
  40. (*T)->data = ch; // 生成根结点
  41. (*T)->lchild = (*T)->rchild = NULL;
  42. CreateBiTree1(&(*T)->lchild); // 构造左子树
  43. CreateBiTree1(&(*T)->rchild); // 构造右子树
  44. }
  45. }
  46. /*先序遍历*/
  47. void PreOrder(BiTree T)
  48. {
  49. if (T != NULL)
  50. {
  51. visit(T);
  52. PreOrder(T->lchild);
  53. PreOrder(T->rchild);
  54. }
  55. }
  56. /*输出树结点*/
  57. void visit(BiTree T)
  58. {
  59. printf("树结点的值:%c\n", T->data);
  60. }

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号