当前位置:首页 > 日记 > 正文

算法系列15天快速第十一天树操作(上)

算法系列15天快速第十一天树操作(上)
以前,我们一直在讨论线性结构,它的特征是一个节点有一个最大的先行者和后继者,那么我们今天所说的树是什么呢

我们可以把线性结构转换成一个最大的前体和多个继承者的节点。Haha,这就是我们今天讨论的树。

1:树

我们的思维是一棵枝繁叶茂的树,那么树的数据结构是什么呢是的,他实际上是一棵倒置的树。
条款1:

事实上,树中有很多术语,这是我们必须学习的树结构。

父节点、子节点、兄弟关系

这比较简单。b和c的父节点是A,而b和c是A. B和C的子节点是兄弟节点。



事实上,程度是分支的数目,例如A的分支数有两个B和C

树的程度

这似乎是难以形容的。他与节点度的不同在于树的度数是树中最大的点。事实上,是2。

叶节点,分支节点

叶节点既不是左边节点,也不是右边节点,即节点度为0,分支节点是。

节点中的节点数

这是非常简单的,也就是说,树有几个层次。

有序树,无序树

以前使用的有序树,如堆和两叉叉排序树,表明树是按照一定的规则排序的,而另一种条件是无序树。

森林

在现实中,许多树木形成了森林,在数据结构中,我们把上面的地图的节点割开,然后B、C子树在一起就是森林。

2个树的表示

树结构有多种表示形式,常用作圆括号。
例如,上面的树可以表示为:(a(b(d),(e)),(c(f),(g)))

二叉树

在我们的项目开发中,很多地方都会用到树上,但是树很纠结,所以我们本着小、小的原则。

把一棵树变成两棵树,问题就简单多了。

1:两叉树和树木有什么区别

第一点:树的度数是没有限制的,两棵叉树只能有两棵树,或者不是那两棵树,哈哈。
第二:树中的子树是不分的,很简单啊,找不到参考点,两叉树都会有参考。

2:两叉树的类型

在两叉树中有两种更完美的类型,完全是两叉树和完全的两叉树。

二叉树

除了叶节点外,所有节点的度为2,并且在文章开头的树是完整的两棵树。

完全二叉树

必须满足两个条件:最后一层被干燥,两棵树变成一棵二叉树。

叶节点的最后一层必须从左向右删除。

我们在文章开头把节点f和g干了出来,在这里,它仍然完全是两棵叉树,但它不是一棵完整的两棵树,你知道吗。

3:两叉树的性质

在这两棵叉树上有5点是非常重要的,我们必须记住。

在二叉树,i层的节点有最大值2(i-1)。

二叉树的深度为k最多有2k-1节点。

在两叉树中,叶节点树为N1,节点为2的节点为n2,然后为n2=n2+1。

有n个结点的二叉树的深度为(log2n)+ 1层。

n个节点的完整的二叉树是如何按顺序存储的,对于其中一个节点,I.有以下关系

2 * i是节点i的父节点。

i 2是节点i的左子。

(i 2)+ 1是i节点的右子节点。

4:两叉树的顺序存储

有两种类型的存储方式:顺序存储和链式存储。

顺序存储

说实话,树的存储结构比较小,因为我们可以从性质定理中看出,只要两叉树不存在,我们就只能限制在两棵二叉树上。

两个完整的二进制树,那我们就麻烦了,它必须被转化成两个完整的二叉树,与#代替空节点,图中还可以看出,为了维护

定理5的性质要求我们牺牲两个资源的空间。
链式存储

它还说,顺序存储会造成资源的浪费,因此我们在同一个链存储中使用更多或更多的链式存储。

它也非常形象,非常合理。

一个节点持有一个左指针和一个右指针,这是两个链表。

如何轻松地找到节点的父节点可以使用三叉链表。

5通用操作:

一般来说,它是添加节点、查找节点、计算深度、遍历节点和清除节点。

在这里,我们使用两链链表来定义链式存储模型。
复制代码代码如下所示:
#区二叉链表存储结构
X
两个二进制链表存储结构
X
X
ChainTree公共类
{
公共T数据;

公共ChainTree左;

公共ChainTree权;
}
#铁心端部定点
添加节点

要添加节点,我们将找到添加节点的父节点,并根据指示将左节点或右节点插入父节点。

