C語(yǔ)言 數(shù)據(jù)結(jié)構(gòu)之中序二叉樹(shù)實(shí)例詳解
C語(yǔ)言數(shù)據(jù)結(jié)構(gòu) 中序二叉樹(shù)
前言:
線索二叉樹(shù)主要是為了解決查找結(jié)點(diǎn)的線性前驅(qū)與后繼不方便的難題。它只增加了兩個(gè)標(biāo)志性域,就可以充分利用沒(méi)有左或右孩子的結(jié)點(diǎn)的左右孩子的存儲(chǔ)空間來(lái)存放該結(jié)點(diǎn)的線性前驅(qū)結(jié)點(diǎn)與線性后繼結(jié)點(diǎn)。兩個(gè)標(biāo)志性域所占用的空間是極少的,所有充分利用了二叉鏈表中空閑存的儲(chǔ)空間。
要實(shí)現(xiàn)線索二叉樹(shù),就必須定義二叉鏈表結(jié)點(diǎn)數(shù)據(jù)結(jié)構(gòu)如下(定義請(qǐng)看代碼):
|
left |
leftTag |
data |
rightTag |
right |
說(shuō)明:
1. leftTag=false時(shí),表示left指向該結(jié)點(diǎn)的左孩子;
2. leftTag=true時(shí),表示left指向該結(jié)點(diǎn)的線性前驅(qū)結(jié)點(diǎn);
3. rightTag=false時(shí),表示right指向該結(jié)點(diǎn)的右孩子;
4. rightTag=true時(shí),表示right指向該結(jié)點(diǎn)的線性后繼結(jié)點(diǎn);
以二叉鏈表結(jié)點(diǎn)數(shù)據(jù)結(jié)構(gòu)所構(gòu)成的二叉鏈表作為二叉樹(shù)的存儲(chǔ)結(jié)構(gòu),叫做線索二叉鏈表;指向結(jié)點(diǎn)的線性前驅(qū)或者線性后繼結(jié)點(diǎn)的指針叫做線索;加上線索的二叉樹(shù)稱(chēng)為線索二叉樹(shù);對(duì)二叉樹(shù)以某種次序遍歷將其變?yōu)榫€索二叉樹(shù)的過(guò)程叫做線索化。
中序次序線索化二叉樹(shù)算法:
中序次序線索化是指用二叉鏈表結(jié)點(diǎn)數(shù)據(jù)結(jié)構(gòu)建立二叉樹(shù)的二叉鏈表,然后按照中序遍歷的方法訪問(wèn)結(jié)點(diǎn)時(shí)建立線索;(具體看代碼)
檢索中序二叉樹(shù)某結(jié)點(diǎn)的線性前驅(qū)結(jié)點(diǎn)的算法:
1. 如果該結(jié)點(diǎn)的leftTag=true,那么left就是它的線性前驅(qū);
2. 如果該結(jié)點(diǎn)的leftTag=false,那么該結(jié)點(diǎn)左子樹(shù)最右邊的尾結(jié)點(diǎn)就是它的線性前驅(qū)點(diǎn);
(具體請(qǐng)看代碼)
檢索中序二叉樹(shù)某結(jié)點(diǎn)的線性后繼結(jié)點(diǎn)和算法:
1. 如果該結(jié)點(diǎn)的right=true,那么right就是它的線性后繼結(jié)點(diǎn);
2. 如果該結(jié)點(diǎn)的right=false,那么該結(jié)點(diǎn)右子樹(shù)最左邊的尾結(jié)點(diǎn)就是它的線性后繼結(jié)點(diǎn)
(具體請(qǐng)看代碼)

圖:后繼線索

