为什么使用线索二叉树
浪费了10*4个字节
使用中序遍历 H D I B E A F C G 可以利用“^”记录该结点的前去后继,节省指针浪费的空间。
如果是这种情况
需要将定义好的结构进行扩容
lchild , ltag , data, rtag, rchild
ltag为0 指向该结点的左孩子,为1时指向该结点的前驱
rtag为0 指向该结点的右孩子,为1时指向该结点的后继
线索二叉树的实现
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> typedef char ElemType; //线索存储标志位 //Link(0):表示指向左右孩子的指针 //Thread(1):表示指向前驱后继的线索 typedef enum {Link,Thread}PointerTag; typedef struct BiThrNode { char data; struct BiThrNode *lchild,*rchild; PointerTag ltag; PointerTag rtag; }BiThrNode,*BiThrTree; //全局变量,始终指向刚刚访问过的结点 BiThrTree pre; //创建一棵二叉树,约定用户遵照前序遍历的方式输入数据 CreateBiThrTree(BiThrTree *T) { char c; scanf("%c", &c); if (' ' == c) { *T = NULL; } else { *T = (BiThrNode*)malloc(sizeof(BiThrNode)); (*T)->data = c; (*T)->ltag = Link; (*T)->rtag = Link; CreateBiThrTree(&(*T)->lchild); CreateBiThrTree(&(*T)->rchild); } } //中序遍历线索化 InThreading(BiThrTree T) { if (T) { InThreading(T->lchild);//递归左孩子线索化 //结点处理 if (!T->lchild) //如果该结点没有左孩子,设置ltag为thread,并把lchild指向刚刚访问的结点 { T->ltag = Thread; T->lchild = pre; } if (!pre->rchild)//如果上一个的右节点为空,没孩子 { pre->rtag = Thread; //设置上一个节点rtag为线索 pre->rchild = T; } pre = T; InThreading(T->rchild);//递归右孩子线索化 } } // void InOrderThreading(BiThrTree *p,BiThrTree T) { *p = malloc(sizeof(BiThrNode));//头指针 (*p)->ltag = Link; (*p)->rtag = Thread; (*p)->rchild = *p; if (!T) { (*p)->lchild = *p; } else { (*p)->lchild = T; pre = *p; InThreading(T); pre->rchild = *p; pre->rtag = Thread; (*p)->rchild = pre; } } void visit(char c) { printf("%c", c); } //中序遍历二叉树,非递归 void InOrderTraverse(BiThrTree T) { BiThrTree p; p = T->lchild; while (p!=T)//p=T,头指针等于根节点 空树或者遍历到结束 { while (p->ltag == Link)//有左子树 { p = p->lchild;//找到最左节点 } visit(p->data); while (p->rtag == Thread &&p->rchild != T)//有右子树,并且右节点不指向头 { p = p->rchild;//说明有后继 visit(p->data); } p = p->rchild; } } int main() { BiThrTree P, T=NULL; CreateBiThrTree(&T); InOrderThreading(&P,T); printf("中序遍历输出结果为:"); printf("\n"); InOrderTraverse(P); printf("\n"); }