复制代码代码如下所示:
#区域插入指定的节点到二叉树
X
将将指定的节点插入到两叉树中。
X
X
X
X
只插入左操作是正确的
X
市民ChainTree BinTreeAddNode(ChainTree树ChainTree节点、数据、方向)
{
如果(树= NULL)
返回null;

如果(tree.data.equals(数据))
{
开关(方向)
{
案例方向左:
如果(tree.left!= null)
抛出新的异常(树的左节点不是空的,不能插入);
其他的
tree.left =节点;

打破;
案例方向:
如果(tree.right!= null)
抛出新的异常(树的右节点不是空的,不能插入);
其他的
tree.right =节点;

打破;
}
}

BinTreeAddNode(tree.left、节点、数据、方向);
BinTreeAddNode(tree.right、节点、数据、方向);

回归树;
}
#铁心端部定点
查找节点

在两叉树中到处都有递归思想,它可以使我们理解递归,以及递归的思想。

复制代码代码如下所示:
#区域查找在两个指定键叉树
X
只需在键中指定搜索两个二叉树
X
X
X
X
X
市民ChainTree BinTreeFind(ChainTree树T的数据)
{
如果(树= NULL)
返回null;

如果(tree.data.equals(数据))
回归树;

返回BinTreeFind(树、数据);
}
#铁心端部定点
计算深度

这个问题和我纠缠了两个多小时。原因是对递归没有深刻的理解。实际上,主要思想是递归左子树和右子树,然后得到较大的子树。

复制代码代码如下所示:
#区域得到两深度叉树
X
获取两个叉树的深度
X
X
X
X
市民int BinTreeLen(ChainTree树)
{
国际leftlength;
国际rightlength;

如果(树= NULL)
返回0;

递归/左子树深度
leftlength = BinTreeLen(树。左);

正确的书递归深度
rightlength = BinTreeLen(树吧);

如果(leftlength > rightlength)
返回leftlength + 1;
其他的
返回rightlength + 1;
}
#铁心端部定点
遍历节点

遍历二叉树结点两个以上,用一级顺序,顺序,根据层,实际上这些东西只被感觉到,没有解释,真的很难口语。

很明显,递归需要一次又一次地实现。

前言:首先访问根,然后递归访问左子树,最后递归的右子树(DLR模式)。

中序:首先递归访问左子树,访问根,最后递归右子树(LDR模式)。

后序:首先递归访问左子树,然后递归地访问右子树,最后访问根。(LRD模式)

逐层:这是简单的,从上到下,从左到右遍历节点。

复制代码代码如下所示:
#区域的二叉树的前序遍历
X
第一个遍历 /两叉树
X
X
X
公共无效bintree_dlr(ChainTree树)
{
如果(树= NULL)
返回;

第一个输出根元素
控制台。写(tree.data + T );

然后遍历左侧子树
bintree_dlr(树。左);

最后右子树遍历。
bintree_dlr(树吧);
}
#铁心端部定点

#区域的二叉树的中序遍历
X
顺序遍历二叉树
X
X
X
公共无效bintree_ldr(ChainTree树)
{
如果(树= NULL)
返回;

左子树的第一次遍历
bintree_ldr(树。左);

然后输出节点
控制台。写(tree.data + T );

最后右子树遍历。
bintree_ldr(树吧);
}
#铁心端部定点

#区域的二叉树的后序遍历
X
遍历之后,这两棵叉树
X
X
X
公共无效bintree_lrd(ChainTree树)
{
如果(树= NULL)
返回;

左子树的第一次遍历
bintree_lrd(树。左);

然后遍历右子树
bintree_lrd(树吧);

最终输出节点元素
控制台。写(tree.data + T );
}
#铁心端部定点

#区二叉树进行遍历层
X
只是两叉树级遍历
X
X
X
公共无效bintree_level(ChainTree树)
{
如果(树= NULL)
返回;

申请 /保存空间
ChainTree {} TreeList =新的ChainTree {长};

整数头= 0;
int尾部= 0;

存储阵列
{尾} =树的树形;

循环链尾部位置计算
尾=(尾+ 1)%长度;

当(头)!=尾)
{
无功tempnode = TreeList {头};

头=(头+ 1)%长度;

输出节点
控制台。写(tempnode.data + T );

如果左子树不是空的,左边子树存储在尾部位置数组中。
如果(tempnode.left!= null)
{
Treelist {尾} = tempnode.left;

尾=(尾+ 1)%长度;
}

如果右子树不是空的,则右子树存储在数组尾部位置。
如果(tempnode.right!= null)
{
Treelist {尾} = tempnode.right;

尾=(尾+ 1)%长度;
}
}
}
#铁心端部定点
空两叉树

