線索化 - 遍歷思想,流程,代碼

一、前言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;
}
相關文章
相關標籤/搜索