线索二叉树 C++

最后都变了- 提交于 2019-12-13 13:01:59

线索二叉树 C++

以此二叉树为例进行创建:
在这里插入图片描述
前序法创建节点,输入’#'表示为NULL

用前序创建的话需要输入 :ABD##E##C#G##
前序遍历:ABD##E##C#G##
中序遍历:#D#B#E#A#C#G#
后序遍历: ##D##EB###GCA
层序遍历: ABCDEG

在进行线索二叉树线索化的过程中我们并不设置 头结点, 而是**直接设置一个全局变量 指针 Prev **, 表示指向上一个节点的位置 。

思想:
1.首先对创建好的二叉树利用一次中序遍历的过程设置好 lTag 与 rtag 。
在这个过程中 T指针负责设置 T->ltag(前驱), prev指针负责设置 prev->rtag(后继)
2.中序线索二叉树的遍历 ,由于设置了前驱和后继,就可以不使用栈, 直接用迭代法进行中序遍历。

ThreadBiTree.h

#pragma once
#include <iostream>
using namespace std;
#define MAX 30
typedef char ElemType;
typedef struct ThreadBiNode {
	ElemType data;
	struct ThreadBiNode *lchild, *rchild;
	int ltag, rtag;//0表示正常连接孩子, 1表示前缀后缀
	ThreadBiNode() :data(-1), lchild(NULL), rchild(NULL), ltag(0), rtag(0) {};//无参的构造函数
	ThreadBiNode(ElemType e) :data(e), lchild(NULL), rchild(NULL), ltag(0), rtag(0) {};//有参的构造函数
}ThreadBiNode, *ThreadBiTree;



//创建线索二叉树(前序创建),等到中序遍历时才设置ltag, rtag
ThreadBiTree CreateThreadBiTree(const string& tree, int& i);
//中序遍历
void InTraverse_Settag(ThreadBiTree& T, ThreadBiTree& prev);
//中序遍历测试ltag rtag设置得是否正确
void InTraverse(ThreadBiTree T);

//线索二叉树的遍历 此时因为设置了tag, 所以不再需要借助栈了
void InTraverse_Thread(ThreadBiTree root);

ThreadBiTree.cpp

#include "ThreadBiTree.h"


//创建线索二叉树(前序创建),等到中序遍历时才设置ltag, rtag
ThreadBiTree CreateThreadBiTree(const string& tree, int& i) {
	if (tree[i] == '#') {//如果节点'#'则表示这个节点为NULL
		return NULL;
	}
	else {
		ThreadBiTree pNew = new ThreadBiNode(tree[i]);
		i++;
		pNew->lchild = CreateThreadBiTree(tree, i);
		i++;
		pNew->rchild = CreateThreadBiTree(tree, i);
		return pNew;
	}
}


/*
设置两个指针(注意这两个指针会改变树的结构) T, prev
T只负责左孩子 (前缀)
prev只负责右孩子 (后缀)
*/
//中序遍历
void InTraverse_Settag(ThreadBiTree& T, ThreadBiTree& prev) {//prev刚开始设置成头结点
	if (T == NULL) {
		//printf("#");
		return;
	}
	else {
		InTraverse_Settag(T->lchild, prev);

		if (T->lchild == NULL) {
			T->ltag = 1;
			T->lchild = prev;
		}

		if ((prev != NULL) && (prev->rchild == NULL)) {//prev!= NULL 这个条件容易被遗漏
			prev->rtag = 1;
			prev->rchild = T;
		}

		prev = T;//注意这一步是关键的步骤,只要能进入递归条件这里,则说明一定会有pre的交替

		InTraverse_Settag(T->rchild, prev);
	}
}


//中序遍历测试ltag rtag设置得是否正确
void InTraverse(ThreadBiTree T) {
	if (T == NULL) {
		//printf("#");
		return;
	}
	else {
		if (T->ltag == 0)
			InTraverse(T->lchild);
		printf("ltag = %d, data = %c, rtag = %d\n", T->ltag, T->data, T->rtag);
		if (T->rtag == 0)
			InTraverse(T->rchild);
	}
}



//线索二叉树的遍历 此时因为设置了tag, 所以不再需要借助栈了
void InTraverse_Thread(ThreadBiTree root) {
	ThreadBiTree p = root;

	while (p) {
		//向左
		while (p->ltag == 0 && p->lchild) {
			p = p->lchild;
		}

		printf("%c", p->data);//visit

		while (p->rtag != 0) {
			p = p->rchild;
			printf("%c", p->data);//visit

		}
		p = p->rchild;
	}
}

main.cpp

#include "ThreadBiTree.h"


int main() {
	const string tree = "ABD##E##C#G##";
	int i = 0; 
	ThreadBiTree root = CreateThreadBiTree(tree, i);

	ThreadBiTree prev = new ThreadBiNode();//用于表示前面的节点

	
	//线索二叉树设置通过中序遍历 设置 tag
	InTraverse_Settag(root, prev);

	//测试 tag是否设置正确
	InTraverse(root);

	//线索二叉树的遍历 :因为是通过中序遍历的方式设置的tag ,线索二叉树的遍历默认为 中序遍历的结果
	//InTraverse_Thread(root);
	return 0;
}

从程序的编写角度来看, C++确实要比C方便很多。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!