1. 递归线索化二叉树算法分析
采用递归线索化二叉树非常的方便简单,与三序(先、中、后)遍历二叉树的算法颇为相似。只是在遍历二叉树的过程中,如果有节点的左子树为空那么将左标记改为线索,左孩子指针指向前驱(若是第一个节点就置为空),如果节点右子树为空那么将右标记改为线索,右孩子指针指向其后继(若为遍历的最后一个节点那么指向另设的头节点)。
2. 非递归线索化二叉树算法分析
递归算法的思路以及实现在大多数情况下比非递归更直接、容易理解(自己的理解)。所以非递归算法就需要有一个函数每次返回遍历过程中的一个结点指针(遍历算法可以借鉴我之前发的博客,传送门:二叉树递归-非递归三序遍历),在记录下前一个指针pre的前提下根据返回节点的子树情况线索化二叉树。
3. 二叉树线索化的应用
要注意到在线索化的同时我们要形成一条线索链表串联起整个二叉树(不同的遍历方式会得到不同的线索链表),一般我们附设一个头节点head,使其左指针指向二叉树根,使其右指针指向遍历的最后一个节点。那么我们再想要遍历二叉树就不需要再经过复杂的遍历而只需要顺序打印线索链表即可。所以在我们需要频繁遍历二叉树时将此二叉树线索化将会是更好的选择。(根据得到的线索链表打印出遍历序列的具体过程将在下一篇博客写出)
4. 代码
下面贴出线索化的代码(非递归版的,emm,,只写了中序线索化的非递归版,因为没有含量。而递归呢也算是对思维的考察),废话不多说,看代码:
#include<iostream>
#include<windows.h>
using namespace std;
//-----------------------二叉树的二叉线索存储结构------------------------//
typedef enum {
pointer, //指针
thread //线索
} ptrtype;
typedef struct BTree {
int val;
struct BTree *lchild, *rchild;
ptrtype Ltag, Rtag; //左右标志
} BTree, *pBTree;
//-----------------------中序-非递归的二叉树线索化------------------------//
int MidOrderThreading(pBTree &root, pBTree &head) //成功返回0,失败返回-1
{
if (!(head = new BTree)) return -1;
head->Ltag = pointer;head->Rtag = thread;
if (!root) head->lchild = root; //空树
else { //非空树
pBTree pre = nullptr, p; //pre->前驱,p->当前节点
do {
p = MidOrder(root); //每次按中序遍历顺序返回一个节点指针
if (p->lchild && p->rchild) {
pre->Rtag = thread;
pre->rchild = p;
}
if (!p->lchild) {
p->Ltag = thread;
p->lchild = pre;
if (pre && !pre->rchild) {
pre->Ltag = thread;
pre->rchild = p;
}
}
pre = p;
}while(p); //遍历完成返回空指针
pre->rchild = head;
pre->Rtag = thread;
head->rchild = pre; //头节点左指针指向二叉树根节点,右指针指向中序最后一个节点
}
return 0; //线索化完成
}
//-----------------------中序-递归版二叉树线索化------------------------//
pBTree pre = nullptr; //全局前驱指针,方便一点
void MidThreading(pBTree p);
int _MidOrderThreading(pBTree &root, pBTree &head)
{
pre = nullptr;
if (!(head = new BTree)) return -1;
head->Ltag = pointer;head->Rtag = thread;
if (!root) head->lchild = root; //空树
else {
head->lchild = root;
MidThreading(root);
head->rchild = pre;
pre->Rtag = thread;
pre->rchild = head;
}
return 0; //线序化成功
}
void MidThreading(pBTree p) //中序递归部分
{
if (p) {
MidThreading(p->lchild);
if (!p->lchild) {
p->Ltag = thread;
p->lchild = pre;
}
if (pre && !pre->rchild) {
pre->Rtag = thread;
pre->rchild = p;
}
pre = p;
MidThreading(p->rchild);
}
}
//-----------------------先序-递归的二叉树线索化------------------------//
void PreThreading(pBTree);
int PreOrderThreading(pBTree &root, pBTree &head)
{
pre = nullptr;
if (!(head = new BTree)) return -1;
head->Ltag = pointer; head->Rtag = thread;
head->rchild = head;
if (!root) head->lchild = head;
else {
PreThreading(root);
pre->Rtag = thread;
pre->rchild = head;
head->rchild = pre;
}
return 0;
}
void PreThreading(pBTree p) //先序递归部分
{
if (p) {
if (!p->lchild) {
p->Ltag = thread;
p->lchild = pre;
}
if (pre && !pre->rchild) {
pre->Rtag = thread;
pre->rchild = p;
}
pre = p;
PreThreading(p->lchild);
PreThreading(p->rchild);
}
}
//-----------------------后序-递归的二叉树线索化------------------------//
void BehThreading(pBTree);
int BehOrderThreading(pBTree root, pBTree head)
{
pre = nullptr;
if (!(head = new BTree)) return -1;
head->Ltag = pointer; head->Rtag = thread;
head->rchild = head; //回指
if (!root) head->lchild = head;
else {
head->lchild = root;
BehThreading(root);
head->rchild = pre; //连接根节点
}
}
void BehThreading(pBTree p) //递归部分
{
if (p) {
BehThreading(p->lchild);
BehThreading(p->rchild);
if (!p->lchild) {
p->Ltag = thread;
p->lchild = pre;
}
if (pre && !pre->rchild) {
pre->Rtag = thread;
pre->rchild = p;
}
pre = p; //最终指向根节点
}
}
int main()
{
pBTree root,
head; //二叉线索链表头节点指针
/*
// 建立二叉树的过程省略,返回root为根节点指针
*/
MidOrderThreading(root, head); //非递归---中序
_MidOrderThreading(root, head); //递归---中序
PreOrderThreading(root, head); //递归---前序
BehOrderThreading(root, head); //递归---后序
system("pause");
return 0;
}
5. ending
下一篇博客会写根据线索链表打印二叉树的具体实现代码,敬请期待!!
(前几天过年回家了,进度耽搁了抱歉!疫情这么严重我就不该东走西走哈哈哈)