一、前言ios
普通二叉樹僅僅能找到結點的左右孩子信息。而該結點的直接前驅和直接後繼僅僅能在遍歷過程當中得到。算法
若可將遍歷後相應的有關前驅和後繼預存起來,則從第一個結點開始就能很是快「順藤摸瓜」而遍歷整個樹了。spa
二叉線索樹思想是幹什麼的?指針
中序遍歷這棵樹===》轉換成鏈表訪問code
2線索化思想
遞歸
結論:線索化過程就是在遍歷過程(若是是中序遍歷)中改動空指針的過程:io
將空的lchild改成結點的直接前驅。class
將空的rchild改成結點的直接後繼。thread
3線索化思想
stream
請將此樹線索化。
1)右空指針線索化:
2)左空指針線索化
3)總結
線索化的本質:讓先後結點,創建關係。
1)兩個輔助指針變量造成差值後:後繼結點的左孩子指向前驅結點,前驅結點的右孩子指向後繼結點。
2)賦值指針變量和業務操做的邏輯關係
代碼:
// threadTree.cpp // 樹的線索化 #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <cstdio> #include <stack> using namespace std; // Link == 0表示指向左右孩子指針 // Thread==1表示指向前驅或者後繼的線索 #define Thread 1 #define Link 0 // 二叉線索存儲結點結構 typedef struct BiThrNode { char data; struct BiThrNode *lchild, *rchild; int LTag; int RTag; // 左右標誌 }BiThrNode, *BiThrTree; char Nil = '#'; // 字符型以空格符爲空 // 按前序輸入二叉線索樹中結點的值。構造二叉線索樹T BiThrNode* createBiThrTree() { BiThrNode *tmp = NULL; char ch; scanf("%c", &ch); if (ch == '#') { return NULL; } else { tmp = (BiThrNode *)malloc(sizeof(BiThrNode)); if (tmp == NULL) { return NULL; } memset(tmp, 0, sizeof(BiThrNode)); tmp->data = ch; tmp->lchild = createBiThrTree(); // 遞歸構造左子樹 tmp->rchild = createBiThrTree(); } return tmp; } BiThrNode *pre; // 全局變量。始終指向剛剛訪問過的結點 // 中序遍歷進行中序線索化 void inThreading(BiThrNode *p) { if (p) { inThreading(p->lchild); // 遞歸左子樹線索化 if (!p->lchild) { // 沒有左子樹 p->LTag = Thread; // 前驅線索 p->lchild = pre;// 左孩子指向前驅 } if (!pre->rchild) { // 前驅沒有又孩子 pre->RTag = Thread; // 後繼線索 pre->rchild = p; // 前驅又孩子指向後繼 } pre = p; // 保持pre指向p的前驅 inThreading(p->rchild); // 遞歸右子樹線索化 } } // 中序遍歷二叉樹T。並將當中序線索化,thrt指向頭結點 BiThrNode* inOrderThreading(BiThrTree T) { BiThrNode *Thrt = NULL; Thrt = (BiThrNode *)malloc(sizeof(BiThrNode)); if (!Thrt) { return NULL; } memset(Thrt, 0, sizeof(BiThrNode)); Thrt->LTag = Link; // 左孩子爲孩子指針 Thrt->RTag = Thread; // 右孩子爲線索化的指針 Thrt->rchild = Thrt; // 右指針回指 if (!T) { // 若二叉樹爲空,則左指針回指 Thrt->lchild = Thrt; } else { Thrt->lchild = T; // 步驟1 pre = Thrt; inThreading(T); // 中序遍歷進行中序線索化 pre->rchild = Thrt;// 步驟4 pre->RTag = Thread; // 最後一個結點線索化 Thrt->rchild = pre; // 步驟2 } return Thrt; } /* 中序遍歷二叉線索樹T(頭結點)的非遞歸算法 */ int InOrderTraverse_Thr(BiThrNode* T) { BiThrNode* p; p = T->lchild; /* p指向根結點 */ while (p != T) { /* 空樹或遍歷結束時,p==T */ while (p->LTag == Link) p = p->lchild; printf("%c ", p->data); //假設中序遍歷的最後一個結點的 右孩子 == T 說明到最後一個結點 ,遍歷結束.. while (p->RTag == Thread && p->rchild != T) { p = p->rchild; printf("%c ", p->data); } p = p->rchild; } return 0; } /* 中序遍歷二叉線索樹T(頭結點)的非遞歸算法 */ int InOrderTraverse_Thr2(BiThrNode* T) { BiThrNode* p; p = T->rchild; /* p指向根結點 */ while (p != T) { /* 空樹或遍歷結束時,p==T */ while (p->RTag == Link) p = p->rchild; printf("%c ", p->data); //假設中序遍歷的最後一個結點的 右孩子 == T 說明到最後一個結點 ,遍歷結束.. while (p->LTag == Thread && p->lchild != T) { p = p->lchild; printf("%c ", p->data); } p = p->lchild; } return 0; } void operatorTree() { BiThrTree T, H; printf("請按前序輸入二叉樹(如:'ABDH##I##EJ###CF##G##')\n"); T = createBiThrTree(); // 按前序產生二叉樹 H = inOrderThreading(T); // 中序遍歷,並中序線索化二叉樹 printf("中序遍歷(輸出)二叉線索樹:\n"); InOrderTraverse_Thr(H); // 中序遍歷(輸出)二叉線索樹 // H D I B J E A F C G printf("\n逆序訪問:"); InOrderTraverse_Thr2(H); // G C F A E J B I D H printf("\n"); } int main() { operatorTree(); return 0; }