在上篇博文中我們說到有關二叉樹的遍歷問題,將樹中的所有結點按照某種次序排列在乙個線性有序的序列中,然後從某個結點出發就會可以輕易找到在某種次序下的前驅和後繼。
然而當我們希望快速找到某一結點的前驅後繼,同時又不希望對二叉樹進行遍歷時,這時就需要乙個東西去把每個結點的前驅後繼記錄儲存起來。為了做到這一點,資料結構引出乙個概念叫線索。就好比在某種次序下用一根線將這棵樹的前驅後繼儲存起來,使得乙個前驅指標指向前驅結點,乙個後繼指標指向後繼結點。
我們可以用乙個結構體來對儲存這些結點,在這裡用列舉對前驅和後繼進行標記。
enum
pointer
;struct binarytreenodethd
當我們做完這些的時候就可以考慮我們怎麼去實現線索化。
1.中序線索二叉樹
在中序線索化中,如果_lefttag==link,那表示在_left中儲存的是左孩子結點的指標;如果_lefttag==thread,即_left中儲存的是指向前驅的指標。_righttag也同理。
首先判斷當前結點,如果當前結點是根結點,那麼就遞迴找到它的最後乙個葉子結點,即圖中3這個結點。現在對3進行前驅線索化,使得_lefttag等於thread。緊接著對它進行後繼線索,因為3沒有左孩子和右孩子,所以接下來我們需要對4進行線索化。
在這裡我們需要借用乙個pre的指標,讓它在遍歷的過程中總是指向在中序遍歷下的前驅結點,即在中序遍歷中剛剛訪問過的結點。同理,4 的前驅結點為2,後繼結點為1……一定要注意:當我們遇到空指標時就根據情況填入前驅或後繼線索。
void _inorderthreading(node* cur, node*& prev) //中序線索化
if (prev && prev->_right ==
null) //建立當前結點的後繼線索
prev = cur; //前驅跟上,當前結點向前遍歷
_inorderthreading(cur->_right, prev); //遞迴,右孩子線索化
}
2.前序線索二叉樹前序線索在思想上和中序線索是一樣的,區別僅是加入前驅和後繼的時間不同。線索表示如下圖。
首先先考慮根,然後在對它的左孩子和右孩子進行處理。當乙個結點是葉子結點時,它需要把前驅鏈結到它的父結點上,用pre儲存上乙個訪問的結點(在這裡也就是父結點),然後再次訪問它父結點的右孩子……依此類推,對於每個結點都做這樣的處理,把大問題不斷變成子問題,然後對其進行處理。**如下。
void _prevorderthreading(node* root, node*& prev)
if (prev && prev->_right ==
null)
prev = root;
if (root->_lefttag ==
link)
_prevorderthreading(root->_left, prev);
if (root->_righttag ==
link)
_prevorderthreading(root->_right, prev);
}
對二叉樹的線索化,思路都是從大問題不斷細化縮小實現,一定要明白它的線索是怎麼個線索法:有孩子結點就存孩子結點的指標,沒有孩子結點就指向前驅或後繼。
最後附上源**。
#include
using
namespace
std;
enum pointer
;template
struct binarytreenodethd
};template
class binarytreethd
//lefttag==0 left中存放的是指向左孩子結點的指標
//lefttag==1 left中存放的是該結點中序下的前驅結點指標
void inorderthreading() //中序線索化
void inorderthd() //中序線索化遍歷
cout
<< cur->_data << " ";
while (cur->_righttag == thread)
cur = cur->_right;
}cout
<< endl;
}void prevorderthreading()
void prevorderthd()
cout
<< cur->_data << " ";
cur = cur->_right;
}cout
<< endl;
}protected:
node* _creattree(t* a, size_t n, const t& invalid, size_t& index)
return root;
}void _inorderthreading(node* cur, node*& prev)
if (prev && prev->_right == null) //建立當前結點的後繼線索
prev = cur; //前驅跟上,當前結點向前遍歷
_inorderthreading(cur->_right, prev); //遞迴,右孩子線索化
}void _prevorderthreading(node* root, node*& prev)
if (prev && prev->_right == null)
prev = root;
if (root->_lefttag == link)
_prevorderthreading(root->_left, prev);
if (root->_righttag == link)
_prevorderthreading(root->_right, prev);
}protected:
node* _root;
};
(C )二叉樹的線索化 線索二叉樹
線索化標誌tag enum pointertag 結點結構 template struct binarytreenodethd 基類迭代器 template struct binarytreeiterator t operator t operator bool operator const sel...
線索化二叉樹以及遍歷線索化二叉樹
1.線索二叉樹基本介紹 n個結點的二叉鍊錶中含有n 1 公式 2n n 1 n 1 個空指標域。利用二叉鍊錶中的空指標域,存放指向該結點在某種遍歷次序下的前驅和後繼結點的指標 這種附加的指標稱為 線索 這種加上了線索的二叉鍊錶稱為線索鍊錶,相應的二叉樹稱為線索二叉樹 threaded binaryt...
線索化二叉樹
define crt secure no warnings 1 includeusing namespace std enum pointertag 列舉 其結構如下 void prevorderthreading 前序 void postorderthreading 後序 void inorder...