• 线索二叉树


    目录

    一、线索二叉树的类型定义

    二、各种线索化的二叉树

    三、中序线索二叉树的算法

     完整代码

    四、有关哈夫曼树的定义

    哈夫曼编码


    一、线索二叉树的类型定义

    1. typedef struct BTNode
    2. {
    3. ElemType data;//数据域
    4. struct BTNode* lchild;//左孩子或线索指针
    5. struct BTNode* rchild;//右孩子或线索指针
    6. int ltag, rtag;
    7. }BTNode, * BTree;
    •  左标志ltag=0,表示lchild指向左孩子结点;ltag=1,表示lchild指向前驱结点
    • 右标志rtag=0,表示rchild指向右孩子结点;rtag=1,表示rchild指向后继结点
    • 二叉树线索化的基本思想
    • 二叉树的线索化实质上是遍历一棵二叉树。在遍历过程中,访问结点的操作是检查此结点的左、右指针域是否为空,如果为空,将它指向其前驱或后继结点的线索

    二、各种线索化的二叉树

     

    •  为了操作方便,在存储线索二叉树的时候增设一个头结点,其结构与其他的线索二叉树的结点相同,只是数据域不存储任何数据,其左指针域指向二叉树的根结点,右指针指向遍历的最后一个结点,而二叉树在某种遍历下的第一个结点的前驱和最后一个结点的后继线索都指向头结点。

    三、中序线索二叉树的算法

    • 第一种方法建立并且遍历中序线索二叉树: 
    1. //第一种方法
    2. void CreatInThread(BTree &T);建立中序线索树
    3. void InThread(BTree& T);//中序遍历二叉树,一边遍历一边线索化
    4. void visit(BTree& q);//访问根结点
    5. void visit2(BTree T);//遍历输出中序线索二叉树
    1. BTNode* pre = NULL;//定义全局变量
    2. void CreatInThread(BTree& T)//建立中序线索树
    3. {
    4. pre = NULL;
    5. if (T != NULL)
    6. {
    7. InThread(T);//中序线索化二叉树
    8. if (pre!=NULL&&pre->rchild == NULL)
    9. {
    10. pre->rtag = 1;
    11. }
    12. }
    13. }
    14. void InThread(BTree& T)//中序遍历二叉树,一边遍历一边线索化
    15. {
    16. if (T != NULL)
    17. {
    18. InThread(T->lchild);//左子树递归线索化
    19. visit(T);//访问根结点同时线索化
    20. InThread(T->rchild);//右子树递归线索化
    21. }
    22. }
    23. void visit(BTree& q)//访问根结点
    24. {
    25. if (q->lchild == NULL)//左子树为空的时候,让其前驱线索指向空
    26. {
    27. q->lchild = pre;
    28. q->ltag = 1;
    29. }
    30. else
    31. {
    32. q->ltag = 0;
    33. }
    34. if (pre != NULL && pre->rchild == NULL)
    35. {
    36. pre->rchild = q;//建立前驱结点的后继线索(让前驱结点的rchild域存放后继结点的地址)
    37. pre->rtag = 1;
    38. }
    39. else
    40. {
    41. q->rtag = 0;
    42. }
    43. pre = q;
    44. }
    45. void visit2(BTree T)//遍历中序线索二叉树
    46. {
    47. BTNode* p = T;
    48. while (p != NULL)
    49. {
    50. while (p->ltag == 0)//找开始结点
    51. {
    52. p = p->lchild;
    53. }
    54. cout << p->data << " ";//找到中序遍历最开始的结点并输出其data的值
    55. while (p->rtag == 1 && p->rchild != NULL)
    56. {
    57. p = p->rchild;
    58. cout << p->data << " ";
    59. }
    60. p = p->rchild;
    61. }
    62. return;
    63. }
    •  第二种方法建立并且遍历中序线索二叉树:
    1. //第二种方法
    2. BTree CreatBTree(BTree& T);//中序线索化二叉树,先创建头结点root
    3. void Thread(BTree& T);//中序线索化二叉树
    4. void ThInOrder(BTree T);//在中序线索化二叉树中实现中序遍历(输出)
    1. BTree CreatBTree(BTree & T)//中序线索化二叉树,先创建头结点root
    2. {
    3. BTNode* root = (BTNode*)malloc(sizeof(BTNode));//创建一个头结点
    4. if (root == NULL)
    5. {
    6. exit(0);
    7. }
    8. root->ltag = 0;
    9. root->rtag = 1;
    10. root->rchild = T;
    11. if (T == NULL)//空二叉树
    12. {
    13. root->lchild = root;
    14. }
    15. else
    16. {
    17. root->lchild = T;//头结点的lchild域存放二叉树根结点的地址
    18. pre = root;
    19. Thread(T);//中序线索化二叉树
    20. pre->rchild = root;//最后处理加入头结点的线索
    21. pre->rtag = 1;
    22. root->rchild = pre;//头结点线索化
    23. }
    24. return root;
    25. }
    26. void Thread(BTree& T)//中序线索化二叉树
    27. {
    28. if (T != NULL)
    29. {
    30. Thread(T->lchild);//左子树线索化
    31. if (T->lchild == NULL)
    32. {
    33. T->lchild = pre;//建立当前结点的前驱线索
    34. T->ltag = 1;
    35. }
    36. else
    37. {
    38. T->ltag = 0;
    39. }
    40. if (pre != NULL && pre->rchild == NULL)
    41. {
    42. pre->rchild = T;//建立前驱结点的后继线索
    43. pre->rtag = 1;
    44. }
    45. else
    46. {
    47. if (pre != NULL)
    48. {
    49. pre->rtag = 0;
    50. }
    51. }
    52. pre = T;
    53. Thread(T->rchild);//右子树线索化
    54. }
    55. }
    56. void ThInOrder(BTree tb)//tb指向中序线索二叉树的头结点
    57. {
    58. BTNode* p = tb->lchild;
    59. while (p != tb)
    60. {
    61. while (p->ltag == 0)//找中序二叉树的开始结点(开始结点在最左下方)
    62. {
    63. p = p->lchild;
    64. }
    65. cout << p->data << " ";
    66. while (p->rtag == 1 && p->rchild != tb)
    67. //p->rtag=1并且p->rchild!=头结点表示p结点的rchild域存放的是中序遍历的后继结点的地址(线索)
    68. {
    69. p = p->rchild;//沿右线索访问后继结点
    70. cout << p->data << " ";
    71. }
    72. p = p->rchild;//转向p的右子树
    73. }
    74. }
    •  完整代码

    1. #pragma once
    2. #include
    3. #include
    4. #include
    5. using namespace std;
    6. #define MAXSIZE 100
    7. typedef char ElemType;
    8. typedef struct BTNode
    9. {
    10. ElemType data;//数据域
    11. struct BTNode* lchild;//左孩子或线索指针
    12. struct BTNode* rchild;//右孩子或线索指针
    13. int ltag, rtag;
    14. }BTNode, * BTree;
    15. BTree Creat(char str[]);//先序序列建立二叉链表
    16. void PreOrder(BTree T);//先序遍历
    17. void InOrder(BTree T);//中序遍历
    18. void PostOrder(BTree T);//后序遍历
    19. void LevelOrder(BTree T);//层序遍历
    20. //第一种方法
    21. void CreatInThread(BTree &T);建立中序线索树
    22. void InThread(BTree& T);//中序遍历二叉树,一边遍历一边线索化
    23. void visit(BTree& q);//访问根结点
    24. void visit2(BTree T);//遍历输出中序线索二叉树
    25. //第二种方法
    26. BTree CreatBTree(BTree& T);//中序线索化二叉树,先创建头结点root
    27. void Thread(BTree& T);//中序线索化二叉树
    28. void ThInOrder(BTree T);//在中序线索化二叉树中实现中序遍历(输出)
    29. //找后继结点
    30. bool InPostNode(BTree& s);//寻找中序线索二叉树的的后继结点

    1. #include"TBTree.h"
    2. BTree Creat(char str[])//先序序列建立二叉链表(方法1)
    3. {
    4. BTree T;
    5. static int i = 0;
    6. ElemType c = str[i++];
    7. if (c == '#')//输入#表示此结点下不存在分支
    8. {
    9. T = NULL;
    10. }
    11. else
    12. {
    13. T = (BTree)malloc(sizeof(BTree));
    14. if (T == NULL)
    15. {
    16. exit(0);
    17. }
    18. T->data = c;
    19. T->lchild = Creat(str);//递归创建左子树
    20. T->rchild = Creat(str);//到上一个结点的右边递归创建左右子树
    21. }
    22. return T;
    23. }
    24. BTNode* pre = NULL;//定义全局变量
    25. void CreatInThread(BTree& T)//建立中序线索树
    26. {
    27. pre = NULL;
    28. if (T != NULL)
    29. {
    30. InThread(T);//中序线索化二叉树
    31. if (pre!=NULL&&pre->rchild == NULL)
    32. {
    33. pre->rtag = 1;
    34. }
    35. }
    36. }
    37. void InThread(BTree& T)//中序遍历二叉树,一边遍历一边线索化
    38. {
    39. if (T != NULL)
    40. {
    41. InThread(T->lchild);//左子树递归线索化
    42. visit(T);//访问根结点同时线索化
    43. InThread(T->rchild);//右子树递归线索化
    44. }
    45. }
    46. void visit(BTree& q)//访问根结点
    47. {
    48. if (q->lchild == NULL)//左子树为空的时候,让其前驱线索指向空
    49. {
    50. q->lchild = pre;
    51. q->ltag = 1;
    52. }
    53. else
    54. {
    55. q->ltag = 0;
    56. }
    57. if (pre != NULL && pre->rchild == NULL)
    58. {
    59. pre->rchild = q;//建立前驱结点的后继线索(让前驱结点的rchild域存放后继结点的地址)
    60. pre->rtag = 1;
    61. }
    62. else
    63. {
    64. q->rtag = 0;
    65. }
    66. pre = q;
    67. }
    68. bool InPostNode(BTree& s)//寻找中序线索二叉树的的后继结点
    69. {
    70. BTNode* post;
    71. post = s->rchild;
    72. if (s->rtag != 1)//结点s有右孩子
    73. {
    74. while (post->ltag == 0)//从右子树的根结点开始,沿左指针域往下查找,
    75. //直到没有左孩子为止
    76. {
    77. post = post->lchild;
    78. }
    79. }
    80. s = post;
    81. return true;
    82. }
    83. void visit2(BTree T)//遍历中序线索二叉树
    84. {
    85. BTNode* p = T;
    86. while (p != NULL)
    87. {
    88. while (p->ltag == 0)//找开始结点
    89. {
    90. p = p->lchild;
    91. }
    92. cout << p->data << " ";//找到中序遍历最开始的结点并输出其data的值
    93. while (p->rtag == 1 && p->rchild != NULL)
    94. {
    95. p = p->rchild;
    96. cout << p->data << " ";
    97. }
    98. p = p->rchild;
    99. }
    100. return;
    101. }
    102. BTree CreatBTree(BTree & T)//中序线索化二叉树,先创建头结点root
    103. {
    104. BTNode* root = (BTNode*)malloc(sizeof(BTNode));//创建一个头结点
    105. if (root == NULL)
    106. {
    107. exit(0);
    108. }
    109. root->ltag = 0;
    110. root->rtag = 1;
    111. root->rchild = T;
    112. if (T == NULL)//空二叉树
    113. {
    114. root->lchild = root;
    115. }
    116. else
    117. {
    118. root->lchild = T;//头结点的lchild域存放二叉树根结点的地址
    119. pre = root;
    120. Thread(T);//中序线索化二叉树
    121. pre->rchild = root;//最后处理加入头结点的线索
    122. pre->rtag = 1;
    123. root->rchild = pre;//头结点线索化
    124. }
    125. return root;
    126. }
    127. void Thread(BTree& T)//中序线索化二叉树
    128. {
    129. if (T != NULL)
    130. {
    131. Thread(T->lchild);//左子树线索化
    132. if (T->lchild == NULL)
    133. {
    134. T->lchild = pre;//建立当前结点的前驱线索
    135. T->ltag = 1;
    136. }
    137. else
    138. {
    139. T->ltag = 0;
    140. }
    141. if (pre != NULL && pre->rchild == NULL)
    142. {
    143. pre->rchild = T;//建立前驱结点的后继线索
    144. pre->rtag = 1;
    145. }
    146. else
    147. {
    148. if (pre != NULL)
    149. {
    150. pre->rtag = 0;
    151. }
    152. }
    153. pre = T;
    154. Thread(T->rchild);//右子树线索化
    155. }
    156. }
    157. void ThInOrder(BTree tb)//tb指向中序线索二叉树的头结点
    158. {
    159. BTNode* p = tb->lchild;
    160. while (p != tb)
    161. {
    162. while (p->ltag == 0)//找中序二叉树的开始结点(开始结点在最左下方)
    163. {
    164. p = p->lchild;
    165. }
    166. cout << p->data << " ";
    167. while (p->rtag == 1 && p->rchild != tb)
    168. //p->rtag=1并且p->rchild!=头结点表示p结点的rchild域存放的是中序遍历的后继结点的地址(线索)
    169. {
    170. p = p->rchild;//沿右线索访问后继结点
    171. cout << p->data << " ";
    172. }
    173. p = p->rchild;//转向p的右子树
    174. }
    175. }
    176. void PreOrder(BTree T)//先序遍历
    177. {
    178. if (T != NULL)
    179. {
    180. cout << T->data << " ";//访问根结点
    181. PreOrder(T->lchild);//先序遍历左子树
    182. PreOrder(T->rchild);//先序遍历右子树
    183. }
    184. }
    185. void InOrder(BTree T)//中序遍历
    186. {
    187. if (T != NULL)
    188. {
    189. InOrder(T->lchild);
    190. cout << T->data << " ";
    191. InOrder(T->rchild);
    192. }
    193. }
    194. void PostOrder(BTree T)//后序遍历
    195. {
    196. if (T != NULL)
    197. {
    198. PostOrder(T->lchild);
    199. PostOrder(T->rchild);
    200. cout << T->data << " ";
    201. }
    202. }
    203. void LevelOrder(BTree T)//层序遍历
    204. {
    205. BTNode* p;
    206. BTNode* qu[MAXSIZE];//定义循环队列,存放结点指针
    207. int front, rear;//定义头指针和尾指针
    208. front = rear = 0;//置队列为空队列
    209. rear++;
    210. qu[rear] = T;//根结点指针进队
    211. rear++;//队尾指针指向队尾元素的后一个位置
    212. front = (front + 1) % MAXSIZE;//队头指针加1取模
    213. while (front != rear)//队列不为空
    214. {
    215. p = qu[front];//取队头元素
    216. front = (front + 1) % MAXSIZE;//队头元素出队,队头指针后移
    217. cout << p->data << " ";
    218. if (p->lchild != NULL)
    219. {
    220. qu[rear] = p->lchild;//p结点的左孩子进栈
    221. rear = (rear + 1) % MAXSIZE;//队尾指针加1取模
    222. }
    223. if (p->rchild != NULL)
    224. {
    225. qu[rear] = p->rchild;//p结点的右孩子进栈
    226. rear = (rear + 1) % MAXSIZE;
    227. }
    228. }
    229. }
    1. #include"TBTree.h"
    2. int main()
    3. {
    4. cout << "二叉树建立的第一种方法" << endl;
    5. BTree T;//T为指向根结点的指针
    6. T = (BTree)malloc(50*sizeof(BTree));
    7. char str[] = { 'a','b','d','#','g','#','#','#','c','e','#','#','f','#','#' };
    8. T = Creat(str);
    9. cout << "先序遍历结果:";
    10. PreOrder(T);//先序遍历
    11. cout << endl;
    12. cout << "中序遍历结果:";
    13. InOrder(T);//中序遍历
    14. cout << endl;
    15. cout << "后序遍历结果:";
    16. PostOrder(T);//后序遍历
    17. cout << endl;
    18. cout << "层次遍历的结果:";
    19. LevelOrder(T);
    20. cout << endl << endl;
    21. /*cout << "中序线索树遍历结果:";
    22. CreatInThread(T);
    23. visit2(T);
    24. cout << endl << endl;*/
    25. cout << "中序遍历结果2:";
    26. BTree tb;
    27. tb = (BTree)malloc(50*sizeof(BTree));
    28. tb = CreatBTree(T);
    29. ThInOrder(tb);
    30. //system("pause");
    31. return 0;
    32. }

    四、有关哈夫曼树的定义

    • 路径:是指从一个结点到另一个结点之间的分支序列。
    • 路径长度:是指从一个结点到另一个结点所经过的分支数目。
    • 哈夫曼树:也称最优二叉树,是指对于一组带有确定权值的叶结点,构造的具有最小带权路径长度的二叉树

    • 哈夫曼树的构造步骤:

    给定n个权值分别为w1,w2...wn的结点
    1.将这n个结点分别作为n棵仅含一个结点的二叉树,构成森林F
    2.构造一个新的结点,从F中选取两棵根结点权值最小的树作为新结点的左,右子树,并且将
    新结点的权值置为左、右子树上根结点的权值之和。
    3.从F中删除刚才选出的两棵树,同时将新得到的树加入F中。
    4.重复步骤2和3,直至F中只剩下一棵树为止。 

     

    哈夫曼编码

    • 固定长度编码:每个字符用相等长度的二进制位表示

    例如:A--00;B--01;C--10;D--11

    • 可变长度编码:允许对不同字符用不等长的二进制位表示

    例如:C--0;A--10;B--111;D--110

    • 前缀编码:若没有一个编码是另一个编码的前缀,则称这样的编码为前缀编码

    由哈夫曼树得到的哈夫曼编码--字符集中每个字符作为一个叶子结点,各个字符出现的频度作为
    结点的权值。
     

  • 相关阅读:
    maven本地仓库同步上传到nexus远程仓库
    RabbitMQ 常用运维命令
    八皇后问题的解析与实现
    React 多环境运行打包配置(版本区分)
    双非本计算机从零开始三年努力能做到什么程度【学习路线回顾&总结&问答】
    WiFi密码别问了,这神器帮你搞定一切!
    测试工作十年,想对还在迷茫的朋友说:一点要做好个人规划...
    Go中的泛型和反射以及序列化
    【树莓派 Pico 基于Arduino IDE编程开发】
    计算机网络核心知识之Internet应用服务(超细致)
  • 原文地址:https://blog.csdn.net/m0_63783532/article/details/127992468