Skip to content

Commit

Permalink
♻️ 为全线索二叉树添加一个逆中序遍历函数,以方便测试前驱线索的正确性
Browse files Browse the repository at this point in the history
  • Loading branch information
kangjianwei committed Apr 8, 2020
1 parent 9b228d2 commit edc75a5
Show file tree
Hide file tree
Showing 11 changed files with 303 additions and 88 deletions.
3 changes: 3 additions & 0 deletions CLion/CourseBook/0604_BiThrTree/BiThrTree-main.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ int main(int argc, char* argv[]) {

printf("█ 中序遍历中序全线索二叉树...\n");
InOrderTraverse_Thr(Thr, PrintElem);

// 逆中序遍历,用来验证前驱线索是否正确
InOrderTraverse_Thr_Inverse(Thr, PrintElem);
}
PressEnterToContinue(debug);
}
96 changes: 75 additions & 21 deletions CLion/CourseBook/0604_BiThrTree/BiThrTree.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ Status InOrderThreading(BiThrTree* Thrt, BiThrTree T) {
* ████████ 算法6.5 ████████
*
* 中序遍历中序全线索二叉树(非递归算法)。
*
* 注:该方法可以验证后继线索是否正确
*/
Status InOrderTraverse_Thr(BiThrTree T, Status(Visit)(TElemType)) {
BiThrTree p = T->lchild; // p指向二叉树根结点(不同于线索二叉树的头结点)
Expand All @@ -113,6 +115,8 @@ Status InOrderTraverse_Thr(BiThrTree T, Status(Visit)(TElemType)) {
p = p->rchild;
}

printf("\n");

return OK;
}

Expand Down Expand Up @@ -150,31 +154,81 @@ static void CreateTree(BiThrTree* T, FILE* fp) {
* 中序全线索化的内部实现
*/
static void InTheading(BiThrTree p) {
if(p) {
InTheading(p->lchild); // 线索化左子树

// 如果当前结点的左子树为空,则需要建立前驱线索
if(!p->lchild) {
p->LTag = Thread;
p->lchild = pre;

// 如果左子树不为空,添加左孩子标记(教材中缺少这一步骤)
} else {
p->LTag = Link;
if(p == NULL) {
return;
}

InTheading(p->lchild); // 线索化左子树

// 如果当前结点的左子树为空,则需要建立前驱线索
if(!p->lchild) {
p->LTag = Thread;
p->lchild = pre;

/*
* 如果左子树不为空,添加左孩子标记。
* 教材中缺少这一步骤,这会导致出现一些幽灵BUG。
* 这里的Link枚举值是零,如果编译器在动态分配内存后恰好把该标记初始化为0,
* 那么效果跟手动设置Link是一样的。但如果编译器没有初始化零值,那么就会出BUG。
*/
} else {
p->LTag = Link;
}

// 如果前驱结点的右子树为空,则为前驱结点建立后继线索
if(!pre->rchild) {
pre->RTag = Thread;
pre->rchild = p;

/*
* 如果右子树不为空,添加右孩子标记。
* 教材中缺少这一步骤,这会导致出现一些幽灵BUG,理由同上。
*/
} else {
pre->RTag = Link;
}

pre = p; // pre向前挪一步

InTheading(p->rchild); // 线索化右子树
}


/*━━━━━━━━━━━━━━━━━━━━━━ 辅助函数 ━━━━━━━━━━━━━━━━━━━━━━*/

/*
* 逆中序遍历中序全线索二叉树(非递归算法)。
*
* 注:该方法可以验证前驱线索是否正确
*/
Status InOrderTraverse_Thr_Inverse(BiThrTree T, Status(Visit)(TElemType)) {
BiThrTree p = T->rchild; // p指向二叉树中序遍历的最后一个结点,这也相当于是T的左子树上中序遍历的最后一个结点

// 空树或遍历结束时,p==T
while(p != T) {
// 访问结点p,该结点是某棵左子树上中序遍历的最后一个结点
if(!Visit(p->data)) {
return ERROR;
}

// 如果前驱结点的右子树为空,则为前驱结点建立后继线索
if(!pre->rchild) {
pre->RTag = Thread;
pre->rchild = p;

// 如果右子树不为空,添加右孩子标记(教材中缺少这一步骤)
} else {
p->RTag = Link;
// 如果存在前驱线索(即没有左子树)
while(p->LTag == Thread && p->lchild != T) {
p = p->lchild; // 将p指向其前驱
Visit(p->data); // 访问前驱结点
}

pre = p; // pre向前挪一步
// 向左前进一步,可能遇到左子树,也可能遇到终点T
p = p->lchild;

InTheading(p->rchild); // 线索化右子树
// 如果没有遇到终点,即存在左子树,则找到该左子树上中序遍历的最后一个结点
if(p != T) {
while(p->RTag == Link) {
p = p->rchild;
}
}
}

printf("\n");

return OK;
}
16 changes: 15 additions & 1 deletion CLion/CourseBook/0604_BiThrTree/BiThrTree.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ typedef struct BiThrNode {
struct BiThrNode* rchild; // 右孩子指针
PointerTag LTag; // 左指针标记
PointerTag RTag; // 右指针标记

struct BiThrNode* parent; // 双亲结点指针,仅在非递归后序遍历后序后继线索二叉树时使用
} BiThrNode;

/* 指向线索二叉树结点的指针 */
Expand Down Expand Up @@ -62,12 +64,14 @@ Status CreateBiTree(BiThrTree* T, char* path);
* 中序遍历二叉树T,并将其全线索化为线索二叉树Thrt。
* 注:这里的线索包括前驱线索与后继线索。
*/
Status InOrderThreading(BiThrTree *Thrt, BiThrTree T);
Status InOrderThreading(BiThrTree* Thrt, BiThrTree T);

/*
* ████████ 算法6.5 ████████
*
* 中序遍历中序全线索二叉树T(非递归算法)。
*
* 注:该方法可以验证后继线索是否正确
*/
Status InOrderTraverse_Thr(BiThrTree T, Status(Visit)(TElemType));

Expand All @@ -84,4 +88,14 @@ static void CreateTree(BiThrTree* T, FILE* fp);
*/
static void InTheading(BiThrTree p);


/*━━━━━━━━━━━━━━━━━━━━━━ 辅助函数 ━━━━━━━━━━━━━━━━━━━━━━*/

/*
* 逆中序遍历中序全线索二叉树(非递归算法)。
*
* 注:该方法可以验证前驱线索是否正确
*/
Status InOrderTraverse_Thr_Inverse(BiThrTree T, Status(Visit)(TElemType));

#endif
3 changes: 3 additions & 0 deletions Dev-C++/CourseBook/0604_BiThrTree/BiThrTree-main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ int main(int argc, char* argv[]) {

printf("█ 中序遍历中序全线索二叉树...\n");
InOrderTraverse_Thr(Thr, PrintElem);

// 逆中序遍历,用来验证前驱线索是否正确
InOrderTraverse_Thr_Inverse(Thr, PrintElem);
}
PressEnterToContinue(debug);
}
Loading

0 comments on commit edc75a5

Please sign in to comment.