1. 程式人生 > 實用技巧 >線索二叉樹(找前驅/後繼)

線索二叉樹(找前驅/後繼)

線索二叉樹(找前驅/後繼)

建立線索的初衷就是為了在一個結點中能夠更方便找到前驅結點和後繼結點。

  1. 中序線索二叉樹
  2. 先序線索二叉樹
  3. 後序線索二叉樹

中序線索二叉樹找中序後繼

//找到以p為跟的子樹中,第一個被中序遍歷的結點
ThreadNode *Firstnode(ThreadNode *p){
    //迴圈找到最左下角結點(不一定是葉子結點)
    while(p->ltag==0) p=p->lchild;
    return p;
}

//在中序線索二叉樹中找到結點p的後繼結點
ThreadNode *Nextnode(ThreadNode *p){
    //右子樹中最左下結點
    if(p->rtag==0) return Firstnode(p->rchild);
    else return p->rchild;  //rtag==1 直接返回後繼線索
}

//對中序線索二叉樹進行中序遍歷,(利用線索實現的非遞迴演算法)
void Inorder(ThreadNode *T){
    for(ThreadNode *p=Firstnode(T);p!=NULL;p=Nextnode(p))
        visit(p);
}

空間複雜度

\[O(1) \]

中序線索二叉樹找中序前驅

在中序線索二叉樹中找到指定結點*p的中序前驅pre

  1. 若p->ltag==1(被線索化了),則 pre=p->lchild(直接就是前驅)
  2. 若p->ltag==0(沒有被線索化), 必定是有左孩子的。

//找到以p為根的子樹中,最後一個被中序遍歷的結點
ThreadNode *Lastnode(ThreadNode *p){
    //迴圈找到最右下的結點(不一定是葉子結點)
    while(p->rtag == 0) p=p-rchild;
    return p;
}

//在中序線索二叉樹中找到結點p的前驅結點
ThreadNode *Prenode(ThreadNode *p){
    //左子樹中最右下的結點
    if(p->ltag=0) return Lastnode(p->lchild);
    else return p->lchild;//ltag==1 直接返回前驅線索
}

//對中序線索二叉樹進行逆向中序遍歷
void RevInorder(ThreadNode *p){
    for(ThreadNode *p=Lastnode(T);p!=NULL;p=Prenode(p))
        visit(p);
}

先序線索二叉樹找先序後繼

在先序線索二叉樹中找到指定結點*p的先序後繼next

  1. 若p->rtag==1(被線索化了),則 next=p->rchild(直接就是前驅)
  2. 若p->rtag==0(沒有被線索化), 必定是有右孩子的。

ThreadNode *find(ThreadNode *p){
    if(p->lchild != NULL){
        return p->lchild;
    }else if(p->rchlid == NULL){
        return p->rchild;
    }else{
        return null;
    }
}

先序線索二叉樹找先序前驅

在先序線索二叉樹中找到指定結點*p的先序前驅pre

  1. 若p->ltag==1(被線索化了),則 pre=p->lchild(直接就是前驅)
  2. 若p->ltag==0(沒有被線索化), 必定是有左孩子的。

先序遍歷中,左右子樹中的結點只可能是根節點的後繼,不可能是前驅

  1. 如果能找到p的父節點,且p是左孩子
  2. 如果能找到p的父節點,且p是右孩子,其左兄弟為空
  3. 如果能找到p的父節點,且p是右孩子,其左兄弟非空
  4. 如果p是根節點,則p沒有先序前驅

先一直往右邊走,如果沒得走了,在往左邊走

後序線索二叉樹找後序前驅

在後序線索二叉樹中找到指定結點*p的後續前驅pre

  1. 若p->ltag==1,則pre=p->lchild
  2. 若p->ltag==0,必有左孩子

後序線索二叉樹找後序後繼

使用三叉連結串列來實現