圖:前驅(qū)線索
節(jié)點(diǎn)定義:
struct Node
{
int data;
bool leftTag;
bool rightTag;
Node* left;
Node* right;
Node(int _data):data(_data),left(0),right(0),leftTag(false),rightTag(false){}
};
類(lèi)定義:
class BinaryTree
{
private:
Node* root;
private:
Node* head;
Node* pre;
void makeThread(Node* node);
public:
void buildThread();
void traverseBySuccessor();
void traverseByPredecessor();
// helper methods
private:
static inline bool visit(Node* T)
{
if (T)
{
printf("data:%c, left:%c, right:%c\n",
(char)T->data,
(T->left!=0) ? (char)T->left->data : '#',
(T->right!=0) ? (char)T->right->data : '#');
return true;
}
else return false;
}
};
方法定義:
void BinaryTree::makeThread(Node* node)
{
if (node!=NULL)
{
makeThread(node->left);
if (pre!= NULL)
{
if (pre->right==NULL) // 如果前驅(qū)節(jié)點(diǎn)的右子樹(shù)為空, 那么把前驅(qū)節(jié)點(diǎn)的右子樹(shù)用作線索
{
pre->rightTag = true;
pre->right = node;
}
else pre->rightTag = false;
}
if (node->left==NULL) // 如果當(dāng)前結(jié)點(diǎn)的左子樹(shù)為空, 那么把當(dāng)前結(jié)點(diǎn)的左子樹(shù)用作線索
{
node->leftTag = true;
node->left = pre;
}
else node->leftTag = false;
pre = node;
makeThread(node->right);
}
}
void BinaryTree::traverseBySuccessor()
{
Node* p = head->left; //first find the root node
// 親測(cè)表明 如果不使用head啞節(jié)點(diǎn) 就要設(shè)三道卡, 防止p訪問(wèn)到NULL,
// 分別在主while處, 第二個(gè)visit處和下面的p=p->right處
while (p!=head)
{
while (!p->leftTag)
p = p->left;
visit(p);
while (p->rightTag && p->right!=head)
{
p = p->right;
visit(p);
}
p = p->right;
}
cout<<endl;
}
void BinaryTree::traverseByPredecessor()
{
Node* p = head->left; //first find the root node
while (p!=head)
{
while (!p->rightTag)
p = p->right;
visit(p);
if (p!=NULL)
{
while (p->leftTag && p->left!=head)
{
p = p->left;
visit(p);
}
p = p->left;
}
}
cout<<endl;
}
void BinaryTree::buildThread()
{
pre = NULL;
head = new Node('@');
head->left = root;
head->right = head;
makeThread(root);
// 經(jīng)過(guò)了makeThread過(guò)程之后, pre必然指向中序遍歷最晚的結(jié)點(diǎn).
// 把pre的右子樹(shù)指向head, 就構(gòu)成了一個(gè)雙向循環(huán)鏈表
//
pre->rightTag = 1;
pre->right = head;
pre = NULL;
Node* p = root;
/*
* 在建立前驅(qū)線索的時(shí)候,最左邊的結(jié)點(diǎn)沒(méi)有和head結(jié)點(diǎn)連接。要在這里補(bǔ)上
*/
while (p->left!=NULL)
p = p->left;
p->left = head;
}
感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
相關(guān)文章
C語(yǔ)言中用于產(chǎn)生隨機(jī)數(shù)的函數(shù)使用方法總結(jié)
這篇文章主要介紹了C語(yǔ)言中用于產(chǎn)生隨機(jī)數(shù)的函數(shù)使用方法總結(jié),分別介紹了rand()函數(shù)和srand()函數(shù)以及封裝出的arc4random()函數(shù),需要的朋友可以參考下2016-05-05
C語(yǔ)言實(shí)現(xiàn)十六進(jìn)制與二進(jìn)制的相互轉(zhuǎn)換
這篇文章主要為大家詳細(xì)介紹了如何利用c語(yǔ)言實(shí)現(xiàn)將文件中十六進(jìn)制數(shù)據(jù)與二進(jìn)制數(shù)據(jù)相互轉(zhuǎn)換,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的可以學(xué)習(xí)一下2022-11-11
c語(yǔ)言枚舉類(lèi)型enum的用法及應(yīng)用實(shí)例
enum是C語(yǔ)言中的一個(gè)關(guān)鍵字,enum叫枚舉數(shù)據(jù)類(lèi)型,枚舉數(shù)據(jù)類(lèi)型描述的是一組整型值的集合,這篇文章主要給大家介紹了關(guān)于c語(yǔ)言枚舉類(lèi)型enum用法及應(yīng)用的相關(guān)資料,需要的朋友可以參考下2021-07-07
C語(yǔ)言用數(shù)組實(shí)現(xiàn)反彈球消磚塊
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言用數(shù)組實(shí)現(xiàn)反彈球消磚塊,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05
C語(yǔ)言利用鏈表實(shí)現(xiàn)學(xué)生成績(jī)管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言如何利用鏈表實(shí)現(xiàn)學(xué)生成績(jī)管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-11-11

