二叉树顺序结构和链式结构的相互转换

设计思路

顺序存储结构和链式存储结构的联系

链式的根节点与其的左右孩子在顺序存储结构中,存在这样的关系:

\[左孩子的序号=根节点序号*2+1 【根节点序号从零开始算,若从一开始算无需+1】 \]

\[右孩子的序号=左孩子+1=根节点序号*2+2 \]

伪代码

根据其之间的联系,设想如下伪代码:

/*顺序转链式*/
BiTree Order_to_Chain(SqBtree T, int i)
{                    //读入一棵顺序存储的二叉树T,字符串类型
if(T[i]=='#') return 空;
新建二叉树的结点BT;
BT->data=T[i];
递归遍历左子树;//
递归遍历右子树;
return BT;
}
/*链式转顺序*/
void Chain_to_Order(BiTree T,int i)
{            //读入链式存储结构的二叉树

	if (树不空)
	{
		BT[i]=T->data;
		递归遍历左子树;
		递归遍历右子树;
	}
	else(如果该节点为空)
	{
		顺序树存入‘#’字符。
	}
}

重要代码实现

顺序转链式

/*顺序存储结构转链式*/
 BiTree Order_to_Chain(SqBtree T, int i) 
{
	BiTree BT;
	if (T[i] == '#')
	{
		return NULL;
	}
	BT = new TNode;
	BT->data = T[i];
	BT->lchild = Order_to_Chain(T, 2 * i+1);
	BT->rchild = Order_to_Chain(T, 2 * i + 2);
	return BT;
}

链式转顺序

/*链式存储结构转顺序*/
void Chain_to_Order(BiTree T,SqBtree &BT,int i)
{
	if (T)
	{
		BT[i] = T->data;
		Chain_to_Order(T->lchild, BT, 2 * i + 1);
		Chain_to_Order(T->rchild, BT, 2 * i + 2);
	}
	else
	{
		BT[i] = '#';
	}
}

代码运行结果及分析

对于这棵二叉树:
image-20200406123107999.png
它的前序遍历结果为ABDEC,中序遍历结果为DEBAC,它的后序遍历结果为EDBCA,它的顺序存储结构为:

0 1 2 3 4 5 6 7 8
A B C D # # # # E

其实顺序存储结构最后一位结点E,它的左孩子和右孩子都为空,但也是需要申请存储空间的,但因为他后面无带数据的根节点,我们可以在代码上加入一个判断,当下标超出数组长度时,则均返回null。

进行代码测试:

扫描二维码关注公众号,回复: 10535774 查看本文章

1、顺序转链式,输入字符串“ABCD####E”

image-20200406131246227.png

运行结果正确。

2、链式转顺序,输入一串字符”ABD#E###C##“,前序创建树

image-20200406155130617.png

运行结果正确

全部代码展示

#include<iostream>
#include<string>
using namespace std;
char BT[100];   //定义全局变量,存储顺序存储结构的二叉树
typedef char Elemtype;
typedef string SqBtree;
typedef struct TNode {
	Elemtype data;
	TNode* lchild, * rchild;
}TNode,*BiTree;
/*先序遍历创建树*/
int N = 0;
BiTree CreateTree(string s) {
	if (s[N] == '#') {
		N++;
		return NULL;
	}
	BiTree root;
	root = new TNode;
	root->data = s[N];
	N++;
	root->lchild = CreateTree(s);
	root->rchild = CreateTree(s);
	return root;
}
/*顺序存储结构转链式*/
 BiTree Order_to_Chain(SqBtree T, int i,int len) 
{
	 if (i >= len) return NULL;
	BiTree BT;
	if (T[i] == '#')
	{
		return NULL;
	}
	BT = new TNode;
	BT->data = T[i];
	BT->lchild = Order_to_Chain(T, 2 * i+1,len);
	BT->rchild = Order_to_Chain(T, 2 * i + 2,len);
	return BT;
}
/*链式存储结构转顺序*/
void Chain_to_Order(BiTree T,int i)
{
	
	if (T)
	{
		BT[i] = T->data;
		Chain_to_Order(T->lchild, 2 * i + 1);
		Chain_to_Order(T->rchild, 2 * i + 2);
	}
	else
	{
		BT[i] = '#';
	}
}
/*前序遍历*/
void PreOrder(BiTree b)
{
	if (b != NULL)
	{
		cout << b->data
			<< ' ';
		PreOrder(b->lchild);
		PreOrder(b->rchild);
	}
	else return;
}
/*中序遍历*/
void InOrder(BiTree b)
{
	if (b != NULL)
	{
		InOrder(b->lchild);
		cout << b->data
			<< ' ';
		InOrder(b->rchild);
	}
	else return;
}
/*后序遍历*/
void PostOrder(BiTree b)
{
	if (b != NULL)
	{
		PostOrder(b->lchild);
		PostOrder(b->rchild);
		cout << b->data
			<< ' ';
	}
	else return;
}
/*遍历输出二叉链树*/
void printTree1(BiTree T)
{
	if (T == NULL) 
		cout << "树为空";
	else 
	{
		cout << "先序遍历: ";
		PreOrder(T);
		cout << endl;
		cout << "中序遍历: ";
		InOrder(T);
		cout << endl;
		cout << "后序遍历: ";
		PostOrder(T);
		cout << endl;
	}
}
/*输出顺序树*/
void printTree2(char BT[])
{
	int i;
	cout << "该树的顺序存储结构为: ";
	for (i = 0; BT[i] != '0'; i++) {
		cout << BT[i];
	}
}
int main() {
	SqBtree s;
	BiTree T;
	{    //顺序转链序输入
	//cin >> s;
	//int len = s.size();
	//T = Order_to_Chain(s, 0,len);
	//printTree1(T);
	}
	
	{
		/*      链式转顺序
	cin >> s;
	T = CreateTree(s);
	memset(BT, '0', sizeof(BT));  //将BT字符串一键初始化为0
	Chain_to_Order(T,0);
	printTree2(BT);
	*/
	}
	return 0;
}


总结

整个代码设计都是围绕递归来写的,一开始没有初始化字符串BT的时候,运行总是出现string subscript out of range的错误,这是越界了,然后把string改为一个具有上限的char 【maxsize】的话,就无法确定输出字符的个数,因此引入了memset一键初始化,这样就既保证了不会越界,也能控制输出。

猜你喜欢

转载自www.cnblogs.com/AJAJAJfighting/p/12642549.html