1、什么是线索二叉树

  线索化的二叉树就是:在原有的二叉树基础上有些改动,将没有孩子结点的链域声明为线,左孩子指向前驱,右孩子指向后继节点;

有孩子结点的为链,表示指向原先的左右孩子;

线索二叉树的基本存储结构如下:


2、中序二叉树的图形表示


线索二叉树无需遍历,可以很方便的得到其任一结点的前驱、后继。+

3、中序线索二叉树的建立

  必须先建立好二叉树(根据先序序列),在其基础上创建中序线索二叉树;

核心程序:最好画图跟踪一下,才能弄得清楚;

注意:最后一个结点在函数结束时为LINK,没有更改过来!

template
void BinTree::createInThread(BinTreeNode *t, BinTreeNode *&pre){ //创建中序线索二叉树
    if(t == NULL){                        //pre必须引用传递,的保证及时的更改!!!
        return;  //空树直接返回
    }
    createInThread(t->leftChild, pre);  //pre一直为空,一直在往左走;
    if(t->leftChild == NULL){
        t->ltag = THREAD;  //将左孩子设置为线
        t->leftChild = pre;  //因为是第一个,无前驱,所以置空
    }
    if(pre != NULL && pre->rightChild == NULL){ 
        pre->rtag = THREAD;  //将右孩子设置为线;
        pre->rightChild = t;  //此时指向后继结点,t已经回到了上一层
    }
    pre = t;  //将当前结点给pre;
    createInThread(t->rightChild, pre); //往右边递归
}

完整创建程序:

#ifndef _THREAD_BIN_TREE_H_
#define _THREAD_BIN_TREE_H_

#include
using namespace std;

typedef enum{LINK, THREAD}TAG;  //定义枚举标记链和线

template
class BinTree;

template  //结点类,多了两个标记链和线的;
class BinTreeNode{
    friend class BinTree;
public:
    BinTreeNode() : data(Type()), leftChild(NULL), rightChild(NULL), ltag(LINK), rtag(LINK){}
    BinTreeNode(Type value, BinTreeNode *left = NULL, BinTreeNode *right = NULL) :
    data(value), leftChild(left), rightChild(right), ltag(LINK), rtag(LINK){}
    ~BinTreeNode(){}
private:
    Type data;
    BinTreeNode *leftChild;
    BinTreeNode *rightChild;
    TAG            ltag;          //左标记
    TAG            rtag;         //右标记
};
///////////////////////////////////////////////////////////////////////////////
template
class BinTree{
public:
    BinTree() : root(NULL){}
    BinTree(Type ref) : root(NULL), refval(ref){}
    BinTree(const BinTree &t){}
    ~BinTree(){
    }
public:
    void createBinTree(const char *str);  //的先建立二叉树
    void createInThread();
protected :
    void createBinTree(const char *&str, BinTreeNode *&t);
    void createInThread(BinTreeNode *t, BinTreeNode *&pre);
template
void BinTree::createBinTree(const char *str){
    createBinTree(str, root);
}
template
void BinTree::createInThread(){  //在二叉树已经建立起来,创建中序线索二叉树;
    BinTreeNode *pre = NULL;  //得弄一个前驱节点,做为参数传递过去
    createInThread(root, pre);   //真正的创建中序线索二叉树
    pre->rtag = THREAD;  //最后一个应该为线
}
template
void BinTree::createInThread(BinTreeNode *t, BinTreeNode *&pre){ //创建中序线索二叉树
    if(t == NULL){
        return;
    }
    createInThread(t->leftChild, pre);
    if(t->leftChild == NULL){
        t->ltag = THREAD;
        t->leftChild = pre;
    }
    if(pre != NULL && pre->rightChild == NULL){
        pre->rtag = THREAD;
        pre->rightChild = t;
    }
    pre = t;
    createInThread(t->rightChild, pre);
}
template  //创建二叉树
void BinTree::createBinTree(const char *&str, BinTreeNode *&t){
    if(*str == refval){
        t = NULL;
    }else{
        t = new BinTreeNode(*str);
        createBinTree(++str, t->leftChild);
        createBinTree(++str, t->rightChild);
    }
}

#endif

4、其它方法的实现:

