数据结构——树:二叉树的线索化及前序构建遍历

一、名称定义

do something:执行某项任务

renew:值的更新

preOrder:前序遍历

change-type:变形操作,将二叉树Tree类型转变为List类型

root:根节点,即:在main中最开始的那个二叉树节点(node)

二、理解

  这次学习的是前序二叉树及其遍历。这个和中序遍历有很多相似的地方,相同的地方就不在赘述,详情见数据结构——树:二叉树的线索化及中序构建遍历

  首先,还是要构建树的数据结构并且搭建二叉树

#include"iostream"
#include"cstdlib"
#include"cstring"

#define ElemType char

using namespace std;

typedef struct TreeNode
{
    ElemType data;
    struct TreeNode* lchild;
    struct TreeNode* rchild;

    int ltag;
    int rtag;
}TreeNode;


void createTree(TreeNode** T, ElemType* data, int* index)
{
	char ch;
	ch = data[*index];
	*index += 1;
	if (ch == '#')
	{
		*T = nullptr;
	}
	else
	{
		*T = (TreeNode*)malloc(sizeof(TreeNode));
		(*T)->data = ch;
		(*T)->ltag = 0;
		(*T)->rtag = 0;
		//we define the "false" means the node is not visited
		createTree(&((*T)->lchild), data, index);
		createTree(&((*T)->rchild), data, index);
	}
}


int main(void)
{
	TreeNode* T;
	int index = 0;
	TreeNode* pre = nullptr;
	char data[] = "ABD##E##CF##G##";
	createTree(&T, data, &index);
	
	return 0;
}

对于前序遍历,其基本的逻辑和中序遍历差不多,但是有些许的不同,关键就是在于转变函数preThreadTree()。

对于如上的一个二叉树,进行前序遍历(root-left-right),所得的List为:A-B-D-E-C。

现在对它执行change-type操作。

 

三、代码实现

        1.1 preThreadTree(TreeNode* T, TreeNode** pre_node):用于将Tree类型的二叉树转化为List类型的二叉树。

void preThreadTree(TreeNode* T, TreeNode** pre_node)
{
    if(T != nullptr)
    {
        if(T->lchild == nullptr)
        {
            T->ltag = 1;
            T->lchild = *pre_node;
        }
        
        if (*pre_node != nullptr && (*pre_node)->rchild == nullptr)
		{
			(*pre_node)->rtag = 1;
			(*pre_node)->rchild = T;
		}

		*pre_node = T;
		if (T->ltag == 0) // have left-child
		{
			//if T->lchild != nullptr, execute this function, or execute the "if-program"
			preThreadTree(T->lchild, pre_node);
		}
		//*pre_node = T;

		
		//after you have finished manipulating the left-child, then you should deal with the 
		//right-child
		preThreadTree(T->rchild, pre_node);
        
    }
}

int main(void)
{
	TreeNode* T;
	int index = 0;
	TreeNode* pre = nullptr;
	char data[] = "ABD##E##CF##G##";
	createTree(&T, data, &index);
	preThreadTree(T, &pre);
	pre->rtag = 1;
	pre->rchild = nullptr;
	
	return 0;
}

        1.2 解析

  前序遍历和中序遍历之间的关系就和三种递归遍历之间的关系是相同的。就是“做事”和“更新”两者之间的位置不同而已。中序遍历的搭建逻辑是:

inThreadTree(T->lchild, pre_node);

//do something

inThreadTree(T->rchild, pre_node);

前序遍历的逻辑是:

 //do something

inThreadTree(T->lchild, pre_node);

inThreadTree(T->rchild, pre_node);

 但是在这里需要注意的是,由于do something在renew前面,所以可能会造成某个node为空,导致段错误,因此在renew的时候需要进行判断。

由前文所提到的二叉树模型进行分析。在main函数中传入的为root。进入就执行 if 判断

由于 A != nullptr 且 A->lchild  == B != nullptr,不执行

由于 在main中将pre_node 初始化为了nullptr,故不执行第二个 if

