假设二叉树中每个结点的值为单个字符, 设计一个算法将一棵以二叉链方式存储的二叉树 b 转换成对应的顺序存储结构 a。——含具体实现工程

28 篇文章 0 订阅
19 篇文章 0 订阅

假设二叉树中每个结点的值为单个字符, 设计一个算法将一棵以二叉链方式存储的二叉树 b 转换成对应的顺序存储结构 a。——李春葆数据结构第五版第七章,P246,第十题

思路解析:

解:设二叉树的顺序存储结构类型为SqBTree,先将顺序存储结构a中所有元素置为‘#’(表示空结点)。将b转换成a的递归模型如下:
f(b,a,i) -> a[i]='#'; 当b=NULL
f(b,a,i) -> 由b结点data域值建立a[i]元素; f(b->lchild,a,2*i); f(b->rchild,a,2*i+1); 其他情况
调用方式为:f(b,a,1)(a的下标从1开始)。

对应的算法如下:
void Ctree(BTNode *b,SqBTree a,int i)
{ if (b!=NULL)
{ a[i]=b->data;
Ctree(b->lchild,a,2*i);
Ctree(b->rchild,a,2*i+1);
}
else a[i]='#';
}

具体实现:

我用VC++6.0做的工程,共建了5个源代码文件,代码可访问https://github.com/COCO5666/Date_Structure下载(Chapter07/Ch07_10)

vc6.0(完整绿色版)(支持XP、Win7、Win8、Win10)

https://blog.csdn.net/COCO56/article/details/84570964

LiBTree.h

这里为了避免因重复包含LiBTree.h而造成结构体类型(LBTNode)重复定义的错误发生,使用了#ifndef语句:

#ifndef LiBTree_H

#define LiBTree_H

//代码段

#endif

上面这句话的意思是如果没有定义过LiBTree_H那么定义LiBTree_H并执行"代码段",如果已经定义过则会跳过下面的所有语句,#endif用于结束条件编译,编译时与前面最近的#if、#ifdef#ifndef作为一对,经常一起使用,来进行判断是否编译两者之间的部分代码段(或称程序段)。

#ifndef LiBTree_H

#define LiBTree_H

#include <cstdio>
#include <malloc.h>

#define ElemType char
#define MaxSize 500

typedef struct node
{
	ElemType data;
	struct node *lchild;
	struct node *rchild;
}LBTNode;

void CreateLiBTree(LBTNode *&b, char *str);
void DispLiBTree(LBTNode *b);
void DestroyLiBTree(LBTNode *&b);

#endif

SqBTree.h

#include "LiBTree.h"

#include <cstdio>
#include <iostream>

using namespace std;

#define ElemType char
#define MaxSize 500

typedef ElemType SBTree[MaxSize];
typedef ElemType SBTNode;

void CreateSqBTFromLiBT(SBTNode *&SB, LBTNode *LB, int index=1);
void CreateSqBTree(SBTNode *&b, char *str);
void DispSqBTree(SBTNode *b, int index=1);
void DestroySqBTree(SBTNode *b);

LiBTree.cpp

#include "LiBTree.h"

void CreateLiBTree(LBTNode *&b, char *str)
{
	LBTNode *St[MaxSize], *p;
	int top=-1,k,j=0;
	char ch;
	b = NULL;
	ch = str[j];
	while(ch!='\0')
	{
		switch(ch)
		{
		case '(':top++;St[top]=p;k=1;break;
		case ')':top--;break;
		case ',':k=2;break;
		default:p=(LBTNode *)malloc(sizeof(LBTNode));
			p->data=ch;
			p->lchild=p->rchild=NULL;
			if(b==NULL)
			{
				b=p;
			}
			else
			{
				switch(k)
				{
				case 1:St[top]->lchild=p;break;
				case 2:St[top]->rchild=p;break;
				}
			}
		}
		j++;
		ch=str[j];
	}
}

void DispLiBTree(LBTNode *b)
{
	if(b!=NULL)
	{
		printf("%c", b->data);
		if(b->lchild!=NULL || b->rchild!=NULL)
		{
			printf("(");
			DispLiBTree(b->lchild);
			if(b->rchild!=NULL)
			{
				printf(",");
			}
			DispLiBTree(b->rchild);
			printf(")");
		}
	}
}

void DestroyLiBTree(LBTNode *&b)
{
	if(b!=NULL)
	{
		DestroyLiBTree(b->lchild);
		DestroyLiBTree(b->rchild);
		free(b);
	}
}

SqBTree.cpp

#include "SqBTree.h"

void CreateSqBTFromLiBT(SBTNode *&SB, LBTNode *LB, int index)
{
	static bool flag = true;
	if(flag)
	{
		SB = (SBTNode *)malloc(sizeof(SBTree));
		flag = false;
		for(int j=0; j<MaxSize; j++)
		{
			SB[j]='#';
		}
	}
	if(LB!=NULL)
	{
		SB[index-1] = LB->data;
		CreateSqBTFromLiBT(SB, LB->lchild, 2*index);
		CreateSqBTFromLiBT(SB, LB->rchild, 2*index+1);
	}
	else
	{
		SB[index] = '#';
	}
}