  中序线索二叉树

public:
    BinTreeNode* first()const;  //查找中序的第一个结点
    BinTreeNode* last()const;   //查找中序的最后一个结点
    BinTreeNode* prev(BinTreeNode *cur)const; //查找当前结点的前驱
    BinTreeNode* next(BinTreeNode *cur)const; //查找当前结点的后继
    BinTreeNode* parent(BinTreeNode *cur)const; //查找当前结点的父结点
    void inOrder()const;  //中序遍历线索二叉树
    BinTreeNode* find(const Type &key); //查找某一结点

  关于还有些方法: 求树高,求结点个数,这些其实跟前面写的差不多,将结束条件换为if(t->ltag == THREAD) return 0;

  (1)、查找第一个结点

template
BinTreeNode* BinTree::first(BinTreeNode *t)const{
    if(t == NULL){
        return NULL;
    }
    while(t->ltag == LINK){
        t = t->leftChild;
    }
    return t;
}

  (2)、查找最后一个结点

template
BinTreeNode* BinTree::last(BinTreeNode *t)const{
    if(t == NULL){
        return NULL;
    }
    while(t->rtag == LINK){
        t = t->rightChild;
    }

    return t;
}

  (3)、查找当前结点的前驱:

template
BinTreeNode* BinTree::prev(BinTreeNode *t, BinTreeNode *cur)const{
    if(t == NULL || cur == NULL){
        return NULL;
    }
    if(cur->ltag == THREAD){
        return cur->leftChild;
    }else{
        return last(cur->leftChild);  //当前结点的前驱是:左树的最后一个结点;
    }
}

  (4)、查找当前结点的后继

template
BinTreeNode* BinTree::next(BinTreeNode *t, BinTreeNode *cur)const{
    if(t == NULL || cur == NULL){
        return NULL;
    }
    if(cur->rtag == THREAD){
        return cur->rightChild;
    }else{
        return first(cur->rightChild);  //当前结点的后继是:右树的第一个结点;
    }   
}

