线索二叉树:(threaded binary tree):n个结点的二叉链表中含有n+1(2n-(n-1)=n+1)个空指针域。利用二叉链表中的空指针域,存放指向结点在某种遍历次序下的前驱和后继结点的指针
【注】已知二叉树的节点个数n,那么边的个数n-1。
现在给出树节点的定义:
class TreeNode
{
public:
TreeNode(int x) { val = x; }
int val;
TreeNode *left;
int lflag;
TreeNode *right;
int rflag;
};
ltag=0 时lchild指向左子女;
ltag=1 时lchild指向前驱;
rtag=0 时rchild指向右子女;
rtag=1 时rchild指向后继;
1.第一步线索化:
设置pre为了将它的空指针域指向p,设置其后继结点
在将p的空左节点 前驱节点指向pre,将所有的空节点均填满
void InThread(TreeNode *&root, TreeNode*&pre)//pre为p的前驱节点 p为pre的后继结点
{
if (root)
{
InThread(root->left, pre);//线索化左子树
if (!root->left)//左节点是空
{
root->lflag = 1;//指向前驱节点
root->left = pre;
}
if (pre && !pre->right)//pre后是空
{
pre->rflag = 1;
pre->right = root;//指向后继结点
}
pre = root;
InThread(root->right, pre);//线索化右子树
}
}
2.线索遍历:
TreeNode* FirstNode( TreeNode *t)
{
if(!t)return(NULL);
while(t->lflag==0) t=t->left;//找到最左边的节点
}
TReeNode*NextNode(TreeNode *t)
{
if(rflag==1) return(t->right);
else return(FirstNode(t->right));//返回右节点的最左下节点
}
给出代码:
#include "stdafx.h"
#include <iostream>
#include <queue>
using namespace std;
class TreeNode
{
public:
TreeNode(int x) { val = x; } //constructor
int val;
TreeNode *left;
int lflag;
TreeNode *right;
int rflag;
};
void CreateTree(TreeNode*&t) //先序遍历
{
cout << "input the x:" << endl;
int x;
cin >> x;
if (x != 0)
{
t = (TreeNode *)new TreeNode(x);
CreateTree(t->left);
CreateTree(t->right);
}
else
t = NULL;
}
//中序遍历
void Inorder(TreeNode*p)
{
if (p)
{
Inorder(p->left);
cout << p->val << endl;
Inorder(p->right);
}
}
//层次遍历
void LevelOrder(TreeNode *root)
{
queue<TreeNode* > q;
q.push(root);
while (!q.empty())
{
TreeNode *temp = q.front();
q.pop(); //出队
cout << temp->val << " ";
if (temp->left)
q.push(temp->left);
if (temp->right)
q.push(temp->right);
}
}
//中序线索化--比较常见
void InThread(TreeNode *&root, TreeNode*&pre)//pre为p的前驱节点 p为pre的后继结点
{
if (root)
{
InThread(root->left, pre);//线索化左子树
if (!root->left)//左节点是空
{
root->lflag = 1;//指向前驱节点
root->left = pre;
}
if (pre && !pre->right)//pre后是空
{
pre->rflag = 1;
pre->right = root;//指向后继结点
}
pre = root;
InThread(root->right, pre);//线索化右子树
}
}
void CreateThreaded(TreeNode*& root)
{
if (root)
{
TreeNode*pre = NULL;
InThread(root, pre);//线索化
//处理最后的pre
pre->right = NULL;
pre->rflag = 0;
}
}
TreeNode* FirstNode( TreeNode*t)
{
if (!t) return(NULL);
while (t->lflag == 0)//找到最左下节点
t = t->left;
return(t);
}
TreeNode* NextNode(TreeNode*t)
{
if (t->rflag == 1)//直接后继结点
return(t->right);
else//右子树并不是直接的next节点 就找到其最左端节点
return(FirstNode(t->right));
}
int main()
{
//先序初始化 建树
TreeNode *root;
CreateTree(root);
if (root == NULL) cout << "root==NULL" << endl;
else cout << root->val << endl;
cout << "Inorder" << endl;
Inorder(root);
cout << "LevelOrder" << endl;
LevelOrder(root);
cout << "start to threading:" << endl;
CreateThreaded(root);
//开始线索遍历
for (TreeNode*p = FirstNode(root); p != NULL; p = NextNode(p))
cout << p->val << endl;
system("pause");
}
【注】这里用中序遍历来验证建树是否正确,假设n,m分别是一棵树上的2个节点,那么Inorder的过程中,n在m之前的充要条件是n在m的左边。其中这个在南开大学的硕士入学考试中出现过。