1、定义
对于具有n个节点的二叉树,采用二叉链存储结构时,每个节点有两个指针域,总共有2n个指针域,又由于只有n-1个节点被有效指针所指向,则共有2n-(n-1)=n+1个空链域。
空的左孩子指针指向该结点的前驱;空的右孩子指针指向该结点的后继。这种附加的指针值称为线索,带线索的二叉树称为
线索二叉树。
在不同的遍历次序下,二叉树中的每个结点一般有不同的前驱和后继。因此,线索二叉树又分为
前序线索二叉树
、
中序线索二叉树
和
后序线索二叉树
3种。
根据二叉树的特性,n个结点的二叉树,采用链式存储结构时,有n+1个空链域,可以利用这些空链域存放指向结点的直接前驱和直接后继结点的指针。为此做如下规定:当结点的左指针为空(即无左子树)时,令该指针指向按某种方式遍历二叉树时得到的该结点的前驱结点;当结点的右指针为空(即无右子树)时,令该指针指向按某种方式遍历二叉树时得到的该结点的后继结点;为了避免混淆,还需要增加
两个标志位
来区分指针指向的是其孩子还是前驱及后继。
2、应用
线索二叉树能很快速地求出二叉树节点的前驱节点和后继节点,算法的复杂度为O(n),虽然普通二叉树遍历求前驱和后继节点复杂度也是O(n),但线索二叉树的常数因子更小,求前驱和后继节点比普通二叉树遍历更快。
注:先序线索二叉树查找后继节点容易、查找前驱节点困难;后序线索二叉树查找前驱节点容易、查找后继节点困难;而中序线索二叉树查找后继节点和先驱节点都很容易。因此,先序和后序线索二叉树应用较少,中序线索二叉树应用更加广泛。
3、线索化
由于中序线索二叉树的应用更加广泛,而前序和后序应用较少,所以这里只介绍中序序列二叉树的线索化。
(1)以*b为当前节点,以*pre为直接前驱节点进行二叉树的中序线索化
//create the thread binary tree void ThreadBTNode_InOrder(BTNode* b, BTNode* &pre) { if (b == NULL) return; //1.thread the left child node first ThreadBTNode_InOrder(b->left, pre); //2.then thread the self node if (b->left == NULL) { b->left = pre; b->lTag = 1; } else b->lTag = 0; if (pre->right == NULL) { pre->right = b; pre->rTag = 1; } else pre->rTag = 0; //update the pre node pre = b; //3.last thread the right child ThreadBTNode_InOrder(b->right, pre); }
(2)将一颗二叉链存储的二叉树b进行中序线索化,返回附加线索化二叉树的根节点
//create the thread binary tree, returns the root node BTNode* CreateThreadBTNode_InOrder(BTNode* b) { BTNode* root = new BTNode; root->data = '#'; root->lTag = 0; root->left = b; root->right = NULL; BTNode* p = root; ThreadBTNode_InOrder(b, p); p->rTag == 1; p->right = root; return root; }
4、遍历
(1)求线索二叉树的直接前驱
//get the pre node BTNode* GetPreThreadBTNode_InOrder(BTNode* b) { if (b->lTag == 0) { BTNode* p = b->left; while (p->rTag == 0) p = p->right; return p; } return b->left; }
(2)求线索二叉树的直接后继
//get the next node BTNode* GetNextThreadBTNode_InOrder(BTNode* b) { if (b->rTag == 0) { BTNode* p = b->right; while (p->lTag == 0) p = p->left; return p; } return b->right; }
(3)遍历所有节点
//thread order to display a thread binary tree void ThreadOrder(BTNode* root) { BTNode* p = GetNextThreadBTNode_InOrder(root); while (p != NULL && p != root) { cout << p->data << ", "; p = GetNextThreadBTNode_InOrder(p); } cout << endl; }
5、测试
#include <iostream> using namespace std; typedef char ElemType; //declare the binary tree typedef struct BTNode { ElemType data; int lTag, rTag; BTNode *left, *right; }BTNode; //create binary tree by pre order and in order BTNode* CreateBTByPreAndIn(ElemType* pre, ElemType* in, int n) { if (n <= 0) return NULL; BTNode* b = new BTNode; b->data = *pre; int k; for (ElemType* p = in; p < in + n; p++) { if (*p == *pre) { k = p - in; break; } } b->left = CreateBTByPreAndIn(pre + 1, in, k); b->right = CreateBTByPreAndIn(pre + 1 + k, in + 1 + k, n - k - 1); return b; } //create the thread binary tree void ThreadBTNode_InOrder(BTNode* b, BTNode* &pre) { if (b == NULL) return; //1.thread the left child node first ThreadBTNode_InOrder(b->left, pre); //2.then thread the self node if (b->left == NULL) { b->left = pre; b->lTag = 1; } else b->lTag = 0; if (pre->right == NULL) { pre->right = b; pre->rTag = 1; } else pre->rTag = 0; //update the pre node pre = b; //3.last thread the right child ThreadBTNode_InOrder(b->right, pre); } //create the thread binary tree, returns the root node BTNode* CreateThreadBTNode_InOrder(BTNode* b) { BTNode* root = new BTNode; root->data = '#'; root->lTag = 0; root->left = b; root->right = NULL; BTNode* p = root; ThreadBTNode_InOrder(b, p); p->rTag == 1; p->right = root; return root; } //get the pre node BTNode* GetPreThreadBTNode_InOrder(BTNode* b) { if (b->lTag == 0) { BTNode* p = b->left; while (p->rTag == 0) p = p->right; return p; } return b->left; } //get the next node BTNode* GetNextThreadBTNode_InOrder(BTNode* b) { if (b->rTag == 0) { BTNode* p = b->right; while (p->lTag == 0) p = p->left; return p; } return b->right; } //thread order to display a thread binary tree void ThreadOrder(BTNode* root) { BTNode* p = GetNextThreadBTNode_InOrder(root); while (p != NULL && p != root) { cout << p->data << ", "; p = GetNextThreadBTNode_InOrder(p); } cout << endl; } int main() { //create binary tree by pre order and in order const char* pre = "ABDGCEF"; const char* in = "DGBAECF"; BTNode* b = CreateBTByPreAndIn(const_cast<ElemType*>(pre), const_cast<ElemType*>(in), strlen(pre)); //create and display thread binary tree ThreadOrder(CreateThreadBTNode_InOrder(b)); system("pause"); return 0; }