線索二叉樹(找前驅/后繼)
建立線索的初衷就是為了在一個結點中能夠更方便找到前驅結點和后繼結點。
- 中序線索二叉樹
- 先序線索二叉樹
- 后序線索二叉樹
中序線索二叉樹找中序后繼
//找到以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
- 若p->ltag==1(被線索化了),則 pre=p->lchild(直接就是前驅)
- 若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
- 若p->rtag==1(被線索化了),則 next=p->rchild(直接就是前驅)
- 若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
- 若p->ltag==1(被線索化了),則 pre=p->lchild(直接就是前驅)
- 若p->ltag==0(沒有被線索化), 必定是有左孩子的。
先序遍歷中,左右子樹中的結點只可能是根節點的后繼,不可能是前驅
- 如果能找到p的父節點,且p是左孩子
- 如果能找到p的父節點,且p是右孩子,其左兄弟為空
- 如果能找到p的父節點,且p是右孩子,其左兄弟非空
- 如果p是根節點,則p沒有先序前驅
先一直往右邊走,如果沒得走了,在往左邊走
后序線索二叉樹找后序前驅
在后序線索二叉樹中找到指定結點*p的后續前驅pre
- 若p->ltag==1,則pre=p->lchild
- 若p->ltag==0,必有左孩子
后序線索二叉樹找后序后繼
使用三叉鏈表來實現