在前面总结的链表是一种一对一的关系,而有一种一对多的关系就是树。树也是由一个一个的结点组成的,每一个结点都可以看成一棵树。每一个结点只能有一个父结点,而子结点可以有多个,没有父结点的结点称为根结点,在一棵树中,根结点有且仅有一个。根结点的子结点又可以当成是一棵树,称为子树。没有子结点的结点称为叶子结点。在树结构中,最常用的时二叉树,即每个结点至多只有两颗子树。
现在我们来自定义一颗二叉树,要构造一颗二叉树,首先要有结点,所以首先要先定义一个结点类TreeNode,然后定义结点的属性,即数据域,指向父结点的对象和指向两个子结点的对象以及设置和得到这些属性的相关方法,具体代码如下:
/**
* 二叉树结点类
* @author lenovo
*
*/
public class TreeNode {
private Object obj;
private TreeNode parent;
private TreeNode Lchild;
private TreeNode Rchild;
//构造方法
public TreeNode(Object obj){
this.obj = obj;
}
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
public TreeNode getParent() {
return parent;
}
public void setParent(TreeNode parent) {
this.parent = parent;
}
public TreeNode getLchild() {
return Lchild;
}
public void setLchild(TreeNode lchild) {
Lchild = lchild;
}
public TreeNode getRchild() {
return Rchild;
}
public void setRchild(TreeNode rchild) {
Rchild = rchild;
}
}
定义了结点之后,就可以创建根结点以及其他子结点,然后再建立引用关系就可以手工建成一颗二叉树了,具体代码如下所示:
/**
* 手工创建二叉树
* @return:返回树的根结点
*/
public TreeNode createTree(){
//创建根结点
TreeNode root = new TreeNode("根结点");
TreeNode lchild = new TreeNode("左孩子");
TreeNode rchild = new TreeNode("右孩子");
TreeNode llchild = new TreeNode("左左孩子");
TreeNode lrchild = new TreeNode("左右孩子");
TreeNode rlchild = new TreeNode("右左孩子");
TreeNode rrchild = new TreeNode("右右孩子");
TreeNode lllchild = new TreeNode("左左左孩子");
TreeNode llrchild = new TreeNode("左左右孩子");
//建立引用关系
root.setLchild(lchild);
root.setRchild(rchild);
lchild.setParent(root);
rchild.setParent(root);
lchild.setLchild(llchild);
lchild.setRchild(lrchild);
llchild.setParent(lchild);
lrchild.setParent(lchild);
rchild.setLchild(rlchild);
rchild.setRchild(rrchild);
rlchild.setParent(rchild);
rrchild.setParent(rchild);
llchild.setLchild(lllchild);
llchild.setRchild(llrchild);
lllchild.setParent(llchild);
llrchild.setParent(llchild);
return root;
}
这样弄好之后,要检验是不是我们所想要的二叉树,最好的办法就是把它遍历出来。对树的遍历有三种方法,一般都是遍历左子树,再是右子树,根据根结点被遍历的顺序分为先序遍历,中序遍历,后序遍历,这里用中序遍历,具体代码如下:
/**
* 根据根结点遍历二叉树
* @param root:传入的根结点
*/
public void printTree(TreeNode root){
if (root!=null){
TreeNode Lchild = root.getLchild();
TreeNode Rchild = root.getRchild();
//递归
printTree(Lchild);
Object data = root.getObj();
System.out.print(data+"\t");
//递归
printTree(Rchild);
}
}
运行结果为:
左左左孩子
左左孩子
左左右孩子
左孩子
左右孩子
根结点
右左孩子
右孩子
右右孩子
运行结果可以证明是我们想要的二叉树。现在来总结把任意一个整型的一维数组转化为一颗线索二叉树,并且通过遍历二叉树能得到有序的数组。首先要定义遍历的规则,这里是用中序遍历的。然后是把数组的第一个元素当做二叉树的根结点,然后根据根结点的四种情况定义一个方法,即根的子左结点和子右结点都不为空;子左结点不为空,子右结点为空;子左结点为空,子右结点不为空;子左结点和子右结点都为空这四种情况,然后再用递归法,具体代码如下所示:
/**
* 根据根结点的四种情况建立二叉树
* @param num:新结点数据
* @param root:根结点
*/
public void judgeNode(int num,TreeNode root){
if (root.getLchild()==null&&root.getRchild()==null){//如果根结点的左子结点和右子结点都为空
if (num<(Integer)root.getObj()){
TreeNode node = new TreeNode(num);//创建新结点
//建立引用关系
root.setLchild(node);
node.setParent(root);
}else {
TreeNode node = new TreeNode(num);//建立新结点
//建立引用关系
root.setRchild(node);
node.setParent(root);
}
}else if (root.getLchild()!=null&&root.getRchild()==null){//根结点的左子节点不为空
if (num<(Integer)root.getObj()){
//递归
judgeNode(num,root.getLchild());
}else {
TreeNode node = new TreeNode(num);//建立新结点
//建立引用关系
root.setRchild(node);
node.setParent(root);
}
}else if (root.getLchild()==null&&root.getRchild()!=null){//根结点的右子结点不为空
if (num<(Integer)root.getObj()){
TreeNode node = new TreeNode(num);//建立新结点
//建立引用关系
root.setLchild(node);
node.setParent(root);
}else {
//递归
judgeNode(num,root.getRchild());
}
}else if (root.getLchild()!=null&&root.getRchild()!=null){//根结点的左子结点和右子结点都不为空
if (num<(Integer)root.getObj()){
//递归
judgeNode(num,root.getLchild());
}else {
//递归
judgeNode(num,root.getRchild());
}
}
}
最后再遍历数组调用此方法就可以了,代码如下:
/**
* 将数组转化为二叉树
* 定义规则:中序遍历
* @param array:传入的数组
*/
@SuppressWarnings("unused")
public TreeNode arrayToTree(int[] array){
//取数组第一个元素作为根结点
TreeNode root = new TreeNode(array[0]);
if (array==null){
throw new RuntimeException("数组为空,不能生成树!!");
}else {
for (int i=1;i<array.length;i++){
//调用方法
judgeNode(array[i],root);
}
}
return root;
}
然后随机生成一个数组检验如下:
/**
* 程序入口
* @param args
*/
public static void main(String args[]){
Random rd = new Random();
//实例化对象
Tree t = new Tree();
//随机生成数组
int[] b = new int[10];
for (int i=0;i<b.length;i++){
b[i] = rd.nextInt(100);
}
System.out.println("原有数组:");
for (int i=0;i<arr.length;i++){
System.out.print(arr[i]+"\t");
}
System.out.println();
System.out.println("生成树后,按中序遍历的数组:");
TreeNode root = arrayToTree(arr);
printTree(root);
}
运行结果:
原有数组:
3 52 26 84 93 67 79 49 4 90
生成树后,按中序遍历的数组:
3 4 26 49 52 67 79 84 90 93
至此我们已经对二叉树有了一定的了解,但是知识是无限的,学习还在继续中,总结也会陆续更新。
分享到:
相关推荐
11. 叶子结点的最小结点数:有50个叶子结点的二叉树至少有51个结点。 12. 高度为h且只有度为0和2的二叉树结点数:至少有2^h-1个结点。 13. 线索二叉树的目的:线索二叉树的引入是为了在二叉树中快速找到结点的前驱...
14. 线索二叉树性质:线索二叉树是一种逻辑结构,通过线索连接结点,物理存储上仍保持二叉链表的形式。 15. 森林与二叉树的转换:森林F转换为二叉树B后,若F中有n个非终端结点(非叶节点),那么在B中右指针域为空...
24. 中序线索二叉树的前驱结点:在中序线索二叉树中,有左孩子的结点且不是根结点的前驱结点是其左子树中最右叶结点,答案是D。 25. 线索二叉树:线索二叉树是一种存储结构,答案是B。 26. 线索二叉树的线索数:n...
- 问题4解析:在线索二叉树中,某个节点\(R\)没有左孩子当且仅当\(R\)的左标志\(ltag\)为1。 - 问题5解析:深度为\(k\)的完全二叉树至少有\(2^{k-1}\)个节点,至多有\(2^k-1\)个节点。编号最小的叶子节点序号为\(2...
**线索二叉树**是为了解决非递归遍历二叉树而引入的,通过在二叉链表中添加线索,使得在二叉树中查找前驱和后继变得容易。 **树、森林与二叉树的转换** 树与森林可以转化为二叉树,以便利用二叉树的高效操作。这些...
线索二叉树是在二叉树的基础上对空指针进行利用的一种技术,它通过对二叉树的遍历,把遍历过程中空闲的指针域充分利用起来,指向其前驱或后继结点,从而提高查找效率。 #### 六、哈夫曼树及其应用 哈夫曼树是一种...
这些知识点在计算机科学的学习和实践中是非常基础且重要的,它们涉及到树的性质、高度计算、存储结构、遍历方法、完全二叉树的特性以及线索二叉树的概念。掌握这些知识对于理解更复杂的算法和数据结构至关重要。
25. **线索二叉树的定义**:线索二叉树是一种存储结构,它添加了线索来方便遍历。 26. **...** 以上分析涵盖了题目中的主要知识点,包括树和二叉树的定义、性质、遍历方式、存储结构以及它们之间的关系。这些概念...
线索二叉树是在二叉树的结点中添加指向其前驱和后继的线索,使得可以在任何顺序下遍历树。 最后,赫夫曼树是一种特殊的二叉树,也称为最优二叉树,常用于数据压缩,通过构建最小带权路径长度的二叉树来达到压缩目的...
4. **线索二叉树**:线索二叉树是在二叉链表的基础上增加线索,以便在非递归方式下进行中序或其他遍历。T所指节点没有左子树的充要条件是其左线索为空。 5. **二叉树遍历**:在非空树上,根节点没有直接前驱。...
3. **画出二叉树bt的后序线索树(不带头结点)。** - 答案:根据后序序列`echfjigdba`,可以构建出图7.4所示的后序线索树。 **题目5:** 含有60个叶子结点的二叉树的最小高度是多少? - 答案:当二叉树为完全...
线索二叉树是一种特殊的二叉树,通过增加线索(指向父结点和前驱/后继结点的指针),使得二叉树的遍历无需栈或队列的支持,方便了对二叉树的动态操作。 哈夫曼树是一种特殊的二叉树,用于数据压缩。哈夫曼编码是...
14. **线索二叉树的性质**:线索二叉树是一种存储结构,它通过线索连接相邻结点,提供更快的查找速度。 15. **森林与二叉树转换**:由一个有n个非终端结点的森林变换得到的二叉树,有n-1个右指针域为空的结点。 ...
1.5 小结 15 习题 16 第2章 线性表 18 2.1 线性表的类型定义 18 2.1.1 线性表的定义和特点 18 2.1.2 线性表的抽象数据类型定义 18 2.2 线性表的顺序表示和实现 19 2.2.1 线性表的顺序存储表示 19 ...
3.7部分讲解了在中序线索二叉树中查找前序和后序后继的算法。前序后继可以通过判断节点的ltag和rtag属性来确定,而后序后继则需找到父节点并检查其在中序遍历中的位置。 3.11讨论了AVL树的高度和节点数的关系。AVL...
14. 先序和后序线索二叉树查找:线索二叉树用于非递归遍历,通过线索可以找到结点的前后继。 15. 中序线索二叉树查找:同样,线索可以用来在中序遍历中找到结点的前后继。 16. 孩子-兄弟链表的叶子计数和深度计算...
- 线索二叉树是在二叉树的空闲链域中存储额外信息,以便在二叉树中进行前序、中序和后序遍历。对于线索二叉树,可以快速找到一个节点的后继节点。例如,若要找到节点q的后继节点,可以通过其右线索或下一层的左线索...
线索二叉树中某结点R没有左孩子的充要条件是R.ltag=1。 深度为k的完全二叉树至少有2^k-1个结点,至多有2^k个结点,具有n个结点的完全二叉树按层序从1开始编号,则编号最小的叶子的序号是2^k-2+1。 一个高度为h的满...