【线索二叉树】C++代码及线索化过程详解

简介: 【线索二叉树】C++代码及线索化过程详解


我在这里不仅写了线索二叉树的普通代码,在代码中我还加入了线索化过程的打印,更好的帮助理解!

线索二叉树的概念

传统的二叉树存在很多空指针能否利用这些空指针来存放指向其前驱或后继的指针?这样就可以像遍历单链表那样方便地遍历二叉树。引入线索二叉树正是为了加快查找结点前驱和后继的速度。
若无左子树,令lchild指向其前驱结点;若无右子树,令rchild指向其后继结点。如图所示,还需增加两个标志域标识指针域是指向左(右)孩子还是指向前驱(后继)。 这就是线索二叉树



中序线索二叉树的构造

二叉树的线索化是将二叉链表中的空指针改为指向前驱或后继的线索。而前驱或后继的信息只有在遍历时才能得到,因此线索化的实质就是遍历一次二叉树
以中序线索二叉树的建立为例。附设指针 pre 指向刚刚访问过的结点,指针p 指向正在访问的结点,即pre指向p 的前驱。在中序遍历的过程中,检查p的左指针是否为空,若为空就将它指向pre;检查pre的右指针是否为空,若为空就将它指向p,如图所示。



中序线索二叉树的遍历

中序线索二叉树的结点中隐含了线索二叉树的前驱和后继信息。在对其进行遍历时,只要先找到序列中的第一个结点,然后依次找结点的后继,直至其后继为空在中序线索二叉树中找结点后继的规律是:若其右标志为“1”,则右链为线索,指示其后继,否则遍历右子树中第一个访问的结点(右子树中最左下的结点)为其后继


过程详解版代码

程序运行部分结果

代码

#include<iostream>
#include<cstdio>
#include<stdlib.h>
using namespace std;
#define OK 1
#define ERROR 0
#define OVERFLOW -1
#define TElemType char
#define Status int
/*二叉树的二叉线索表示*/
typedef enum {Link, Thread} PointerTag; //子树不为空时,Link==0 表示指针;子树为空时,Thread==1表示线索
typedef struct BiThrNode{
  TElemType data;
  struct BiThrNode *lchild, *rchild;  //左右孩子 
  PointerTag LTag, RTag;        //左右标志 
}BiThrNode, *BiThrTree; 
int cnt = 0;
/*按照先序序列建立一棵线索二叉树*/
Status CreatBiThrTree(BiThrTree &T){
  //按照先序序列输入二叉树中结点的值(一个字符),#表示空树
  char ch;
  cin >> ch;
  if(ch == '#') T = NULL;
  else{
    if(!(T = (BiThrNode*)malloc(sizeof(BiThrTree)))) exit(OVERFLOW);
    T->data = ch;       //生成根节点 
    T->LTag = Link;
    T->RTag = Link;
    CreatBiThrTree(T->lchild);  //构造左子树 
    CreatBiThrTree(T->rchild);  //构造右子树 
  }
  return OK; 
}//CreatBiThrTree
/*中序线索化*/
void Visualize(BiThrTree p, BiThrTree pre){
  //线索化的可视化输出
  cout << "p指向的结点:";
  if(p != NULL) cout << p->data << '\t';
  else cout << "NULL\t";
  cout <<  "pre指向的结点:";
  if(pre != NULL) cout << pre->data << endl;
  else cout << "NULL" << endl; 
}
Status InThread(BiThrTree &p, BiThrTree &pre){
  Visualize(p, pre);
  if(p != NULL){
    cout << "------------------------------------>线索化" << p->data << "的左子树" << endl; 
    InThread(p->lchild, pre); //递归,线索化左子树
    cout << "------------------------------------>" << p->data << "的左子树线索化完成" << '\t';
    if(p->lchild == NULL){    //如果左子树为空,建立前驱线索
      cout << p->data << "的前驱节点指向pre指向的结点" << endl; 
      p->lchild = pre;
      p->LTag = Thread;   
    }
    if(pre != NULL && pre->rchild == NULL){
      cout << pre->data << "的后继结点指向" << p->data << endl;
      pre->rchild = p;    //如果此时的前驱结点的右子树为空,建立后继线索 
      pre->RTag = Thread;
    }
    cout << "pre指向p所指向的结点" << endl;
    pre = p;          //pre后移
    cout << "------------------------------------>线索化" << p->data << "的右子树" << endl; 
    InThread(p->rchild, pre); //递归,线索化右子树 
    cout << "------------------------------------>" << p->data << "的右子树线索化完成" << endl;
    cout << ++cnt << "次线索化之后:"; 
    Visualize(p, pre);
    cout << endl << endl; 
  }//else if(p == NULL) return ERROR;//空树返回错误 
  return OK;
}//InThread
Status CreatInThread(BiThrTree &T){
  BiThrTree pre = NULL; //因为第一个结点一开始无前驱
  if(T != NULL){
    InThread(T, pre); //线索化二叉树
    pre->rchild = NULL; //处理到了最后一个结点,pre指向最后一个结点,右孩子设为空表示最后一个结点 
    pre->RTag = Thread; //表示指针 
  }
  return OK;
}//CreatInThread
/*打印结点*/
void visit(BiThrNode *p){
  cout << p->data;
}
/*中序递归遍历*/
void InOrder(BiThrTree T){
  if(T != NULL){
    InOrder(T->lchild);
    visit(T);
    InOrder(T->rchild);
  }
}
/*中序线索二叉树的遍历*/
BiThrNode *FirstNode(BiThrNode *p){
  //求中序线索二叉树中中序序列下的第一个结点
  while(p->LTag != Thread) p = p->lchild; //找到最左下方的结点(中序的第一个结点)
  return p; 
}
BiThrNode *NextNode(BiThrNode *p){
  //求中序线索二叉树中结点p在中序序列的后继结点
  if(p->RTag == Link) 
    return FirstNode(p->rchild);    //如果有右子树,继续递归向下找 
  else return p->rchild;          //RTag==1,直接返回线索 
}
void InThreadOrder(BiThrTree T){
  //不含头结点的中序线索二叉树的中序遍历算法 
  for(BiThrNode *p = FirstNode(T); p != NULL; p = NextNode(p))
    visit(p);
}
/*主函数*/
int main(){
  cout << "---------------这是一个线索二叉树程序!---------------" << endl;
  cout << "-------------首先按照先序序列建立一棵线索二叉树-------" << endl << endl;
  cout << "按照先序序列输入二叉树中结点的值(一个字符),#表示空树" << endl; 
  BiThrTree T;
  CreatBiThrTree(T);
  cout << "二叉树的递归中序遍历:"; 
  InOrder(T);
//  if(s == 1) 
  cout << endl << endl << "-------------下面进行中序线索化-------------" << endl;
  cout << "--------------打印线索化的过程--------------" << endl;
  if(CreatInThread(T) == 1) cout << "--------------已完成线索化--------------" << endl;
  cout << "中序线索二叉树的非递归遍历序列:";
  InThreadOrder(T);
  return 0;
}
//测试示例:abc##de#g##f###

纯享版代码

#include<iostream>
#include<cstdio>
#include<stdlib.h>
using namespace std;
#define OK 1
#define ERROR 0
#define OVERFLOW -1
#define TElemType char
#define Status int
/*二叉树的二叉线索表示*/
typedef enum {Link, Thread} PointerTag; //子树不为空时,Link==0 表示指针;子树为空时,Thread==1表示线索
typedef struct BiThrNode{
  TElemType data;
  struct BiThrNode *lchild, *rchild;  //左右孩子 
  PointerTag LTag, RTag;        //左右标志 
}BiThrNode, *BiThrTree; 
/*按照先序序列建立一棵线索二叉树*/
Status CreatBiThrTree(BiThrTree &T){
  //按照先序序列输入二叉树中结点的值(一个字符),#表示空树
  char ch;
  cin >> ch;
  if(ch == '#') T = NULL;
  else{
    if(!(T = (BiThrNode*)malloc(sizeof(BiThrTree)))) exit(OVERFLOW);
    T->data = ch;       //生成根节点 
    T->LTag = Link;       //这里一定要加上,不然后边会出错 
    T->RTag = Link;
    CreatBiThrTree(T->lchild);  //构造左子树 
    CreatBiThrTree(T->rchild);  //构造右子树 
  }
  return OK; 
}//CreatBiThrTree
/*中序线索化*/
Status InThread(BiThrTree &p, BiThrTree &pre){
  if(p != NULL){
    InThread(p->lchild, pre); //递归,线索化左子树
    if(p->lchild == NULL){    //如果左子树为空,建立前驱线索
      p->lchild = pre;
      p->LTag = Thread;   
    }
    if(pre != NULL && pre->rchild == NULL){
      pre->rchild = p;    //如果此时的前驱结点的右子树为空,建立后继线索 
      pre->RTag = Thread;
    }
    pre = p;          //pre后移
    InThread(p->rchild, pre); //递归,线索化右子树 
  }//else if(p == NULL) return ERROR;//空树返回错误 
  return OK;
}//InThread
Status CreatInThread(BiThrTree &T){
  BiThrTree pre = NULL; //因为第一个结点一开始无前驱
  if(T != NULL){
    InThread(T, pre); //线索化二叉树
    pre->rchild = NULL; //处理到了最后一个结点,pre指向最后一个结点,右孩子设为空表示最后一个结点 
    pre->RTag = Thread;     //表示指针 
  }
  return OK;
}//CreatInThread
/*打印结点*/
void visit(BiThrNode *p){
  cout << p->data;
}
/*中序递归遍历*/
void InOrder(BiThrTree T){
  if(T != NULL){
    InOrder(T->lchild);
    visit(T);
    InOrder(T->rchild);
  }
}
/*中序线索二叉树的遍历*/
BiThrNode *FirstNode(BiThrNode *p){
  //求中序线索二叉树中中序序列下的第一个结点
  while(p->LTag != Thread) p = p->lchild; //找到最左下方的结点(中序的第一个结点)
  return p; 
}
BiThrNode *NextNode(BiThrNode *p){
  //求中序线索二叉树中结点p在中序序列的后继结点
  if(p->RTag == Link) 
    return FirstNode(p->rchild);        //如果有右子树,继续递归向下找 
  else return p->rchild;          //RTag==1,直接返回线索 
}
void InThreadOrder(BiThrTree T){
  //不含头结点的中序线索二叉树的中序遍历算法 
  for(BiThrNode *p = FirstNode(T); p != NULL; p = NextNode(p))
    visit(p);
}
/*主函数*/
int main(){
  BiThrTree T;
  CreatBiThrTree(T);
//  InOrder(T); 
  CreatInThread(T);
  cout << "遍历序列:"; 
  InThreadOrder(T); 
  return 0;
}
//abc##de#g##f###
相关文章
|
7天前
|
C语言 C++ 开发者
深入探索C++:特性、代码实践及流程图解析
深入探索C++:特性、代码实践及流程图解析
|
1月前
|
IDE Java Linux
【CMake】CMake构建C++代码(一)
【CMake】CMake构建C++代码(一)
|
1月前
|
C++ 计算机视觉 Windows
【C++】由于找不到xxx.dll,无法继续执行代码,重新安装程序可能会解决此问题。(解决办法)
【C++】由于找不到xxx.dll,无法继续执行代码,重新安装程序可能会解决此问题。(解决办法)
|
1天前
|
C++
【C++】一文深入浅出带你参透库中的几种 [ 智能指针 ]及其背后实现原理(代码&图示)
【C++】一文深入浅出带你参透库中的几种 [ 智能指针 ]及其背后实现原理(代码&图示)
|
1天前
|
C++ 数据格式
【C++】C++中的【文件IO流】使用指南 [手把手代码演示] & [小白秒懂]
【C++】C++中的【文件IO流】使用指南 [手把手代码演示] & [小白秒懂]
【C++】C++中的【文件IO流】使用指南 [手把手代码演示] & [小白秒懂]
|
1天前
|
编译器 C++
【C++】【C++的常变量取地址问题(对比C的不同)】const修饰的常变量&volatile修饰用法详解(代码演示)
【C++】【C++的常变量取地址问题(对比C的不同)】const修饰的常变量&volatile修饰用法详解(代码演示)
|
2天前
|
C++
【期末不挂科-C++考前速过系列P6】大二C++实验作业-模板(4道代码题)【解析,注释】
【期末不挂科-C++考前速过系列P6】大二C++实验作业-模板(4道代码题)【解析,注释】
【期末不挂科-C++考前速过系列P6】大二C++实验作业-模板(4道代码题)【解析,注释】
|
2天前
|
Serverless C++ 容器
【期末不挂科-C++考前速过系列P5】大二C++实验作业-多态性(3道代码题)【解析,注释】
【期末不挂科-C++考前速过系列P5】大二C++实验作业-多态性(3道代码题)【解析,注释】
|
2天前
|
C++ 芯片
【期末不挂科-C++考前速过系列P4】大二C++实验作业-继承和派生(3道代码题)【解析,注释】
【期末不挂科-C++考前速过系列P4】大二C++实验作业-继承和派生(3道代码题)【解析,注释】
|
2天前
|
编译器 C++
【期末不挂科-C++考前速过系列P3】大二C++第3次过程考核(20道选择题&12道判断题&2道代码题)【解析,注释】
【期末不挂科-C++考前速过系列P3】大二C++第3次过程考核(20道选择题&12道判断题&2道代码题)【解析,注释】