虽然在C #有GC,我们不能自己释放GC。我们还需要清空两个节点。我们使用递归。说实话,这个练习让我喜欢它。

在xxx的情况下,递归不是很好,但递归仍然非常强大。

复制代码代码如下所示:
#区空二叉树
X
只要清空两棵叉树
X
X
X
公共无效BinTreeClear(ChainTree树)
{
/结束点交付到起始点
如果(树= NULL)
返回;

BinTreeClear(树。左);
BinTreeClear(树吧);

在返回当前节点数据空间的过程中
树=空;
}
#铁心端部定点
最后是总的代码。

复制代码代码如下所示:
使用系统;
使用system.collections.generic;
使用LINQ系统;
使用系统文本;

命名空间的ChainTree
{
程序公开课
{
static void main(String { } args)
{
chaintreemanager经理=新chaintreemanager();

插入节点操作
ChainTree树= CreateRoot();

插入节点数据
AddNode(树);

第一次遍历
console.writeline(一级结果:;
manager.bintree_dlr(树);

在顺序遍历中
console.writeline(结果按照;
manager.bintree_ldr(树);

在遍历之后
console.writeline(订单后结果:;
manager.bintree_lrd(树);

/ /层次遍历
console.writeline(结果级别是:;
管理器长度= 100;
manager.bintree_level(树);

console.writeline(深度树:+ manager.bintreelen(树)+ ;

Console.ReadLine();

}

#区域生成根节点
X
总是生成根节点
X
X
ChainTree CreateRoot(静态)
{
ChainTree树=新的ChainTree();

console.writeline(请输入从而生成树的根节点;

tree.data = console.readline();

console.writeline(根节点的生成产生了;

回归树;
}
#铁心端部定点

#区域插入节点操作
X
只需插入节点操作
X
X
静ChainTree AddNode(ChainTree树)
{
chaintreemanager经理=新chaintreemanager();

虽然(真实)
{
ChainTree节点=新的ChainTree();

console.writeline(请输入数据插入节点:;

node.data = console.readline();

console.writeline(请输入父节点的数据发现:;

无功parentdata = console.readline();

如果(树= NULL)
{
console.writeline(不找你进入,其父节点,请重新输入它。);
继续;
}

console.writeline(请插入母:1左、2右);

方向=(方向)枚举。解析(typeof(方向)、Console.ReadLine());

树= mananger.bintreeaddnode(树节点,parentdata,方向);

console.writeline(插入成功,你继续吗1继续,2退出;

如果(int.parse((控制台。readline))= = 1)
继续;
其他的
打破;
}

回归树;
}
#铁心端部定点
}

#区域插入左节点或节点的正确
X
插入左或右节点节点x
X
枚举方向{左= 1,右= 2 }
#铁心端部定点

#区二叉链表存储结构
X
两个二进制链表存储结构
X
X
ChainTree公共类
{
公共T数据;

公共ChainTree左;

公共ChainTree权;
}
#铁心端部定点

X
只是两叉树帮助类
X
chaintreemanager公共类
{
#区存储空间被层长度
X
根据空间的长度存储层遍历
X
公共长度;get;set;}
#铁心端部定点

#区域插入指定的节点到二叉树
X
将将指定的节点插入到两叉树中。
X
X
X
X
只插入左操作是正确的
X
市民ChainTree BinTreeAddNode(ChainTree树ChainTree节点、数据、方向)
{
如果(树= NULL)
返回null;

如果(tree.data.equals(数据))
{
开关(方向)
{
案例方向左:
如果(tree.left!= null)
抛出新的异常(树的左节点不是空的,不能插入);
其他的
tree.left =节点;

打破;
案例方向:
如果(tree.right!= null)
抛出新的异常(树的右节点不是空的,不能插入);
其他的
tree.right =节点;

打破;
}
}

BinTreeAddNode(tree.left、节点、数据、方向);
BinTreeAddNode(tree.right、节点、数据、方向);

回归树;
}
#铁心端部定点

#区域得到两状态分叉树指定的孩子
X
只要得到两叉树指定孩子的状态
X
X
X
X
X
市民ChainTree BinTreeChild(ChainTree树,方向)
{
ChainTree子结点= null;

如果(树= NULL)
抛出新的异常(两叉树为空);

开关(方向)
{
案例方向左:
子结点= tree.left;
打破;
案例方向:
子结点= tree.right;
打破;
}

返回子节点;
}

#铁心端部定点

#区域得到两深度叉树
X
获取两个叉树的深度
X
X
X
X
市民int BinTreeLen(ChainTree树)
{
国际leftlength;
国际rightlength;

如果(树= NULL)
返回0;

递归/左子树深度
leftlength = BinTreeLen(树。左);

正确的书递归深度
rightlength = BinTreeLen(树吧);

如果(leftlength > rightlength)
返回leftlength + 1;
其他的
返回rightlength + 1;
}
#铁心端部定点

#区域确定二叉树是空的
X
公共判断二叉树是空的
X
X
X
X
市民bool BinTreeisEmpty(ChainTree树)
{
返回树= null:false;
}
#铁心端部定点

#区域查找在两个指定键叉树
X
只需在键中指定搜索两个二叉树
X
X
X
X
X
市民ChainTree BinTreeFind(ChainTree树T的数据)
{
如果(树= NULL)
返回null;

如果(tree.data.equals(数据))
回归树;

返回BinTreeFind(树、数据);
}
#铁心端部定点

#区空二叉树
X
只要清空两棵叉树
X
X
X
公共无效BinTreeClear(ChainTree树)
{
/结束点交付到起始点
如果(树= NULL)
返回;

BinTreeClear(树。左);
BinTreeClear(树吧);

在返回当前节点数据空间的过程中
树=空;
}
#铁心端部定点

#区域的二叉树的前序遍历
X
第一个遍历 /两叉树
X
X
X
公共无效bintree_dlr(ChainTree树)
{
如果(树= NULL)
返回;

第一个输出根元素
控制台。写(tree.data + T );

然后遍历左侧子树
bintree_dlr(树。左);

最后右子树遍历。
bintree_dlr(树吧);
}
#铁心端部定点

#区域的二叉树的中序遍历
X
顺序遍历二叉树
X
X
X
公共无效bintree_ldr(ChainTree树)
{
如果(树= NULL)
返回;

左子树的第一次遍历
bintree_ldr(树。左);

然后输出节点
控制台。写(tree.data + T );

最后右子树遍历。
bintree_ldr(树吧);
}
#铁心端部定点

#区域的二叉树的后序遍历
X
遍历之后,这两棵叉树
X
X
X
公共无效bintree_lrd(ChainTree树)
{
如果(树= NULL)
返回;

左子树的第一次遍历
bintree_lrd(树。左);

然后遍历右子树
bintree_lrd(树吧);

最终输出节点元素
控制台。写(tree.data + T );
}
#铁心端部定点

#区二叉树进行遍历层
X
只是两叉树级遍历
X
X
X
公共无效bintree_level(ChainTree树)
{
如果(树= NULL)
返回;

申请 /保存空间
ChainTree {} TreeList =新的ChainTree {长};

整数头= 0;
int尾部= 0;

存储阵列
{尾} =树的树形;

循环链尾部位置计算
尾=(尾+ 1)%长度;

当(头)!=尾)
{
无功tempnode = TreeList {头};

头=(头+ 1)%长度;

输出节点
控制台。写(tempnode.data + T );

如果左子树不是空的,左边子树存储在尾部位置数组中。
如果(tempnode.left!= null)
{
Treelist {尾} = tempnode.left;

尾=(尾+ 1)%长度;
}

如果右子树不是空的,则右子树存储在数组尾部位置。
如果(tempnode.right!= null)
{
Treelist {尾} = tempnode.right;

尾=(尾+ 1)%长度;
}
}
}
#铁心端部定点

}
}
让我们在文章的开头输入两个树节点到我们的结构中,看看遍历效果是怎样的。

相关文章

教你用PS图象处理软件蓝色方形水晶

教你用PS图象处理软件蓝色方形水晶

方形,图象,处理软件,按钮,教你用,本教程是教你使用PS图象处理软件让蓝色水晶按钮。经过比较,效果非常好。很适合初学者学习和推荐给你。希望你能喜欢。 本教程是教你使用PS图象处理软件让蓝色水晶按钮。经过比较,效果非常好。很适合初学者学…

flex输出文件到本地的两种方法

flex输出文件到本地的两种方法

输出,方法,文件,两种,电脑软件,我用两种方法输出文件到本地文件和fielrefreence Flex,这是 实例uff1a 无功exportstring:字符串=这是一个测试。 1,文件输出 复制代码代码如下所示: VaR FF:文件= file.desktopdirectory.resolvepath(进步.csv…

PS制作简单扑克红桃5

PS制作简单扑克红桃5

红桃,扑克,简单,电脑软件,PS,本教程是介绍使用PS简单制作朋友卡的5红桃,5的红心出教程很好,方法很简单,推荐喜欢的朋友跟着教程学习。 相信大家都熟悉扑克,今天教你用ps制作5卡的简单红心,很简单,一起学习吧! 方法/步骤 1。新的5.5cmx8cm图形 2…

所选是ListView显示和显示文件名、

所选是ListView显示和显示文件名、

显示,路径,文件名,类型,所选,复制代码代码如下所示: 如果(openfiledialog1。ShowDialog)=(DialogResult。OK) { listview1.items.clear(); 字符串{ }文件= openfiledialog1.filenames; / /定义一个数组,为选定的文件 字符串{} FileInfo =新的字符串{ …

js对象的基本实例分析

js对象的基本实例分析

实例分析,对象,电脑软件,js,本文演示了js对象的基本用法,供大家参考,具体分析如下: js对象基本上与数组相同,所有数组都存储一组数据,但是创建方法不同,对象需要添加属性。 这是对象的创建、读取/遍历的简单描述,如下所示: 复制代码代码如下所示…

与PS图象处理软件做一个小的网页按

与PS图象处理软件做一个小的网页按

网页,做一个,图象,处理软件,按钮,这个例子主要是用在PS图象处理软件图层样式来做一个小的蓝色按钮,简单方便。 新文件,自己的大小,后台做径向渐变。 建立一个新层,前景# 00d8ff,画一个圆角矩形。 添加图层样式。 效果如下。 输入黑色像素字…

对fs.write方法在Node.js的使用说

对fs.write方法在Node.js的使用说

使用说明,方法,电脑软件,fs,write,方法显示: 写入文件(根据文件描述符),功能类似于fs.writefile(),但这种方法提供了一个低级别的操作。建议使用多fs.writefile()在实际中的应用。 这种方法有两种形式: 1、fs.write(FD,缓冲区长度,偏移,{,} {回调位置,(呃…

登陆QQ后获取用户信息的证书错误

登陆QQ后获取用户信息的证书错误

获取用户信息,错误,证书,电脑软件,QQ,今晚,欧美汇购物中心的QQ登陆功能开启。回调中有一个错误。当file_get_contents函数执行时,它没有抓住正确的信息,从而改变卷曲,但它提示证书错误。 在Internet上找到解决方案是删除证书身份验证。 复制…

PS只画一根胡萝卜台球棒

PS只画一根胡萝卜台球棒

胡萝卜,画一,台球,电脑软件,棒球棒,本教程主要是介绍给朋友们,用PS来画萝卜台球吧,效果很好。难度不是很大。建议你喜欢你的朋友一起学习。 本教程是介绍使用PS绘制一个简单的胡萝卜台球棒的方法,教程很不错,推荐,一起学习吧! U3000 U3000 本教程…

mysql交换数据存储目录的实现

mysql交换数据存储目录的实现

数据存储,目录,电脑软件,mysql,mysql交换数据存储目录的实现 如今,在工作中,MySQL的存储区的分区空间已经被使用,导致MySQL无法正常启动,为此只迁移了数据存储目录。 1,现有的数据存储目录,转移到其他存储空间,今天50G数据文件的传输,复制超过30…

PS使用变形液化工具,使画像成为一个

PS使用变形液化工具,使画像成为一个

变形,工具,成为一个,画像,喜剧,漫画是一种有趣的替代传统的肖像画。我们的想法是使特定功能滑稽夸张展现个人幽默。在PS图象处理软件的扭曲和液化是好的,你可以变换成漫画肖像摄影 漫画是一种有趣的替代传统的肖像画。我们的想法是使特定功…

使用垂直对齐对齐输入和img

使用垂直对齐对齐输入和img

对齐,输入,电脑软件,img,img标签总是高于输入,和对齐=绝对置中的使用是可行的,但它并不符合HTML标准。发现垂直对齐是不经意的:中间,但有类似情况的朋友可以参考它。 把输入和IMG在同一行,img标签总是比输入高出一头,很难看。在尝试了很多方法,没…