Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1184573
  • 博文数量: 573
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 66
  • 用 户 组: 普通用户
  • 注册时间: 2016-06-28 16:21
文章分类

全部博文(573)

文章存档

2018年(3)

2016年(48)

2015年(522)

分类: C/C++

2015-12-02 15:09:58


点击(此处)折叠或打开

  1. #include <string.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <stdbool.h>

  5. #define SZ_STRING 1024

  6. typedef char STRING[SZ_STRING];

  7. /************************************begin线索二叉树定义区****************************/
  8. /*Link == 0:指针,Thread == 1:线索*/
  9. typedef enum
  10. {
  11.     Link,
  12.     Thread
  13. }PointerTag;
  14. /*二叉树的二叉线索存储表示*/
  15. /*线索二叉树就是利用n+1个空链域来存放结点的前驱和后继结点的信息。只能得到部分线索的链表!: 但是它占用的空间小*/
  16. typedef struct binarythrnode
  17. {
  18.     STRING name; /*结点名称*/
  19.     STRING value;     /*结点值*/
  20.     PointerTag LTag, RTag; /*左右指针标志*/
  21.     struct binarythrnode * leftchild;     /*左指针*/
  22.     struct binarythrnode * rightchild;     /*右指针*/
  23. }BINARYTHRNODE;

  24. typedef BINARYTHRNODE * BinaryThrNodePtr;

  25. int GetLeftRightchildLenByPreAndMid(char * cur_pre, char * cur_mid, int * leftlen, int * rightlen);
  26. int CreateBinaryThrTreeByPreAndMid(BinaryThrNodePtr * root, char * cur_pre, char * cur_mid);

  27. void PreThreading(BinaryThrNodePtr binarythrnodeptr, BinaryThrNodePtr * prenode);
  28. void MidThreading(BinaryThrNodePtr binarythrnodeptr, BinaryThrNodePtr * prenode);
  29. void PosThreading(BinaryThrNodePtr binarythrnodeptr, BinaryThrNodePtr * prenode);
  30. int CreateBinaryTreeThreading(BinaryThrNodePtr * threadhead, BinaryThrNodePtr binarythrnodeptr, int type);

  31. void PreOrderTraverseThr(BinaryThrNodePtr threadhead, char * pre);
  32. void MidOrderTraverseThr(BinaryThrNodePtr threadhead, char * mid);
  33. void PosOrderTraverseThr(BinaryThrNodePtr threadhead, char * pos);
  34. BinaryThrNodePtr GetBinaryThrTreeParent(BinaryThrNodePtr threadhead, BinaryThrNodePtr binarythrnodeptr);

  35. void PrintBinaryTreeNodeByPre(BinaryThrNodePtr binarythrnodeptr);
  36. void PrintBinaryTreeNodeByMid(BinaryThrNodePtr binarythrnodeptr);
  37. void PrintBinaryTreeNodeByPos(BinaryThrNodePtr binarythrnodeptr);
  38. void PrintBinaryThrTreeNodeByPre(BinaryThrNodePtr threadhead);
  39. void PrintBinaryThrTreeNodeByMid(BinaryThrNodePtr threadhead);
  40. void PrintBinaryThrTreeNodeByPos(BinaryThrNodePtr threadhead);

  41. /************************************end线索二叉树定义区****************************/



  42. STRING data[26];

  43. int main(int argc, char * * argv)
  44. {
  45.     freopen("threadtree.txt", "w", stdout);
  46.     PointerTag flag1 = Link;
  47.     PointerTag flag2 = Thread;
  48.     printf("flag1=[%d], flag2=[%d]\n", Link, Thread);
  49.     
  50.     printf("二叉树的二叉线索存储结构!(只能得到部分线索的链表!)\n");
  51.     
  52.     int i;
  53.     for(i=0; i<26; i++) /*所有的数据域赋初值*/
  54.     {
  55.         /*特点:data数组的每个元素都是STRING*/
  56.         memset(data[i], 0, sizeof(STRING));
  57.     }
  58.     for(i=0; i<26; i++) /*给所有的数据域赋值*/
  59.     {
  60.         /*data数据域中的数据,即为26个字母的大写(65是A)*/
  61.         memset(data[i], 65+i, sizeof(char)*3);
  62.     }
  63.     
  64.     char pre[128]; /*前序序列*/
  65.     char mid[128]; /*中序序列*/
  66.     char pos[128]; /*后序序列*/
  67.     char lev[128]; /*层次序列*/
  68.     
  69.     printf("******************************************begin第1颗二叉树*******************************************\n");
  70.     
  71.     memset(pre, 0, sizeof(pre));
  72.     strcpy(pre, "ABDHIEJCFG");
  73.     printf("前序序列=[%s]\n", pre);
  74.     memset(mid, 0, sizeof(mid));
  75.     strcpy(mid, "HDIBJEAFCG");
  76.     printf("中序序列=[%s]\n", mid);
  77.     
  78.     printf("创建二叉线索存储结构的二叉树:\n");
  79.     BinaryThrNodePtr rootthrnodeptr1 = NULL;
  80.     CreateBinaryThrTreeByPreAndMid(&rootthrnodeptr1, pre, mid);
  81.     printf("按照中序遍历序列,打印出整颗二叉树:\n");
  82.     PrintBinaryTreeNodeByMid(rootthrnodeptr1);
  83.     
  84.     BinaryThrNodePtr threadhead = NULL; /*线索链表的头节点*/
  85.     printf("中序线索化二叉树:\n");
  86.     CreateBinaryTreeThreading(&threadhead, rootthrnodeptr1, 0); /*中序线索化二叉树*/
  87.     printf("按照中序遍历序列,打印出整颗中序线索化二叉树:\n");
  88.     PrintBinaryThrTreeNodeByMid(threadhead);
  89.     memset(mid, 0, sizeof(mid));
  90.     MidOrderTraverseThr(threadhead, mid);
  91.     printf("中序线索化二叉树:中序遍历序列(非递归)........=[%s]\n", mid);
  92.     
  93.     printf("******************************************end第1颗二叉树*******************************************\n");
  94.     
  95.     printf("\n\n******************************************begin第2颗二叉树*******************************************\n");
  96.         
  97.     memset(pre, 0, sizeof(pre));
  98.     strcpy(pre, "ABDHIEJCFG");
  99.     printf("前序序列=[%s]\n", pre);
  100.     memset(mid, 0, sizeof(mid));
  101.     strcpy(mid, "HDIBJEAFCG");
  102.     printf("中序序列=[%s]\n", mid);
  103.     
  104.     printf("创建二叉线索存储结构的二叉树:\n");
  105.     BinaryThrNodePtr rootthrnodeptr2 = NULL;
  106.     CreateBinaryThrTreeByPreAndMid(&rootthrnodeptr2, pre, mid);
  107.     printf("按照先序遍历序列,打印出整颗二叉树:\n");
  108.     PrintBinaryTreeNodeByPre(rootthrnodeptr2);
  109.     
  110.     printf("先序线索化二叉树:\n");
  111.     CreateBinaryTreeThreading(&threadhead, rootthrnodeptr2, -1); /*先序线索化二叉树*/
  112.     printf("按照先序遍历序列,打印出整颗先序线索化二叉树:\n");
  113.     PrintBinaryThrTreeNodeByPre(threadhead);
  114.     memset(pre, 0, sizeof(pre));
  115.     printf("====================================\n");
  116.     PreOrderTraverseThr(threadhead, pre);
  117.     printf("====================================\n");
  118.     printf("先序线索化二叉树:先序遍历序列(非递归)........=[%s]\n", pre);
  119.     
  120.     printf("******************************************end第2颗二叉树*******************************************\n");
  121.     
  122.     printf("\n\n******************************************begin第3颗二叉树*******************************************\n");
  123.     
  124.     memset(pre, 0, sizeof(pre));
  125.     strcpy(pre, "ABDHIEJCFG");
  126.     printf("前序序列=[%s]\n", pre);
  127.     memset(mid, 0, sizeof(mid));
  128.     strcpy(mid, "HDIBJEAFCG");
  129.     printf("中序序列=[%s]\n", mid);
  130.     
  131.     printf("创建二叉线索存储结构的二叉树:\n");
  132.     BinaryThrNodePtr rootthrnodeptr3 = NULL;
  133.     CreateBinaryThrTreeByPreAndMid(&rootthrnodeptr3, pre, mid);
  134.     printf("按照后序遍历序列,打印出整颗二叉树:\n");
  135.     PrintBinaryTreeNodeByPos(rootthrnodeptr3);
  136.     
  137.     printf("后序线索化二叉树:\n");
  138.     CreateBinaryTreeThreading(&threadhead, rootthrnodeptr3, 1); /*后序线索化二叉树*/
  139.     printf("按照后序遍历序列,打印出整颗后序线索化二叉树:\n");
  140.     PrintBinaryThrTreeNodeByPos(threadhead);
  141.     memset(pos, 0, sizeof(pos));
  142.     printf("====================================\n");
  143.     PosOrderTraverseThr(threadhead, pos);
  144.     printf("====================================\n");
  145.     printf("后序线索化二叉树:后序遍历序列(非递归)........=[%s]\n", pos);
  146.     
  147.     printf("******************************************end第3颗二叉树*******************************************\n");
  148.     
  149.     return 0;
  150. }

  151. /*功能:层次线索化二叉树*/
  152. /*功能:层次遍历线索化二叉树*/

  153. /*功能:如何去线索化??*/

  154. /*功能:求一个二叉树结点的双亲元素*/
  155. BinaryThrNodePtr GetBinaryThrTreeParent(BinaryThrNodePtr threadhead, BinaryThrNodePtr binarythrnodeptr)
  156. {
  157.     BinaryThrNodePtr tempptr = NULL;
  158.     tempptr = threadhead;
  159.     if(tempptr->leftchild == binarythrnodeptr)
  160.         return tempptr; /*父节点是头结点*/
  161.     else
  162.     {
  163.         tempptr = tempptr->leftchild; /*tempptr指向头结点*/
  164.         while((tempptr->leftchild != binarythrnodeptr) && (tempptr->rightchild != binarythrnodeptr))
  165.         {
  166.             if(Link==tempptr->RTag)
  167.                 tempptr = tempptr->rightchild; /*如果节点有右节点,那么往右*/
  168.             else
  169.                 tempptr = tempptr->leftchild; /*如果节点没有右孩子,那么去左孩子,没有左孩子,去前驱,也是走往左*/
  170.         }
  171.         return tempptr;
  172.     }
  173. }

  174. /*************************************************************************
  175.  *函数名:PosOrderTraverseThr()
  176.  *功能:遍历后序线索化二叉树(非递归)
  177.  *输入参数:
  178.  * threadhead :线索二叉树的头结点
  179.  *输出参数:
  180.  * pos : 后序序列
  181.  *返回值:空
  182.  *特点:非递归遍历时,如果有线索链表是可以方便的实现遍历,可以不用栈了。
  183.  *编程思想:
  184.  *     遍历后序线索化二叉树与遍历先序中序索化二叉树编程思想很相似,但是要复杂一些:
  185. **************************************************************************/
  186. void PosOrderTraverseThr(BinaryThrNodePtr threadhead, char * pos)
  187. {
  188.     BinaryThrNodePtr p = NULL;
  189.     BinaryThrNodePtr parentptr = NULL;
  190.     p = threadhead->leftchild; /*p指向根结点*/
  191.     
  192.     /*从根开始:一直向左,走到最左下方*/
  193.     while(p->LTag == Link)
  194.     {
  195.         p = p->leftchild; /*p指向第一个被访问的节点*/
  196.     }

  197.     while(p != threadhead)
  198.     {
  199.         /*printf("结点名=[%s], 结点值=[%s], LTag=[%d], RTag=[%d]\n", p->name, p->value, p->LTag, p->RTag);*/
  200.         strncat(pos, p->name, sizeof(char)*1); /*得到后序序列*/
  201.         parentptr = GetBinaryThrTreeParent(threadhead, p); /*parentptr是p的双亲*/
  202.         
  203.         if(parentptr == threadhead) /*p是根节点,整颗树就一个结点,没有左右孩子*/
  204.         {
  205.             break;
  206.         }
  207.         
  208.         if(parentptr->RTag == Thread) /*parentptr没有右孩子*/
  209.         {
  210.             p = parentptr; /*根据(后序:,,)p是左孩子,右孩子为空,可以开始遍历根结点了*/
  211.         }
  212.         else if(p == parentptr->rightchild) /*p是parentptr的右孩子*/
  213.         {
  214.             p = parentptr; /*根据(后序:,,)p是右孩子,已访问,可以开始遍历根结点了*/
  215.         }
  216.         else if(p == parentptr->leftchild) /*p是parentptr的左孩子*/
  217.         {
  218.             if(parentptr->RTag == Link) /*parentptr有右孩子*/
  219.             {
  220.                 parentptr = parentptr->rightchild; /*再把这个根的右孩子,当做根结点*/
  221.                 while(parentptr->LTag == Link) /*从根开始:一直向左,走到最左下方*/
  222.                 {
  223.                     parentptr = parentptr->leftchild;
  224.                 }
  225.             }
  226.             p = parentptr;
  227.         }
  228.     }
  229. }

  230. /*************************************************************************
  231.  *函数名:PreOrderTraverseThr()
  232.  *功能:遍历先序线索化二叉树(非递归)
  233.  *输入参数:
  234.  * threadhead :线索二叉树的头结点
  235.  *输出参数:
  236.  * pre : 先序序列
  237.  *返回值:空
  238.  *特点:非递归遍历时,如果有线索链表是可以方便的实现遍历,可以不用栈了。
  239. **************************************************************************/
  240. void PreOrderTraverseThr(BinaryThrNodePtr threadhead, char * pre)
  241. {
  242.     BinaryThrNodePtr p = NULL;
  243.     p = threadhead->leftchild; /*p指向根结点*/
  244.     while(p != threadhead) /*p指向线索链表头threadhead时:表示遍历结束*/
  245.     {
  246.         while(p->LTag == Link)
  247.         {
  248.             /*p指向的结点:有左子树,就可以访问了*/
  249.             /*printf("结点名=[%s], 结点值=[%s], LTag=[%d], RTag=[%d]\n", p->name, p->value, p->LTag, p->RTag);*/
  250.             strncat(pre, p->name, sizeof(char)*1); /*得到先序序列*/
  251.             p = p->leftchild;
  252.         }
  253.         
  254.         while(p->RTag == Thread) /*有后继结点,就一直向后找*/
  255.         {
  256.             /*p指向的结点:有后继结点,是可以直接访问的*/
  257.             /*printf("结点名=[%s], 结点值=[%s], LTag=[%d], RTag=[%d]\n", p->name, p->value, p->LTag, p->RTag);*/
  258.             strncat(pre, p->name, sizeof(char)*1); /*得到先序序列*/
  259.             p = p->rightchild;
  260.             if(p == threadhead) /*p指向线索头结点了,就可以跳出循环了*/
  261.             {
  262.                 break;
  263.             }
  264.         }
  265.     }
  266. }

  267. /*************************************************************************
  268.  *函数名:MidOrderTraverseThr()
  269.  *功能:遍历中序线索化二叉树(非递归)
  270.  *输入参数:
  271.  * threadhead :线索二叉树的头结点
  272.  *输出参数:
  273.  * mid : 中序序列
  274.  *返回值:空
  275.  *特点:非递归遍历时,如果有线索链表是可以方便的实现遍历,可以不用栈了。
  276. **************************************************************************/
  277. void MidOrderTraverseThr(BinaryThrNodePtr threadhead, char * mid)
  278. {
  279.     BinaryThrNodePtr p = NULL;
  280.     p = threadhead->leftchild; /*p指向根结点*/
  281.     while(p != threadhead) /*p指向threadhead时:表示遍历结束*/
  282.     {
  283.         while(p->LTag == Link) /*结点指针走到最左下结点,就可以访问了*/
  284.         {
  285.             p = p->leftchild;
  286.         }
  287.         /*printf("结点名=[%s], 结点值=[%s], LTag=[%d], RTag=[%d]\n", p->name, p->value, p->LTag, p->RTag);*/
  288.         strncat(mid, p->name, sizeof(char)*1); /*得到中序序列*/
  289.         
  290.         while((p->RTag == Thread)&&(p->rightchild != threadhead)) /*有后继结点,就一直向后找*/
  291.         {
  292.             p = p->rightchild; /*后继线索指针指向后继结点,是可以直接访问的*/
  293.             /*printf("结点名=[%s], 结点值=[%s], LTag=[%d], RTag=[%d]\n", p->name, p->value, p->LTag, p->RTag);*/
  294.             strncat(mid, p->name, sizeof(char)*1); /*得到中序序列*/
  295.         }
  296.         p = p->rightchild; /*没有后继了,就找右孩子结点,做右子树根结点*/
  297.     }
  298. }

  299. /*************************************************************
  300.  *函数名:PreThreading()
  301.  *功能:前序线索化(只能部分线索)
  302.  *前序线索化:是指用二叉链表结点数据结构建立二叉树的二叉链表,然后按照前序遍历的方法访问结点时建立线索。
  303.  *输入参数:
  304.  * root :二叉树的根结点
  305.  * prenode : 刚刚访问过的结点 :即为当前访问结点的前驱
  306.  *输出参数:
  307.  * prenode :
  308.  *返回值:空
  309.  *注意:第一次递归调用时,prenode指向线索链表的空头结点
  310.  *线索化的实质:将二叉链表中的空指针改为指向前驱或后继的线索
  311.  *线索化的过程:在遍历的过程中修改空指针的过程
  312. **************************************************************/
  313. void PreThreading(BinaryThrNodePtr binarythrnodeptr, BinaryThrNodePtr * prenode)
  314. {
  315.     if(binarythrnodeptr == NULL) /*加了线索之后,起始没有空指针域了,递归不可能从这里返回了*/
  316.     {
  317.         return;
  318.     }
  319.     /*开始访问前序遍历的结点。*/
  320.     if(binarythrnodeptr->leftchild == NULL) /*当前访问的结点:若其左孩子为空:则左孩子指针域加前驱线索*/
  321.     {
  322.         binarythrnodeptr->LTag = Thread;
  323.         binarythrnodeptr->leftchild = (*prenode); /*加前驱线索*/
  324.     }
  325.     if((*prenode)->rightchild == NULL) /*刚刚访问过的结点:若其右孩子为空:则右孩子指针域加后继线索*/
  326.     {
  327.         (*prenode)->RTag = Thread;
  328.         (*prenode)->rightchild = binarythrnodeptr; /*加后继线索*/
  329.     }
  330.     *prenode = binarythrnodeptr; /*保证*prenode指向刚刚访问过的结点*/
  331.     
  332.     if(binarythrnodeptr->LTag == Link) /*左子树存在,注意:这个判断一个要有*/
  333.     {
  334.         PreThreading(binarythrnodeptr->leftchild, prenode); /*左子树前序线索化*/
  335.     }
  336.     if(binarythrnodeptr->RTag == Link) /*右子树存在*/
  337.     {
  338.         PreThreading(binarythrnodeptr->rightchild, prenode); /*右子树前序线索化*/
  339.     }
  340. }

  341. /*************************************************************
  342.  *函数名:MidThreading()
  343.  *功能:中序线索化(只能部分线索)
  344.  *中序线索化:是指用二叉链表结点数据结构建立二叉树的二叉链表,然后按照中序遍历的方法访问结点时建立线索。
  345.  *输入参数:
  346.  * binarythrnodeptr :二叉树的根结点
  347.  * prenode : 刚刚访问过的结点 :即为当前访问结点的前驱(初始指向线索链表的空头结点)
  348.  *输出参数:
  349.  * prenode :
  350.  *返回值:空
  351.  *注意:第一次递归调用时,prenode指向线索链表的空头结点
  352.  *线索化的实质:将二叉链表中的空指针改为指向前驱或后继的线索
  353.  *线索化的过程:在遍历的过程中修改空指针的过程
  354. **************************************************************/
  355. void MidThreading(BinaryThrNodePtr binarythrnodeptr, BinaryThrNodePtr * prenode)
  356. {
  357.     if(binarythrnodeptr == NULL)
  358.     {
  359.         return;
  360.     }
  361.     if(binarythrnodeptr->LTag == Link)
  362.     {
  363.         MidThreading(binarythrnodeptr->leftchild, prenode); /*左子树中序线索化*/
  364.     }
  365.     /*开始访问中序遍历的结点。*/
  366.     if(binarythrnodeptr->leftchild == NULL) /*当前访问的结点:若其左孩子为空:则左孩子指针域加前驱线索*/
  367.     {
  368.         binarythrnodeptr->LTag = Thread;
  369.         binarythrnodeptr->leftchild = (*prenode); /*加前驱线索*/
  370.     }
  371.     if((*prenode)->rightchild == NULL) /*刚刚访问过的结点:若其右孩子为空:则右孩子指针域加后继线索*/
  372.     {
  373.         (*prenode)->RTag = Thread;
  374.         (*prenode)->rightchild = binarythrnodeptr; /*加后继线索*/
  375.     }
  376.     *prenode = binarythrnodeptr; /*保证*prenode指向刚刚访问过的结点*/
  377.     
  378.     if(binarythrnodeptr->RTag == Link)
  379.     {
  380.         MidThreading(binarythrnodeptr->rightchild, prenode); /*右子树中序线索化*/
  381.     }
  382. }

  383. /*************************************************************
  384.  *函数名:PosThreading()
  385.  *功能:后序线索化(只能部分线索)
  386.  *后序线索化:是指用二叉链表结点数据结构建立二叉树的二叉链表,然后按照后序遍历的方法访问结点时建立线索。
  387.  *输入参数:
  388.  * root :二叉树的根结点
  389.  * prenode : 刚刚访问过的结点 :即为当前访问结点的前驱
  390.  *输出参数:
  391.  * prenode :
  392.  *返回值:空
  393.  *注意:第一次递归调用时,prenode指向线索链表的空头结点
  394.  *线索化的实质:将二叉链表中的空指针改为指向前驱或后继的线索
  395.  *线索化的过程:在遍历的过程中修改空指针的过程
  396. **************************************************************/
  397. void PosThreading(BinaryThrNodePtr binarythrnodeptr, BinaryThrNodePtr * prenode)
  398. {
  399.     if(binarythrnodeptr == NULL)
  400.     {
  401.         return;
  402.     }
  403.     if(binarythrnodeptr->LTag == Link) /*左子树存在*/
  404.     {
  405.         PosThreading(binarythrnodeptr->leftchild, prenode); /*左子树后序线索化*/
  406.     }
  407.     if(binarythrnodeptr->RTag == Link) /*右子树存在*/
  408.     {
  409.         PosThreading(binarythrnodeptr->rightchild, prenode); /*右子树后序线索化*/
  410.     }
  411.     /*开始访问后序遍历的结点。*/
  412.     if(binarythrnodeptr->leftchild == NULL) /*当前访问的结点:若其左孩子为空:则左孩子指针域加前驱线索*/
  413.     {
  414.         binarythrnodeptr->LTag = Thread;
  415.         binarythrnodeptr->leftchild = (*prenode); /*加前驱线索*/
  416.     }
  417.     if((*prenode)->rightchild == NULL) /*刚刚访问过的结点:若其右孩子为空:则右孩子指针域加后继线索*/
  418.     {
  419.         (*prenode)->RTag = Thread;
  420.         (*prenode)->rightchild = binarythrnodeptr; /*加后继线索*/
  421.     }
  422.     *prenode = binarythrnodeptr; /*保证*prenode指向刚刚访问过的结点*/
  423. }

  424. /*************************************************************
  425.  *函数名:CreateBinaryTreeThreading()
  426.  *功能:将二叉树线索化,得到二叉树线索链表
  427.  *输入参数:
  428.  * binarythrnodeptr :待线索化的二叉树根节点
  429.  * type : 线索方式(-1: 先序遍历, 0:中序遍历, 1:后序遍历)
  430.  *输出参数:
  431.  * threadhead :线索链表的头结点
  432.  *返回值:
  433.  * 0:成功 -1:失败
  434.  *线索化的实质:将二叉链表中的空指针改为指向前驱或后继的线索
  435.  *线索化的过程:在遍历的过程中修改空指针的过程
  436. **************************************************************/
  437. int CreateBinaryTreeThreading(BinaryThrNodePtr * threadhead, BinaryThrNodePtr binarythrnodeptr, int type)
  438. {
  439.     BinaryThrNodePtr prenode = NULL; /*存放刚刚访问过的结点 :即为当前访问结点的前驱*/
  440.     *threadhead = (BINARYTHRNODE *)malloc(sizeof(BINARYTHRNODE)); /*建立头结点*/
  441.     if(*threadhead == NULL)
  442.     {
  443.         printf("CreateThreading malloc err!\n");
  444.         return -1;
  445.     }
  446.     (*threadhead)->LTag = Link; /*头结点左标志域为Link:左孩子指针*/
  447.     (*threadhead)->RTag = Thread; /*头结点右标志域为Thread:后继指针*/
  448.     (*threadhead)->rightchild = *threadhead; /*头结点后继指针暂时回指*/
  449.     if(binarythrnodeptr == NULL) /*若二叉树为空*/
  450.     {
  451.         (*threadhead)->leftchild = *threadhead; /*为空,则前驱指针回指*/
  452.     }
  453.     else /*二叉树非空*/
  454.     {
  455.         (*threadhead)->leftchild = binarythrnodeptr; /*非空,则头结点的左孩子指向根结点*/
  456.         prenode = (*threadhead); /*刚刚访问过的结点记录下来,初始指向线索链表的空头结点*/
  457.         if(type == -1)
  458.         {
  459.             PreThreading(binarythrnodeptr, &prenode); /*前序线索化*/
  460.         }
  461.         else if(type == 0)
  462.         {
  463.             MidThreading(binarythrnodeptr, &prenode); /*中序线索化*/
  464.         }
  465.         else if(type == 1)
  466.         {
  467.             PosThreading(binarythrnodeptr, &prenode); /*后序线索化*/
  468.         }
  469.         else
  470.         {
  471.             printf("type 参数不对!\n");
  472.         }
  473.         /*prenode会指向遍历序列的最后一个结点 : 最后一个结点线索化*/
  474.         if(prenode->rightchild == NULL)
  475.         {
  476.             prenode->RTag = Thread;
  477.             prenode->rightchild = *threadhead;
  478.         }
  479.         (*threadhead)->rightchild = prenode; /*头结点后继指针指向最后一个结点*/
  480.     }
  481. }

  482. /************************************
  483.  *函数名:GetLeftRightchildLenByPreAndMid()
  484.  *功能:根据二叉树的先序序列+中序序列,取得当前二叉树左右孩子的结点数
  485.  *输入参数:
  486.  * cur_pre: 当前二叉树的先序序列(其中:cur_pre中第一个元素,即是根元素结点)
  487.  * cur_mid: 当前二叉树的中序序列
  488.  *输出参数:
  489.  * leftlen: 当前二叉树左孩子的长度
  490.  * rightlen: 当前二叉树右孩子的长度
  491.  *返回值:
  492.  * 0:成功 -1:失败
  493.  *
  494.  *由二叉树的先序序列+中序序列,求当前二叉树的左右孩子的结点数方法:
  495.  * 先序序列的第一个元素就是当前二叉树的根结点。
  496.  *    在中序序列中对比根结点所在的位置,
  497.  *    则中序序列中根结点的左边就是根结点的左孩子,即可求出左孩子的结点数,
  498.  *    中序序列中根结点的右边就是根结点的右孩子,即可求出右孩子的结点数,
  499. *************************************/
  500. int GetLeftRightchildLenByPreAndMid(char * cur_pre, char * cur_mid, int * leftlen, int * rightlen)
  501. {
  502.     int left_len = 0;
  503.     if((cur_pre != NULL)&&(cur_mid != NULL)) /*序列非空,则树存在*/
  504.     {
  505.         /* *cur_pre:就是该二叉树的根结点 */
  506.         while(*(cur_mid+left_len) != *cur_pre) /*从中序序列的第一个元素开始与根元素比较*/
  507.         {
  508.             left_len++;
  509.         }
  510.         *leftlen = left_len;
  511.         /*当前二叉树右孩子的结点数=全树长-左孩子的结点数-根结点数*/
  512.         *rightlen = strlen(cur_pre) - left_len - 1;    
  513.     }
  514.     else
  515.     {
  516.         *leftlen = 0;
  517.         *rightlen = 0;    
  518.     }
  519.     return 0;
  520. }

  521. /**********************************************************
  522.  *函数名:CreateBinaryThrTreeByPreAndMid()
  523.  *功能:创建二叉树(由前序序列+中序序列,创建一颗二叉树)
  524.  *输入参数:
  525.  * cur_pre: 当前二叉树的先序序列
  526.  * cur_mid: 当前二叉树的中序序列
  527.  *输出参数:
  528.  * root: 二叉树的根结点
  529.  *返回值:
  530.  * 0-成功 -1-失败
  531.  *示例遍历序列编号:
  532.  *     先序序列=[A,B,D,H,I,E,J,C,F,G]
  533.  * 中序序列=[H,D,I,B,J,E,A,F,C,G]
  534.  * 后序序列=[H,I,D,J,E,B,F,G,C,A]
  535.  * 层次序列=[A,B,C,D,E,F,G,H,I,J]
  536.  *(由前序序列+中序序列,可唯一确定一颗二叉树)编程思路:
  537.  *        从当前二叉树先序序列cur_pre开始,第一个是根结点,再右边的leftlen个结点是左孩子,再右边rightlen个结点是右孩子,
  538.  *        则当前二叉树左孩子的先序序列从cur_pre+1地址开始,长:leftlen。当前二叉树右孩子的先序序列从cur_pre+1+leftlen地址开始,长:rightlen。
  539.  *     从当前二叉树中序序列根元素开始,左右分开,左边是当前二叉树左孩子,右边是当前二叉树右孩子。
  540.  *     则当前二叉树左孩子的中序序列继续从当前二叉树的中序序列的cur_mid地址开始,长:leftlen。当前二叉树右孩子的中序序列从cur_mid+leftlen+1地址开始,长:rightlen。
  541. ***********************************************************/
  542. int CreateBinaryThrTreeByPreAndMid(BinaryThrNodePtr * root, char * cur_pre, char * cur_mid)
  543. {
  544.     int i = 0;
  545.     int ret = -1;
  546.     int leftlen; /*当前二叉树左孩子的结点数*/
  547.     int rightlen; /*当前二叉树右孩子的结点数*/
  548.     char left_pre[128]; /*当前二叉树左孩子的先序序列*/
  549.     char left_mid[128]; /*当前二叉树左孩子的中序序列*/
  550.     char right_pre[128]; /*当前二叉树右孩子的先序序列*/
  551.     char right_mid[128]; /*当前二叉树右孩子的中序序列*/
  552.     
  553.     memset(left_pre, 0 ,sizeof(left_pre));
  554.     memset(left_mid, 0, sizeof(left_mid));
  555.     memset(right_pre, 0 ,sizeof(right_pre));
  556.     memset(right_mid, 0, sizeof(right_mid));
  557.     
  558.     if((cur_pre != NULL)&&(cur_mid != NULL)) /*当树的序列非空,则表明树是存在的*/
  559.     {
  560.         /*接下来创建一个结点的存储区域*/
  561.         *root = (BINARYTHRNODE *)malloc(sizeof(BINARYTHRNODE));
  562.         if(*root == NULL)
  563.         {
  564.             printf("CreateBinaryThrTreeByPreAndMid malloc err!\n");
  565.             return -1;
  566.         }
  567.         memset(*root, 0, sizeof(BINARYTHRNODE));
  568.         memset((*root)->name, 0, sizeof(STRING));
  569.         memset((*root)->value, 0, sizeof(STRING));
  570.         /*以当前二叉树先序序列cur_pre中的第一个元素(*cur_pre)作为域值来生成根结点*/
  571.         strncpy((*root)->name, cur_pre, sizeof(char)*1); /*填充根结点名*/
  572.         /*整颗二叉树是10个节点,data[i]中的数据是10个字符串,即为先序序列cur_pre中相同的数据*/
  573.         for(i=0; i<10; i++)
  574.         {
  575.             /*或者:if((*cur_pre) == data[i][0])*/
  576.             if(strncmp(cur_pre, data[i], sizeof(char)*1) == 0) /*定位结点数据域要填充的字符串*/
  577.             {
  578.                 strcpy((*root)->value, data[i]); /*填充根结点值*/
  579.                 break;
  580.             }
  581.         }
  582.         (*root)->LTag = (*root)->RTag = Link;
  583.         (*root)->leftchild = (*root)->rightchild = NULL; /*刚生成的节点左右孩子指针先赋NULL值*/
  584.         
  585.         /*获取当前二叉树左孩子的结点数leftlen, 右孩子的结点数rightlen*/
  586.         GetLeftRightchildLenByPreAndMid(cur_pre, cur_mid, &leftlen, &rightlen);
  587.         
  588.         memcpy(left_pre, cur_pre+1, leftlen); /*左孩子的先序序列*/
  589.         memcpy(left_mid, cur_mid, leftlen); /*左孩子的中序序列*/
  590.         /*printf("结点=[%c],左孩子:结点数=[%d],先序序列=[%s],中序序列=[%s]\n", *cur_pre, leftlen, left_pre,left_mid);*/
  591.         memcpy(right_pre, cur_pre+1+leftlen, rightlen); /*右孩子的先序序列*/
  592.         memcpy(right_mid, cur_mid+leftlen+1, rightlen); /*右孩子的中序序列*/
  593.         /*printf("结点=[%c],右孩子:结点数=[%d],先序序列=[%s],中序序列=[%s]\n", *cur_pre, rightlen, right_pre, right_mid);*/

  594.         if(leftlen > 0) /*当前二叉树左孩子存在,才需要创建这颗二叉树*/
  595.         {
  596.             ret = CreateBinaryThrTreeByPreAndMid(&((*root)->leftchild), left_pre, left_mid); /*创建当前二叉树的左孩子*/
  597.             if(ret < 0)
  598.                 return -1;
  599.         }

  600.         if(rightlen > 0) /*当前二叉树右孩子存在,才需要创建这颗二叉树*/
  601.         {
  602.             ret = CreateBinaryThrTreeByPreAndMid(&((*root)->rightchild), right_pre, right_mid); /*创建当前二叉树的右孩子*/
  603.             if(ret < 0)
  604.                 return -1;
  605.         }
  606.     }
  607.     else; /*树不存在,二叉树的根节点已经赋空,这里什么都不需要做*/
  608.     return 0;
  609. }

  610. /*功能:打印出整颗二叉树(按照先序遍历序列)*/
  611. void PrintBinaryTreeNodeByPre(BinaryThrNodePtr binarythrnodeptr)
  612. {
  613.     if(binarythrnodeptr == NULL)
  614.     {
  615.         return;
  616.     }
  617.     else
  618.     {
  619.         printf("结点名=[%s],结点值=[%s],LTag=[%d],RTag=[%d]\n", binarythrnodeptr->name, binarythrnodeptr->value, binarythrnodeptr->LTag, binarythrnodeptr->RTag);
  620.         PrintBinaryTreeNodeByPre(binarythrnodeptr->leftchild);
  621.         PrintBinaryTreeNodeByPre(binarythrnodeptr->rightchild);
  622.     }
  623. }

  624. /*功能:打印出整颗二叉树(按照中序遍历序列)*/
  625. void PrintBinaryTreeNodeByMid(BinaryThrNodePtr binarythrnodeptr)
  626. {
  627.     if(binarythrnodeptr == NULL)
  628.     {
  629.         return;
  630.     }
  631.     else
  632.     {
  633.         PrintBinaryTreeNodeByMid(binarythrnodeptr->leftchild);
  634.         printf("结点名=[%s],结点值=[%s],LTag=[%d],RTag=[%d]\n", binarythrnodeptr->name, binarythrnodeptr->value, binarythrnodeptr->LTag, binarythrnodeptr->RTag);
  635.         PrintBinaryTreeNodeByMid(binarythrnodeptr->rightchild);
  636.     }
  637. }

  638. /*功能:打印出整颗二叉树(按照后序遍历序列)*/
  639. void PrintBinaryTreeNodeByPos(BinaryThrNodePtr binarythrnodeptr)
  640. {
  641.     if(binarythrnodeptr == NULL)
  642.     {
  643.         return;
  644.     }
  645.     else
  646.     {
  647.         PrintBinaryTreeNodeByPos(binarythrnodeptr->leftchild);
  648.         PrintBinaryTreeNodeByPos(binarythrnodeptr->rightchild);
  649.         printf("结点名=[%s],结点值=[%s],LTag=[%d],RTag=[%d]\n", binarythrnodeptr->name, binarythrnodeptr->value, binarythrnodeptr->LTag, binarythrnodeptr->RTag);
  650.     }
  651. }

  652. /*功能:打印出整颗中序线索化二叉树(按照中序遍历序列,非递归)
  653. 这个还可以仿照下面的改进*/
  654. void PrintBinaryThrTreeNodeByMid(BinaryThrNodePtr threadhead)
  655. {
  656.     BinaryThrNodePtr p = NULL;
  657.     p = threadhead->leftchild; /*p指向根结点*/
  658.     while(p != threadhead) /*p指向threadhead时:表示遍历结束*/
  659.     {
  660.         while(p->LTag == Link) /*结点指针走到最左下结点,就可以访问了*/
  661.         {
  662.             p = p->leftchild;
  663.         }
  664.         printf("结点名=[%s], 结点值=[%s], LTag=[%d], RTag=[%d]\n", p->name, p->value, p->LTag, p->RTag);
  665.         
  666.         while((p->RTag == Thread)&&(p->rightchild != threadhead)) /*有后继结点,就一直向后找*/
  667.         {
  668.             p = p->rightchild; /*指向后继结点,是可以直接访问的*/
  669.             printf("结点名=[%s], 结点值=[%s], LTag=[%d], RTag=[%d]\n", p->name, p->value, p->LTag, p->RTag);
  670.         }
  671.         p = p->rightchild; /*后继找完了,就找右孩子结点*/
  672.     }
  673. }

  674. /*功能:打印出整颗先序线索化二叉树(按照先序遍历序列,非递归)*/
  675. void PrintBinaryThrTreeNodeByPre(BinaryThrNodePtr threadhead)
  676. {
  677.     BinaryThrNodePtr p = NULL;
  678.     p = threadhead->leftchild; /*p指向根结点*/
  679.     while(p != threadhead) /*p指向线索链表头threadhead时:表示遍历结束*/
  680.     {
  681.         while(p->LTag == Link)
  682.         {
  683.             /*p指向的结点:有左子树,就可以访问了*/
  684.             printf("结点名=[%s], 结点值=[%s], LTag=[%d], RTag=[%d]\n", p->name, p->value, p->LTag, p->RTag);
  685.             p = p->leftchild;
  686.         }
  687.         
  688.         while(p->RTag == Thread) /*有后继结点,就一直向后找*/
  689.         {
  690.             /*p指向的结点:有后继结点,是可以直接访问的*/
  691.             printf("结点名=[%s], 结点值=[%s], LTag=[%d], RTag=[%d]\n", p->name, p->value, p->LTag, p->RTag);
  692.             p = p->rightchild;
  693.             if(p == threadhead) /*p指向线索头结点了,就可以跳出循环了*/
  694.             {
  695.                 break;
  696.             }
  697.         }
  698.     }
  699. }

  700. /*功能:打印出整颗后序线索化二叉树(按照后序遍历序列,非递归)*/
  701. void PrintBinaryThrTreeNodeByPos(BinaryThrNodePtr threadhead)
  702. {
  703.     BinaryThrNodePtr p = NULL;
  704.     BinaryThrNodePtr parentptr = NULL;
  705.     p = threadhead->leftchild; /*p指向根结点*/
  706.     
  707.     /*从根开始:一直向左,走到最左下方*/
  708.     while(p->LTag == Link)
  709.     {
  710.         p = p->leftchild; /*p指向第一个被访问的节点*/
  711.     }

  712.     while(p != threadhead)
  713.     {
  714.         printf("结点名=[%s], 结点值=[%s], LTag=[%d], RTag=[%d]\n", p->name, p->value, p->LTag, p->RTag);
  715.         parentptr = GetBinaryThrTreeParent(threadhead, p); /*parentptr是p的双亲*/
  716.         
  717.         if(parentptr == threadhead) /*p是根节点,整颗树就一个结点,没有左右孩子*/
  718.         {
  719.             break;
  720.         }
  721.         
  722.         if(parentptr->RTag == Thread) /*parentptr没有右孩子*/
  723.         {
  724.             p = parentptr; /*根据(后序:,,)p是左孩子,右孩子为空,可以开始遍历根结点了*/
  725.         }
  726.         else if(p == parentptr->rightchild) /*p是parentptr的右孩子*/
  727.         {
  728.             p = parentptr; /*根据(后序:,,)p是右孩子,已访问,可以开始遍历根结点了*/
  729.         }
  730.         else if(p == parentptr->leftchild) /*p是parentptr的左孩子*/
  731.         {
  732.             if(parentptr->RTag == Link) /*parentptr有右孩子*/
  733.             {
  734.                 parentptr = parentptr->rightchild; /*再把这个根的右孩子,当做根结点*/
  735.                 while(parentptr->LTag == Link) /*从根开始:一直向左,走到最左下方*/
  736.                 {
  737.                     parentptr = parentptr->leftchild;
  738.                 }
  739.             }
  740.             p = parentptr;
  741.         }
  742.     }
  743. }

阅读(736) | 评论(0) | 转发(0) |
0

上一篇:Hash表

下一篇:全线索二叉树

给主人留下些什么吧!~~