線索二叉樹【定義、應用、線索化、遍歷】
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;
}
相關文章
- 線索二叉樹的構造和遍歷二叉樹
- 中序線索二叉樹的建立與遍歷二叉樹
- 中序線索二叉樹的構造和遍歷二叉樹
- 13、線索二叉樹二叉樹
- 二叉樹(順序儲存二叉樹,線索化二叉樹)二叉樹
- 線索二叉樹的原理及建立二叉樹
- java實現-資料結構之二叉樹(三):線索化二叉樹Java資料結構二叉樹
- 常用資料結構之線索二叉樹資料結構二叉樹
- 二叉樹的遍歷及應用二叉樹
- 論 如何畫線索二叉樹[資料結構]二叉樹資料結構
- 【資料結構&演算法】12-線索二叉樹資料結構演算法二叉樹
- CRM中線索是什麼,如何管理線索?
- 二叉樹遍歷二叉樹
- 二叉樹---遍歷二叉樹
- 二叉樹遍歷方法二叉樹
- 二叉樹的遍歷二叉樹
- 二叉樹遍歷 -- JAVA二叉樹Java
- C++樹——遍歷二叉樹C++二叉樹
- 二叉樹的建立、遍歷、廣義錶轉換二叉樹
- 144.二叉樹的前序遍歷145.二叉樹的後序遍歷 94.二叉樹的中序遍歷二叉樹
- 【LeetCode-二叉樹】二叉樹前序遍歷LeetCode二叉樹
- 迴圈遍歷二叉樹二叉樹
- 二叉樹四種遍歷二叉樹
- 完全二叉樹的遍歷二叉樹
- 6.14-二叉樹遍歷二叉樹
- 二叉樹--後序遍歷二叉樹
- 玩轉二叉樹(樹的遍歷)二叉樹
- 初階技能:Android 應用異常如何豐富線索Android
- 根據二叉樹的前序遍歷和中序遍歷輸出二叉樹;二叉樹
- 採用層次遍歷判斷二叉樹為完全二叉樹二叉樹
- java實現二叉樹的Node節點定義手撕8種遍歷(一遍過)Java二叉樹
- 二叉樹的遍歷筆記二叉樹筆記
- 二叉樹的遍歷實現二叉樹
- 二叉樹的層序遍歷二叉樹
- 二叉樹的按層遍歷二叉樹
- 二叉樹遍歷方法總結二叉樹
- 二叉樹的遍歷 → 不用遞迴,還能遍歷嗎二叉樹遞迴
- 什麼是遍歷二叉樹,JavaScript實現二叉樹的遍歷(遞迴,非遞迴)二叉樹JavaScript遞迴