二叉树创建的两种方法(图解)

这篇具有很好参考价值的文章主要介绍了二叉树创建的两种方法(图解)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

       

目录

一、括号表示法

(1)括号表示法构建二叉树的算法思路及算法实现

(2)图解括号表示法构建二叉树

(3)测试程序

 二、扩展二叉树

(1)扩展二叉树构建二叉树的算法思路及算法实现

(2)测试程序


        二叉树的创建方法有很多种,在这里我介绍两种:用括号表示法或扩展二叉树来创建二叉树。

一、括号表示法

(1)括号表示法构建二叉树的算法思路及算法实现

        扩号表示法(本质广义表)是树的一种表示。它的表示方法:将树的根结点写在括号的左边,除根结点之外的其余结点写在扩号中,并用逗号隔开。如下图:

二叉树创建的两种方法(图解)

解释:

1、A是根结点,写在扩号左边,其左右孩子为B,C,写成A(B,C)

2、B又是D、E的双亲结点(相当于B、D、E构成的树,B为根结点),故写成 B(D,E),带入上面A(B(D,E),C)

3、E有左孩子,但无右孩子,故写成E(G,),带入得A(B(D,E(G,)),C)

4、C有右孩子,但无左孩子,写成C(,F),带入得A(B(D,E(G,)),C(,F))

总结:这种写法总的来说就是,树根(左子树,右子树),其中左子树又有左子树和右子树,同样右子树有左子树和右子树,一直递归下去,直到叶子结点。

        那怎么是用括号表示法的字符序列(上图的A(B(D,E(G,)),C(,F))) 创建二叉树,其算法思路如下:

(1)用str获取括号表示法表示二叉树的字符串

(2)用ch扫描str

(3)ch = '(' ,则将前面刚创建的结点作为双亲结点入栈,并置k = 1,表示其后创建的结点将作为这个结点的左孩子

(4)ch = ',' ,置k = 2,表示其后创建的结点为右孩子结点。

(5)ch = ')',表示栈顶元素的左右孩子结点处理完毕,出栈。

(6)其它情况创建一个结点,并根据 k 值,判断这个结点是栈中栈顶元素的左孩子还是右孩子,进行链接。

(7)一直循环下去直至str处理完成。

算法实现:文章来源地址https://www.toymoban.com/news/detail-460141.html

/*栈的存储结构*/
typedef struct Stack
{
	BiTree data[Maxsize]; // 存放栈中元素
	int top;		// 栈顶指针
}SqStack;
/*树的存储结构二叉链表*/
typedef struct BiTNode
{
	Elemtype data;
	struct BiTNode* lchild, * rchild;
}BiTNode, * BiTree;
/*初始化栈*/
void InitStack(SqStack* S)
{
	S->top = -1;
}
/*入栈*/
bool Push(SqStack* S, BiTree x)
{
	if (S->top == Maxsize - 1)   // 栈满
		return false;
	S->data[++(S->top)] = x;
	return true;
}
/*出栈*/
bool Pop(SqStack* S, BiTree* x)
{
	if (S->top == -1) // 栈空
		return false;
	*x = S->data[(S->top)--];
	return true;
}
/*利用广义表构建二叉树*/
void CreateBiTree2(BiTree* T, char* str)
{
	SqStack S;			// 辅助栈
	BiTree p = NULL, x;	// 辅助指针
	InitStack(&S);		// 初始化栈
	char ch;
	int i = 0, k;
	ch = str[i];
	while (ch != '\0')  // str未扫描完时循环
	{
		switch (ch)
		{
			case '(': Push(&S, p);		// 入栈,准备链接左孩子
				      k = 1;
					  break;
			case ')': Pop(&S, &x);		// 出栈
					  break;
			case ',': k = 2;			// 准备链接右孩子
				      break;
			default: 
				p = (BiTree)malloc(sizeof(BiTNode));
				p->data = ch; p->lchild = p->rchild = NULL;
				if ((*T) == NULL)		// p为二叉树的根结点
					(*T) = p;
				else					// 已建立二叉树的根结点,根据k值链接左孩子还是右孩子
				{
					switch (k)
					{
						case 1: S.data[S.top]->lchild = p; break; // 链接左孩子
						case 2: S.data[S.top]->rchild = p; break; // 链接右孩子
					}
				}
		}
		i++;
		ch = str[i]; // 继续扫描str
	}
}

(2)图解括号表示法构建二叉树

        我们用上图的括号表示法的字符串(A(B(D,E(G,)),C(,F)))来构建二叉树:

首先扫描到的A直接是其它情况,构建一个结点,并将A赋值给data,且创建的结点赋值给根结点T(由于刚开始树为空即T=NULL)