void CreateSqBTree(SBTNode *&b, char *str)
{
	b = (SBTNode *)malloc(sizeof(SBTree));
	int j=0, index=1;
	for(;j<MaxSize;j++)
	{
		b[j]='#';
	}
	j=0;
	char ch;
	ch = str[j];
	while(ch!='\0')
	{
		switch(ch)
		{
		case '(':index=index*2;break;
		case ')':index=index/2;break;
		case ',':index=index+1;break;
		default:
			b[index-1]=ch;break;
		}
		j++;
		ch=str[j];
	}
}


void DispSqBTree(SBTNode *b, int index)
{
	if(b[index-1]!='#')
	{
		printf("%c", b[index-1]);
		if(b[2*index-1]!='#' || b[2*index] !='#')
		{
			printf("(");
			DispSqBTree(b, 2*index);
			if(b[2*index] != '#')
				printf(",");
			DispSqBTree(b, 2*index+1);
			printf(")");
		}
	}
}

void DestroySqBTree(SBTNode *b)
{
	if(b!=NULL)
	{
	free(b);
	b = NULL;
	}
}

mian.cpp

#include "LiBTree.h"
#include "SqBTree.h"

#include "string.h"
#include <iostream>

using namespace std;

int main()
{
	char str[]="A(B,C)";
	int i;
	SBTNode *SB, *SB2;
	LBTNode *LB;

	CreateLiBTree(LB, str);
	DispLiBTree(LB);
	cout  << endl;

	CreateSqBTree(SB, str);
	for(i=0; i<10; i++)
		cout << SB[i];
	cout << endl;
	DispSqBTree(SB);
	cout << endl;

	CreateSqBTFromLiBT(SB2, LB);
	for(i=0; i<10; i++)
		cout << SB2[i];
	cout << endl;
	DispSqBTree(SB2);
	cout << endl;

	DestroyLiBTree(LB);
	DestroySqBTree(SB);
	DestroySqBTree(SB2);
	return 0;
}

 

  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 假设非空二叉树采用顺序存储结构每个结点值为单个字符。要输出编号为i的结点的所有祖先结点,可以按照以下步骤进行: 1. 计算结点i的父结点编号:如果i是根结点,则无父结点;否则,父结点编号为(i-1)/2。 2. 从父结点开始,依次向上遍历二叉树输出每个祖先结点,直到根结点为止。 具体实现时,可以使用一个循环来实现向上遍历,每次计算当前结点的父结点编号,并将当前结点更新为父结点,直到遍历到根结点为止。输出祖先结点可以使用一个数组或表来保存,也可以直接打印输出。 ### 回答2: 非空二叉树采用顺序存储结构,可以将二叉树的每一个结点按照层次顺序进行编号,编号从1开始向下逐个增加,若某个结点编号为i,则其左孩子结点的编号为2i,右孩子结点的编号为2i+1。这样,每个结点的编号对应了该结点顺序存储结构的位置。 根据这个编号规律,可以设计一个算法输出编号为i的结点的所有祖先结点具体实现步骤如下: 1. 首先通过编号i计算出该结点在数组的索引index,即index = i-1。 2. 从该结点的父结点开始,依次输出一个祖先结点。 1)若该结点的编号为奇数,则父结点编号为 (i-1)/2; 2)若该结点的编号为偶数,则父结点编号为 (i-2)/2。 3)将该父结点的编号赋给i,重复步骤2直到i=1。 该算法的时间复杂度为 O(logn),空间复杂度为 O(1)。因为它只需要通过结点编号计算出该结点在数组的索引,然后逐个输出结点的祖先结点,不需要额外的空间存储间结果。 ### 回答3: 假设编号为i的结点所在的位置为j(从1开始),那么它的父节点位置为 j/2,左子节点位置为2j,右子节点位置为2j+1。 因此我们可以从编号为i的结点开始,通过不断地向上查找父节点,直到根节点为止,输出所有的祖先结点具体实现可以借助一个栈来存储每个向上查找的结点。从i结点开始,将其入栈。然后依次将其父节点入栈,直到根节点为止。最后依次出栈,输出所有的祖先结点具体代码如下: ```python def get_ancestors(tree, i): ancestors = [] j = i while j > 0: ancestors.append(tree[j-1]) j //= 2 return ancestors[::-1] ``` 其,tree是存储树的数组,i为要查找祖先结点的节点编号。从i开始向上查找,将每个结点加入到ancestors列表,最后将列表反转,输出所有的祖先结点。 该算法的时间复杂度为O(logn),其n为二叉树结点数,因为最多需要向上查找二叉树的深度次数即可找到根节点。而空间复杂度为O(logn),即最多需要存储二叉树深度个结点

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

COCO56(徐可可)

建议微信红包:xucoco56

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值