  (5)、中序遍历线索化二叉树

template
void BinTree::inOrder(BinTreeNode *t)const{
    BinTreeNode *p;

    if(t == NULL){
        return;
    }
    for(p = first(t); p != NULL; p = next(t, p)){
        cout<data<<" ";
    }
    cout< 
  

  (6)、查找某一结点

template
BinTreeNode* BinTree::find(BinTreeNode *t, const Type &key){
    if(t == NULL){
        return NULL;
    }
    if(t->data == key){
        return t;
    }

    BinTreeNode *p;
    for(p = first(t); p != NULL; p = next(t, p)){
        if(p->data == key){
            return p;
        }
    }
    return NULL;
}

  (7) 、查找当前结点的父结点,分析如下:

1、为空,或当前为根结点,其父----->NULL
2、看看根是否为父结点;
3、就是图中E、D这种情况,其父----->后继结点
4、就是图中H、G这种情况,其父----->前驱结点
以上就是针对存在线的求法;
5、针对没有线的求法:(一)、例如求D:看的是其右的最后一个,因为线,走了一圈,就是确定B是其父;
(二)、找当前结点的左树的第一个,在返回其左孩子(此时这个线就是父节点);

template
BinTreeNode* BinTree::parent(BinTreeNode *t, BinTreeNode *cur)const{
    if(t == NULL || cur == NULL || cur == t){
        return NULL;   //父为空
    }
    if(t->ltag == LINK && t->leftChild == cur){  //父为根节点
        return t;
    } 
    if(t->rtag == LINK && t->rightChild == cur){
        return t;
    } 
    
    if(cur->rtag == THREAD && cur->rightChild->leftChild == cur){ //线的找
        return cur->rightChild;
    }
    if(cur->ltag == THREAD && cur->leftChild->rightChild == cur){  //线的找
        return cur->leftChild;
    }

    BinTreeNode *p = last(cur->rightChild);  //往右找最后一个,
    p = p->rightChild;
    if(p != NULL && p->leftChild->rightChild == cur){
        return p->leftChild;
    }
 
    p = first(cur->leftChild);  //换换思路,往左找第一个。
    return p->leftChild;
}


5、完整代码、调试程序,测试结果

  (1)、代码

#ifndef _THREAD_BIN_TREE_H_
#define _THREAD_BIN_TREE_H_

#include
using namespace std;

typedef enum{LINK, THREAD}TAG;

template
class BinTree;

template
class BinTreeNode{
    friend class BinTree;
public:
    BinTreeNode() : data(Type()), leftChild(NULL), rightChild(NULL), ltag(LINK), rtag(LINK){}
    BinTreeNode(Type value, BinTreeNode *left = NULL, BinTreeNode *right = NULL) :
    data(value), leftChild(left), rightChild(right), ltag(LINK), rtag(LINK){}
    ~BinTreeNode(){}
private:
    Type data;
    BinTreeNode *leftChild;
    BinTreeNode *rightChild;
    TAG            ltag;          //左标记
    TAG            rtag;         //右标记
};
///////////////////////////////////////////////////////////////////////////////
template
class BinTree{
public:
    BinTree() : root(NULL){}
    BinTree(Type ref) : root(NULL), refval(ref){}
    BinTree(const BinTree &t){}
    ~BinTree(){
    }
public:
    void createBinTree(const char *str);
    void createInThread();
public:
    BinTreeNode* first()const;
    BinTreeNode* last()const;
    BinTreeNode* prev(BinTreeNode *cur)const;
    BinTreeNode* next(BinTreeNode *cur)const;
    BinTreeNode* parent(BinTreeNode *cur)const;
    void inOrder()const;
    BinTreeNode* find(const Type &key);
protected:
    BinTreeNode* first(BinTreeNode *t)const;
    BinTreeNode* last(BinTreeNode *t)const;
    BinTreeNode* prev(BinTreeNode *t, BinTreeNode *cur)const;
    BinTreeNode* next(BinTreeNode *t, BinTreeNode *cur)const;
    BinTreeNode* parent(BinTreeNode *t, BinTreeNode *cur)const;
    void inOrder(BinTreeNode *t)const;
    BinTreeNode* find(BinTreeNode *t, const Type &key);
protected :
    void createBinTree(const char *&str, BinTreeNode *&t);
    void createInThread(BinTreeNode *t, BinTreeNode *&pre);
private:
    BinTreeNode *root;
    Type               refval;  //'#'
};
template
void BinTree::createBinTree(const char *str){
    createBinTree(str, root);
}
template
void BinTree::createInThread(){
    BinTreeNode *pre = NULL;
    createInThread(root, pre);
    pre->rtag = THREAD;  //最后一个应该为线
}
template
BinTreeNode* BinTree::first()const{
    return first(root);
}
template
BinTreeNode* BinTree::last()const{
    return last(root);
}
template
BinTreeNode* BinTree::prev(BinTreeNode *cur)const{
    return prev(root, cur);
}
template
BinTreeNode* BinTree::next(BinTreeNode *cur)const{
    return next(root, cur);
}
template
BinTreeNode* BinTree::parent(BinTreeNode *cur)const{
    return parent(root, cur);
}
template
void BinTree::inOrder()const{
    inOrder(root);
}
template
BinTreeNode* BinTree::find(const Type &key){
    return find(root, key);
}
//////////////////////////////////////////////////////////////////////////////////////////
template
BinTreeNode* BinTree::find(BinTreeNode *t, const Type &key){
    if(t == NULL){
        return NULL;
    }
    if(t->data == key){
        return t;
    }

    BinTreeNode *p;
    for(p = first(t); p != NULL; p = next(t, p)){
        if(p->data == key){
            return p;
        }
    }
    return NULL;
}
template
void BinTree::inOrder(BinTreeNode *t)const{
    BinTreeNode *p;

    if(t == NULL){
        return;
    }
    for(p = first(t); p != NULL; p = next(t, p)){
        cout<data<<" ";
    }
    cout<
BinTreeNode* BinTree::parent(BinTreeNode *t, BinTreeNode *cur)const{
    if(t == NULL || cur == NULL || cur == t){
        return NULL;
    }
    if(t->ltag == LINK && t->leftChild == cur){
        return t;
    } 
    if(t->rtag == LINK && t->rightChild == cur){
        return t;
    } 
    
    if(cur->rtag == THREAD && cur->rightChild->leftChild == cur){
        return cur->rightChild;
    }
    if(cur->ltag == THREAD && cur->leftChild->rightChild == cur){
        return cur->leftChild;
    }

    BinTreeNode *p = last(cur->rightChild);
    p = p->rightChild;
    if(p != NULL && p->leftChild->rightChild == cur){
        return p->leftChild;
    }

    p = first(cur->leftChild);
    return p->leftChild;
}
template
BinTreeNode* BinTree::next(BinTreeNode *t, BinTreeNode *cur)const{
    if(t == NULL || cur == NULL){
        return NULL;
    }
    if(cur->rtag == THREAD){
        return cur->rightChild;
    }else{
        return first(cur->rightChild);
    }
    
}
template
BinTreeNode* BinTree::prev(BinTreeNode *t, BinTreeNode *cur)const{
    if(t == NULL || cur == NULL){
        return NULL;
    }
    if(cur->ltag == THREAD){
        return cur->leftChild;
    }else{
        return last(cur->leftChild);
    }
}
template
BinTreeNode* BinTree::last(BinTreeNode *t)const{
    if(t == NULL){
        return NULL;
    }
    while(t->rtag == LINK){
        t = t->rightChild;
    }

    return t;
}
template
BinTreeNode* BinTree::first(BinTreeNode *t)const{
    if(t == NULL){
        return NULL;
    }
    while(t->ltag == LINK){
        t = t->leftChild;
    }
    return t;
}
template
void BinTree::createInThread(BinTreeNode *t, BinTreeNode *&pre){
    if(t == NULL){
        return;
    }
    createInThread(t->leftChild, pre);
    if(t->leftChild == NULL){
        t->ltag = THREAD;
        t->leftChild = pre;
    }
    if(pre != NULL && pre->rightChild == NULL){
        pre->rtag = THREAD;
        pre->rightChild = t;
    }
    pre = t;
    createInThread(t->rightChild, pre);

}
template
void BinTree::createBinTree(const char *&str, BinTreeNode *&t){
    if(*str == refval){
        t = NULL;
    }else{
        t = new BinTreeNode(*str);
        createBinTree(++str, t->leftChild);
        createBinTree(++str, t->rightChild);
    }
}

#endif

  (2)、测试代码

#include"threadBinTree.h"

int main(void){
    char *str = "ABC##DE##F##G#H##";
    BinTree bt('#');
    bt.createBinTree(str);
    bt.createInThread();

    bt.inOrder();
    BinTreeNode *k = bt.find('A'); //直接输入字符查找,其方法find(const Type &key)中的const万万不可少
    BinTreeNode *p = bt.first();  //C
    printf("%p\n", k);  //A
    BinTreeNode *m;
    m = bt.parent(p);   
//    printf("%p\n", m);  //B
    BinTreeNode *n;
    n = bt.parent(m);
    printf("%p\n", n);  //A
    return 0;
}

  (3)、测试结果

线索二叉树_第1张图片