二叉树创建的两种方法(图解)

 下一次扫描为 ( , A入栈,并且 k = 1(为A链接左孩子左准备),再次扫描下一个字符:

二叉树创建的两种方法(图解)

扫描的字符为B,创建结点并赋值,此时T != NULL(执行else语句块),根据 k = 1,栈顶元素(A)链接左孩子(即B)

二叉树创建的两种方法(图解)

扫描到 ( , 执行B入栈,k = 1

二叉树创建的两种方法(图解)

扫描到 D,创建结点赋值,然后根据 k = 1,栈顶(B)将D作为左孩子进行链接

二叉树创建的两种方法(图解) 扫描到 , ,k = 2,为栈顶元素(B)链接右孩子做准备 

然后接着扫描,扫描到E,创建结点并赋值,根据 k = 2,将C作为右孩子,链接到栈顶元素(B)

二叉树创建的两种方法(图解)

 扫描到 ( , 将E入栈,k = 1

二叉树创建的两种方法(图解)

扫描到 G,创建结点并赋值,根据 k = 1,将G作为左孩子,链接到栈顶元素(E)

二叉树创建的两种方法(图解) 扫描到 ,,k = 2,接着扫描

扫描到 ),栈顶元素(E)退栈,此时栈中有 B、A

二叉树创建的两种方法(图解)

又扫描到 ),栈顶元素(B)退栈,此时栈只有 A

二叉树创建的两种方法(图解)扫描到,, k = 2,接着扫描 

扫描到C,创建结点并赋值,根据 k = 2,C作为右孩子链接到栈顶元素(A)

二叉树创建的两种方法(图解)

扫描到 ( ,C入栈 k = 1

二叉树创建的两种方法(图解)扫描到 ,k = 2,继续扫描

扫描到 F,创建节点并赋值,根据 k = 2,F作为右孩子链接到栈顶元素(C)

二叉树创建的两种方法(图解)扫描到 (,进行退栈

二叉树创建的两种方法(图解)

 又扫描到(,进行退栈 

二叉树创建的两种方法(图解)

 至此,扫描结束,栈为空,二叉树构建完成。

(3)测试程序

// 输入 A(B(D,E(G,)),C(,F))
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>

#define Maxsize 100

typedef char Elemtype;

/*树的存储结构二叉链表*/
typedef struct BiTNode
{
	Elemtype data;
	struct BiTNode* lchild, * rchild;
}BiTNode, * BiTree;

/*栈的存储结构*/
typedef struct Stack
{
	BiTree data[Maxsize]; // 存放栈中元素
	int top;		// 栈顶指针
}SqStack;

/*初始化栈*/
void InitStack(SqStack* S);
/*入栈*/
bool Push(SqStack* S, BiTree x);
/*出栈*/
bool Pop(SqStack* S, BiTree* x);

/*利用广义表构建二叉树*/
void CreateBiTree2(BiTree* T, char* str2);

/*先序遍历*/
void PreOrder(BiTree T);

/*输出树结点*/
void visit(BiTree T);

/*以广义表输出二叉树*/
void DispBiTree(BiTree T);

/*获取一个由二叉树构成的广义表字符*/
void GetStr(char* str);

int main(void)
{
	BiTree T = NULL;
	char str[50];
	GetStr(str);
	CreateBiTree2(&T, str);
	printf("二叉树的先序遍历:\n");
	PreOrder(T);
	printf("二叉树的括号表示法:");
	DispBiTree(T);
	return 0;
}

/*初始化栈*/
void InitStack(SqStack* S)
{
	S->top = -1;
}

/*入栈*/
bool Push(SqStack* S, BiTree x)
{
	if (S->top == Maxsize - 1)   // 栈满
		return false;
	S->data[++(S->top)] = x;
	return true;
}

/*出栈*/
bool Pop(SqStack* S, BiTree* x)
{
	if (S->top == -1) // 栈空
		return false;
	*x = S->data[(S->top)--];
	return true;
}

/*利用广义表构建二叉树*/
void CreateBiTree2(BiTree* T, char* str)
{
	SqStack S;			// 辅助栈
	BiTree p = NULL, x;	// 辅助指针
	InitStack(&S);		// 初始化栈
	char ch;
	int i = 0, k;
	ch = str[i];
	while (ch != '\0')  // str未扫描完时循环
	{
		switch (ch)
		{
		case '(': Push(&S, p);		// 入栈,准备链接左孩子
			k = 1;
			break;
		case ')': Pop(&S, &x);		// 出栈
			break;
		case ',': k = 2;			// 准备链接右孩子结点
			break;
		default:
			p = (BiTree)malloc(sizeof(BiTNode));
			p->data = ch; p->lchild = p->rchild = NULL;
			if ((*T) == NULL)		// p为二叉树的根结点
				(*T) = p;
			else					// 已建立二叉树的根结点,根据k值链接左孩子还是右孩子
			{
				switch (k)
				{
				case 1: S.data[S.top]->lchild = p; break; // 链接左孩子
				case 2: S.data[S.top]->rchild = p; break; // 链接右孩子
				}
			}
		}
		i++;
		ch = str[i]; // 继续扫描str
	}
}

/*先序遍历*/
void PreOrder(BiTree T)
{
	if (T != NULL)
	{
		visit(T);
		PreOrder(T->lchild);
		PreOrder(T->rchild);
	}
}

/*输出树结点*/
void visit(BiTree T)
{
	printf("树结点的值:%c\n", T->data);
}

/*获取一个由二叉树构成的广义表字符*/
void GetStr(char* str)
{
	printf("请输入由二叉树构成的广义表字符串:");
	scanf("%s", str);
}

/*以广义表输出二叉树*/
void DispBiTree(BiTree T)
{
	if (T != NULL)
	{
		printf("%c", T->data);
		if (T->lchild != NULL || T->rchild != NULL) //左右子树不为空
		{
			printf("(");
			DispBiTree(T->lchild);					// 递归处理左子树
			if (T->rchild != NULL)
				printf(",");
			DispBiTree(T->rchild);					//递归处理右子树
			printf(")");
		}
	}
}

 二、扩展二叉树

(1)扩展二叉树构建二叉树的算法思路及算法实现

        扩展二叉树:将二叉树中的每个结点的空指针引出一个虚结点,其值为一特值,比如"#",这种处理后的二叉树为原二叉树的扩展树。扩展二叉树就可以做到一个遍历序列确定一颗二叉树。如下图(前序遍历扩展二叉树,介绍的也是这种):

二叉树创建的两种方法(图解)

         上图扩展二叉树的前序序列为:ABD##EG###C#F##.

总结:将二叉树变为扩展二叉树,就是将原二叉树的每一个一件的度都变为2,即都有左、右孩子。

 算法思路:

(1)当 ch = '#',构建空指针,即(*T = NULL)

(2)ch != '#' ,创建新结点赋值,并进行递归构造左、右子树

算法实现:

/*树的存储结构二叉链表*/
typedef struct BiTNode
{
	Elemtype data;
	struct BiTNode* lchild, * rchild;
}BiTNode, * BiTree;
/*利用一个前序遍历的扩展二叉树的字符串序列*/
void CreateBiTree1(BiTree* T)
{
	Elemtype ch;

	scanf("%c", &ch); //获取前序遍历的扩展二叉树的字符串的一个字符

	if (ch == '#')
		*T = NULL; // 空树结点
	else
	{
		*T = (BiTree)malloc(sizeof(BiTNode));
		if (!*T)  // 未分配到空间
			exit(false);
		(*T)->data = ch;	// 生成根结点
		(*T)->lchild = (*T)->rchild = NULL;
		CreateBiTree1(&(*T)->lchild); // 构造左子树
		CreateBiTree1(&(*T)->rchild); // 构造右子树
	}
}

(2)测试程序

// 输入 ABD##EG###C#F##
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>

#define Maxsize 100

typedef char Elemtype;

/*树的存储结构二叉链表*/
typedef struct BiTNode
{
	Elemtype data;
	struct BiTNode* lchild, * rchild;
}BiTNode, * BiTree;

/*利用一个前序遍历的扩展二叉树的字符串序列*/
void CreateBiTree1(BiTree* T);

/*先序遍历*/
void PreOrder(BiTree T);

/*输出树结点*/
void visit(BiTree T);

int main(void)
{
	BiTree T = NULL;
	printf("请输入前序遍历的扩展二叉树的字符序列:");
	CreateBiTree1(&T);
	printf("二叉树的先序遍历:\n");
	PreOrder(T);
	return 0;
}

/*利用一个前序遍历的扩展二叉树的字符串序列*/
void CreateBiTree1(BiTree* T)
{
	Elemtype ch;

	scanf("%c", &ch); //获取前序遍历的扩展二叉树的字符串的一个字符

	if (ch == '#')
		*T = NULL; // 空树结点
	else
	{
		*T = (BiTree)malloc(sizeof(BiTNode));
		if (!*T)  // 未分配到空间
			exit(false);
		(*T)->data = ch;	// 生成根结点
		(*T)->lchild = (*T)->rchild = NULL;
		CreateBiTree1(&(*T)->lchild); // 构造左子树
		CreateBiTree1(&(*T)->rchild); // 构造右子树
	}
}

/*先序遍历*/
void PreOrder(BiTree T)
{
	if (T != NULL)
	{
		visit(T);
		PreOrder(T->lchild);
		PreOrder(T->rchild);
	}
}

/*输出树结点*/
void visit(BiTree T)
{
	printf("树结点的值:%c\n", T->data);
}

到了这里,关于二叉树创建的两种方法(图解)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python创建多线程的两种常用方法

    这篇文章主要为大家详细介绍了Python中创建多线程的两种常用方法,文中的示例代码简洁易懂,对我们掌握Python有一定的帮助,需要的可以收藏一下 经过总结,Python创建多线程主要有如下两种方法: 函数 类 接下来,我们就来揭开多线程的神秘面纱。 在Python3中,Python提供了

    2024年02月15日
    浏览(37)
  • 二叉树的最大深度和最小深度(两种方法:递归+迭代)

    二叉树的最大深度:   二叉树的最小深度: 给定一个二叉树,找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 说明: 叶子节点是指没有子节点的节点。  输入:root = [3,9,20,null,null,15,7] 输出:2  

    2024年02月15日
    浏览(38)
  • 二叉树的创建及遍历方法

    目录 1、二叉树的定义及特点 2、满二叉树和完全二叉树的概念 3、二叉树的存储结构 4、创建二叉树 5、树的四种遍历方法 6、结果及其分析         二叉树是指树中节点的度不大于2的有序树,它是一种最简单且最重要的树。二叉树的递归定义为:二叉树是一棵空树,或者

    2024年02月02日
    浏览(43)
  • Qt创建右键菜单的两种通用方法(QTableView实现右键菜单,含源码+注释)

    下图为两种右键菜单实现的示例图,源码在本文第三节(源码含详细注释)。 提示:不会使用Qt设计师设计界面的小伙伴点击这里。 该方法是触发contextMenuEvent事件来实现右键菜单,只需在该事件函数中写入对应的右键菜单代码即可。 该方法是通过控件发出的customContextMenuR

    2024年02月15日
    浏览(49)
  • 使用Qt Designer为您的Qt for Python项目创建基于Qt Widgets的图形界面的两种方法

    本页介绍如何使用Qt Designer为您的Qt for Python项目创建基于Qt Widgets的图形界面。Qt Designer是一个图形UI设计工具,可以作为独立的二进制文件(pyside6-designer)提供,也可以嵌入到Qt Creator IDE中。它在Qt Creator中的使用在Using Qt Designer中描述。 设计存储在.ui文件中,这是一种基于

    2024年02月07日
    浏览(47)
  • 手撕二叉树(图解+代码)

    在学习二叉树之前,我们有必要了解一下树的概念和常用术语。接下来以下面这棵树为例来回顾下树相关概念: 树的概念:一种非线性的数据结构,由n(n =0)个节点组成的一个具有层次关系的集合。 树的术语: 节点的度 一个节点含有子树的个数,例如上图中A的度为6. 树的度

    2023年04月22日
    浏览(36)
  • 线索二叉树(图解+完整代码)

    目录 ⚽1.问题 🏐2.线索化 🏀 3.线索化带来的问题与解决 🥎4.完整代码 我们的二叉树学到现在,会产生两个问题: 在n个结点的二叉树中,必定有n+1个空链域(叶子结点的左右子树空间浪费了) 二叉树的遍历,无论是递归还是非递归算法,效率都不算高。 那我们能不能利用

    2024年02月03日
    浏览(42)
  • 【数据结构】二叉树篇|超清晰图解和详解:二叉树的最近公共祖先

    博主简介: 努力学习的22级计算机科学与技术本科生一枚🌸 博主主页: @是瑶瑶子啦 每日一言🌼: 你不能要求一片海洋,没有风暴,那不是海洋,是泥塘——毕淑敏 🔗236. 二叉树的最近公共祖先 注意:祖先是 包括自身 的! 🍊首先要明白,当 root为p,q的最近祖先节点 ,只

    2024年02月12日
    浏览(52)
  • 数据结构---手撕图解二叉树(含大量递归图解)

    二叉树的几乎所有实现都是依靠递归实现,递归的核心思路是把任何一个二叉树看成根和左右子树,而二叉树递归的核心玩法就是把二叉树的左右子树再看成根,再找左右子树,再看成根… 因此,解决二叉树问题实际上要把二叉树转换成一个一个子树的过程,找到一个一个的

    2024年02月16日
    浏览(41)
  • 数据结构:手撕图解二叉树(含大量递归图解)

    二叉树的几乎所有实现都是依靠递归实现,递归的核心思路是把任何一个二叉树看成根和左右子树,而二叉树递归的核心玩法就是把二叉树的左右子树再看成根,再找左右子树,再看成根… 因此,解决二叉树问题实际上要把二叉树转换成一个一个子树的过程,找到一个一个的

    2024年02月15日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包