更新pre_node为T,开始进行递归,同时不要忘记判断:

        1.当T的左指针空间为0时,说明其指向了下一个节点,走preThreadTree(T->lchild, pre_node)直到找到最左边的node这里的逻辑和inOrder一样

        2.if判断后,再执行preThreadTree(T->rchild, pre_node)

四、完整框架代码

 

#include"iostream"
#include"cstdlib"
#include"cstring"

/*
	  This is oppose to the inOrder binary-tree which is 
	  called "previous clue-binary tree(先序线索二叉树)". The basic logic is the same as the inOrder

	  The basic logic of it is that, if the node which is pointed has no left-child and right-child
	  then, this pointer point to the the previous node and behind node. Or, point to the 
	  corresponding child. 
*/

using namespace std;

typedef struct TreeNode
{
	char data;//used to save the data
	struct TreeNode* lchild; // child pointers
	struct TreeNode* rchild;

	int ltag;//used to record the condition of the left and right node
	int rtag;
}TreeNode;

//create the binary-tree
//the basic logic is similar to the previous achievement
//but you shuold initate the ltag and rtag
void createTree(TreeNode** T, char* data, int* index)
{
	char ch;
	ch = data[*index];
	*index += 1;
	if (ch == '#')
	{
		*T = nullptr;
	}
	else
	{
		*T = (TreeNode*)malloc(sizeof(TreeNode));
		(*T)->data = ch;
		(*T)->ltag = 0;
		(*T)->rtag = 0;
		//we define the "false" means the node is not visited
		createTree(&((*T)->lchild), data, index);
		createTree(&((*T)->rchild), data, index);


	}
}

/*
	  the inOrder traverse Clue-Binary tree
	  change the binary-tree into the clue-binary tree
*/
void preThreadTree(TreeNode* T, TreeNode** pre_node)
{
	/*	  Before you write the tree, you should change your mind first or in order words, you
		shoud tranform the perspective you see the binary-tree. Every time you manipulate the binary-tree,
		you should see the "left-child", "middle-child" and "right-child" as one binary-tree because you
		will use recursion to continue manipulating the next node. So, the next step is delivering the
		left-child or the right-child to the function.
	*/
	// 
	// 
	//There, "T" is the root of the binary tree
	//traverse the tree from the left to middle and then the right.
	//because the root node doesn't have previous node, so the pre_node is "nullptr"
	//FRONT-NODE
	if (T != nullptr)
	{
		if (T->lchild == nullptr)
		{
			//is the left-child is nullptr, assign the ltag is "1"
			T->ltag = 1;
			//and then let the left-child point to the previous node
			T->lchild = *pre_node;
		}
		//BEHIND-NODE
		//after you finish manipulating the lchild, you should deal with the previous node.
		if (*pre_node != nullptr && (*pre_node)->rchild == nullptr)
		{
			(*pre_node)->rtag = 1;
			(*pre_node)->rchild = T;
		}

		*pre_node = T;
		if (T->ltag == 0) // have left-child
		{
			//if T->lchild != nullptr, execute this function, or execute the "if-program"
			preThreadTree(T->lchild, pre_node);
		}
		//*pre_node = T;

		
		//after you have finished manipulating the left-child, then you should deal with the 
		//right-child
		preThreadTree(T->rchild, pre_node);

	}
}

//traverse the clue-binary tree
//because the binary-tree is linear construction now, you can find the head of the list




TreeNode* getNext(TreeNode* node)
{
	if (node->rtag == 1||node->ltag == 1)
	{
		return node->rchild;
	}
	else
	{
		return node->lchild;
	}
	
}


int main(void)
{
	TreeNode* T;
	int index = 0;
	TreeNode* pre = nullptr;
	char data[] = "ABD##E##CF##G##";
	createTree(&T, data, &index);
	preThreadTree(T, &pre);
	pre->rtag = 1;
	pre->rchild = nullptr;
	for (TreeNode* node = T; node != nullptr; node = getNext(node))
	{
		cout << node->data;
	}
	cout << endl;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值