1. 线索化代码
线索化需要先序/中序/后续遍历的过程,多了访问到节点时指针指向的问题
二叉树形状和运行结果
主函数
#include "func.h"
// 二叉树线索化(便于找前驱和后继节点)
// 1. 二叉树先序线索化
// 2. 二叉树中序线索化
// 3. 二叉树后序线索化
// 中序线索化
// 需要有一个前驱节点指针
// 1. 进行中序序遍历,当访问到某节点时,进行判断:
// (1) 如果左子树为空,则让左孩子指向pre
// (2) 如果pre的右子树为空,则让右孩子指向当前访问的节点
// 2. 让pre指向当前节点,进入下一次遍历
BiNode *pre = NULL; // 全局变量
void InThread(BiTree &tree){
if (tree!=NULL){
InThread(tree->left);
if(tree->left == NULL){
tree->ltag = 1;
tree->left = pre;
if (pre==NULL) printf("\n%c.pre --> NULL\n",tree->data.value);
else printf("%c.pre---> %c\n",tree->data.value,pre->data.value);
}
if(pre != NULL && pre->right == NULL){
pre->right = tree;
pre->rtag = 1;
printf("%c.post---> %c\n",pre->data.value,tree->data.value);
}
pre = tree;
InThread(tree->right);
}
}
// 先序线索化
// 需要注意的是,当把节点左孩子链接为该节点前驱,那么再使用tree->left访问左孩子就造成访问错误,需要额外加ltag判断
void PreThread(BiTree &tree){
if(tree!=NULL){
if(tree->left == NULL){
tree->left = pre;
tree->ltag = 1;
printf("%c.pre---> %c\n",tree->data.value,pre->data.value);
}
if(pre!=NULL && pre->right == NULL){
tree->right = pre;
tree->rtag = 1;
printf("%c.post---> %c\n",pre->data.value,tree->data.value);
}
pre = tree;
if (tree->ltag == 0) PreThread(tree->left);
PreThread(tree->right);
}
}
void PostThread(BiTree &tree){
if(tree!=NULL){
PostThread(tree->left);
PostThread(tree->right);
if(tree->left == NULL){
tree->left = pre;
tree->ltag = 1;
if (pre==NULL) printf("\n%c.pre --> NULL\n",tree->data.value);
else printf("%c.pre---> %c\n",tree->data.value,pre->data.value);
}
if(pre!=NULL && pre->right == NULL){
tree->right = pre;
tree->rtag = 1;
printf("%c.post---> %c\n",pre->data.value,tree->data.value);
}
pre = tree;
}
}
// Demo:
// A
// B C
// D E NULL F
// 中序遍历:DBEACF
// 线索化: D.pre->NULL; D.post=B; E.pre->B; E.post->A; C.pre->A; F.pre->C
// 先序遍历: ABDECF
// 线索化: D.pre->B; E->pre=D; D->post=E; C->pre=E; C->post=C
int main() {
printf("---------------------\n");
BiTree tree;
getDemo(tree);
InOrder(tree);
InThread(tree);
pre=NULL;
printf("---------------------\n");
BiTree tree2;
getDemo(tree2);
PreOrder(tree2);
printf("\n");
PreThread(tree2);
printf("---------------------\n");
pre = NULL;
BiTree tree3;
getDemo(tree3);
PostOrder(tree3);
PostThread(tree3);
return 0;
}
头文件和其它源文件
#include "func.h"
void init(BiTree &tree){
tree = (BiNode*) malloc(sizeof(BiNode));
tree->left = NULL;
tree->right = NULL;
tree->ltag = tree->rtag = 0;
}
BiNode* create_node(Element elem){
BiNode *p_node = (BiNode*) malloc(sizeof(BiNode));
p_node->data = elem;
p_node->left = p_node->right = NULL;
p_node->ltag = p_node->rtag = 0;
return p_node;
}
BiTree getDemo(BiTree &tree){
// Demo:
// A
// B C
// D E NULL F
//
init(tree);
Element A,B,C,D,E,F;
A.value = 'A';
B.value = 'B';
C.value = 'C';
D.value = 'D';
E.value = 'E';
F.value = 'F';
BiNode *pb = create_node(B);
BiNode *pc = create_node(C);
BiNode *pd = create_node(D);
BiNode *pe = create_node(E);
BiNode *pf = create_node(F);
tree->data = A;
tree->left = pb;
tree->right = pc;
pb -> left = pd;
pb->right = pe;
pc->right = pf;
}
void visit(BiNode *node){
printf("%c\t",node->data);
}
void PreOrder(BiTree tree){
if (tree != NULL){
visit(tree);
PreOrder(tree->left);
PreOrder(tree->right);
}
}
void InOrder(BiTree tree){
if (tree != NULL){
InOrder(tree->left);
visit(tree);
InOrder(tree->right);
}
}
void PostOrder(BiTree tree){
if (tree != NULL){
PostOrder(tree->left);
PostOrder(tree->right);
visit(tree);
}
}
//
// Created by 64516 on 2023/1/25.
//
#ifndef ORDER_01_FUNC_H
#define ORDER_01_FUNC_H
#include <stdio.h>
#include <stdlib.h>
typedef struct Element{
char value;
};
typedef struct BiNode{
Element data;
BiNode *left,*right; // 可以将节点左右指针初始化为NULL吗?
bool ltag,rtag;
}BiNode,*BiTree;
BiTree getDemo(BiTree &tree);
void visit(BiNode *node);
void PreOrder(BiTree tree);
void InOrder(BiTree tree);
void PostOrder(BiTree tree);
#endif //ORDER_01_FUNC_H
2. 在二叉树线索化后找节点前驱/后继
中序线索二叉树
中序线索二叉树找中序前驱
如果ltag=0,则子树有左孩子,前驱为左子树最右的节点
中序线索二叉树找中序后继
如果rtag=0,则节点有右孩子,后继为子树最左的节点
先序线索二叉树
先序线索二叉树找先序前驱
若ltag=1可以直接找到,若ltag=0,节点有左孩子,该节点在向下子树是第一个被访问的节点,无法找到该节点的前驱,除非该二叉树为三叉链表可以链接到父节点
先序线索二叉树找先序后继
若rtag=0则有右孩子,此时节点有左孩子则左孩子为后继,没有左孩子则右孩子为后继
后序线索二叉树
后续线索二叉树找后续前驱
若ltag=0则有左孩子,此时没有右孩子则左孩子为前驱,有右孩子则右孩子为前驱
后续线索二叉树找后续后继
若rtag=1可以直接找到,若rtag=0则节点有右孩子,该节点在向下子树内是最后访问的,无法找到该节点的后继,除非该二叉树为三叉链表。
三叉链表时的补充: