线索二叉树(及相关算法)

1,016 阅读3分钟

这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战

1.线索二叉树

因为普通的二叉树 不能直接找到当前结点的前驱和后继 就出现了线索二叉树。

  • 二叉树的线索化:若当前结点没有左子树,则将左指针指向前驱结点;若无右子树,则将右指针指向后继结点。
  • 二叉树的存储结构

image.png

相比与普通的二叉树,线索二叉树多了两个标志,ltag,rtag.这两个标志主要用来干啥呢?

当ltag/rtag 为0 表示 该结点有左/右孩子即lchild/rchild指向左/右孩子

当ltag/rtag 为1 表示 该结点无左/右孩子即lchild/rchild指向前驱结点/后继结点

其存储结构:

typedef struct ThreadNode{
  char data;
  struct ThreadNode *lchild,*rchild;
  int ltag,rtag;
}ThreadNode,*ThreadTree;

2. 相关算法

1 中序线索化

//z中序线索化
void InitThread (ThreadTree T,ThreadTree &pre){
  if(p != NULL){
    InitThread(T->lchild,pre);  //1.最先执行的结点时B结点
    if(p->lchild == null){
      p -> lchild = pre;   // 2.此时p的做线索为NULL
      p -> ltag = 1;
    }
    if(pre != NUll && pre->rchild == NULL){  //3.pre目前为NULL 不进入
      pre -> rchild = p;  
      pre -> rtag = 1;
    }
    pre = p; //pre用来记录p的前驱结点 是一个全局变量 //4.此时将Pre指向B结点 
    InitThread(T->rchild,pre);
  }
}

//线索化二叉树
void createThreadTree(ThreadTree T){
  ThreadTree pre = NULL;
  if(T != NULL){
    InitThread(T,pre);
    pre->rchild = NULL;
    pre->rtag = 1;
  }
}

关于中序线索化的算法 如果不好理解可以结合下面这张图(以及我在代码中标注的1~4的序号)来理解 image.png

先序和后续线索化和上面的内容基本一样 只是递归方式的顺序发生了变化

2 找指定二叉树指定次序上的前驱和后继

1. 中序线索二叉树:
  • 查找P的前驱,查ltag为0 则遍历左子树访问其最后一个结点,若ltag为1 则可以直接查找左子树的结点。

  • 查找P的后继结点,查rtag为0,后继则是遍历右子树的第一个结点

中序遍历找前驱

//遍历左子树访问其最后一个结点
ThreadNode *lastNode(ThreadNode *p){
  while(p->rtag == 0){
    //根据中序:左根右 循环找到左子树最右下的结点就为左子树最后一个结点
    p = p->rchild;
  }
  return p;
}

//找前驱
ThreadNode *findPre(ThreadNode *p){
  if(ltag == 0) {
    return lastNode(p->lchild);
  }else{
    return p->lchild;
  }
}

中序遍历找前驱

//遍历左子树访问其最后一个结点
ThreadNode *firstNode(ThreadNode *p){
  while(p->ltag == 0){
    //根据中序:左根右 循环找到右子树最左下的结点就为右子树第一个结点
    p = p->lchild;
  }
  return p;
}

//找前驱
ThreadNode *findPre(ThreadNode *p){
  if(rtag == 0) {
    return firstNode(p->rchild);
  }else{
    return p->rchild;
  }
}
2. 先序线索二叉树:(根左右)

查找P的前驱,查ltag为0,则前驱结点则是结点的双亲结点。 查找P的后继结点,查rtag为0,其后继为:结点左子树存在 则为左子树的根结点,不存在则为右子树的根结点

3. 后续线索二叉树:(左右根)

查找p的前驱,查ltag为0且rtag为0,则p的前驱是右子树的根结点,查ltag为0但rtag为1 则p的前驱是左子树的根结点,

查p的后继

a.若p为根结点 则后继为null;

b. p为右子树的根结点,后继为双亲结点;

c. p为左子树的根结点 若无右兄弟 则后继为双亲,若有右兄弟,则后继则为后续遍历双亲结点右子树时访问的第一个结点。

后续线索二叉树 理解可以结合这张图来理解

image.png