树的应用 —— 二叉树的创建
如果想要对二叉树进行操作,必须先创建一棵二叉树。
如何创建一棵二叉树呢?从二叉树的定义就可以看出,它是递归定义的(除了根,左、右子树也各是一棵二叉树),因此也可以用递归程序来创建二叉树。
递归创建二叉树有两种方法:询问法和补空法。
【1 询问法】
按照先序遍历【根左右】的顺序,每次输入节点信息后,都询问是否创建该节点的左子树,如果是,则递归创建其左子树,否则其左子树为空;询问是否创建该节点的右子树,如果是,则递归创建其右子树,否则其右子树为空。
[算法步骤]
- 输入节点信息,创建一个节点T。
- 询问是否创建T的左子树,如果是,则递归创建其左子树,否则其左子树为NULL。
- 询问是否创建T的右子树,如果是,则递归创建其右子树,否则其右子树为NULL。
[完美图解]
一棵二叉树如下图所示。
该二叉树的创建过程如下:
- 输入节点信息:A。创建节点A,如下图所示。
- 是否添加A的左孩子? (Y/N):Y。
- 输入节点信息:B。创建节点B,作为A的左孩子,如下图所示。
- 是否添加B的左孩子? (Y/N):Y。
- 输入节点信息:D。创建节点D,作为B的左孩子,如下图所示。
- 是否添加D的左孩子? (Y/N):N。
- 是否添加D的右孩子? (Y/N):N。D左右孩子均为空,如下图所示。
- 是否添加B的右孩子? (Y/N):Y。
- 输入节点信息:E。创建节点E,作为B的右孩子,如下图所示。
- 是否添加E的左孩子? (Y/N):N
- 是否添加E的右孩子? (Y/N):N。E左右孩子均为空,如下图所示。
- 是否添加A的右孩子? (Y/N):Y。
- 输入节点信息:C。创建节点C,作为A的右孩子,如下图所示。
- 是否添加C的左孩子? (Y/N):Y。
- 输入节点信息:F。创建节点F,作为C的左孩子,如下图所示。
- 是否添加F的左孩子? (Y/N):N。F的左孩子为空。
- 是否添加F的右孩子? (Y/N):Y。
- 输入节点信息:G。创建节点G,作为F的右孩子,如下图所示。
- 是否添加G的左孩子? (Y/N):N
- 是否添加G的右孩子? (Y/N):N。G左右孩子均为空,如下图所示。
- 是否添加C的右孩子? (Y/N):N。C右孩子为空,如下图所示。
- 二叉树创建完毕。
[算法代码]
void createtree(Btree &T){ //创建二叉树函数(询问法)
char check; //判断是否创建左右孩子
T = new Bnode;
cout << "请输入节点信息:" << endl; //输入根节点数据
cin >> T->data;
cout << "是否添加" << T->data << "的左孩子?(Y/N)" << endl; //询问创建T的左子树
cin >> check;
if(check == 'Y'){
createtree(T->lchild);
}
else{
T->lchild = NULL;
}
cout << "是否添加" << T->data << "的右孩子?(Y/N)" << endl; //询问创建T的右子树
cin >> check;
if(check == 'Y'){
createtree(T->rchild);
}
else{
T->rchild = NULL;
}
}
【补空法】
补空法指如果左子树或右子树为空,则用特殊字符补空,例如“#”。
然后按照先序遍历的顺序,得到先序遍历序列,根据该序列递归创建二叉树。
[算法步骤]
- 输入补空后的二叉树先序遍历序列。
- 如果ch==‘#’,则T=NULL;否则创建一个新节点T,令T->data=ch;递归创建T的左子树;递归创建T的右子树。
[完美图解]
一棵二叉树,将该二叉树补空,在孩子为空时补上特殊符号“#”,如下图所示。
二叉树补空后的先序遍历结果为ABD##E##CF#G###。【根左右】
该二叉树的创建过程如下。
- 读取先序序列的第1个字符“A”,创建一个新节点,如下图所示。然后递归创建A的左子树。
- 读取先序序列的第2个字符“B”,创建一个新节点,作为A的左子树,如下图所示。然后递归创建B的左子树。
- 读取先序序列的第3个字符“D”,创建一个新节点,作为B的左子树,如下图所示。然后递归创建D的左子树。
- 读取先序序列的第4个字符“#”,说明D的左子树为空,如下图所示。然后递归创建D的右子树。
- 读取先序序列的第5个字符“#”,说明D的右子树为空,如下图所示。然后递归创建B的右子树。
- 读取先序序列的第6个字符“E”,创建一个新节点,作为B的右子树,如下图所示。然后递归创建E的左子树。
- 读取先序序列的第7个字符“#”,说明E的左子树为空,如下图所示。然后递归创建E的右子树。
- 读取先序序列的第8个字符“#”,说明E的右子树为空,如下图所示。然后递归创建A的右子树。
- 读取先序序列的第9个字符“C”,创建一个新节点,作为A的右子树,如下图所示。然后递归创建C的左子树。
- 读取先序序列的第10个字符“F”,创建一个新节点,作为C的左子树,如下图所示。然后递归创建F的左子树。
- 读取先序序列的第11个字符“#”,说明F的左子树为空,如下图所示。然后递归创建F的右子树。
- 读取先序序列的第12个字符“G”,创建一个新节点,作为F的右子树,如下图所示。然后递归创建G的左子树。
- 读取先序序列的第13个字符“#”,说明G的左子树为空,如下图所示。然后递归创建G的右子树。
- 读取先序序列的第14个字符“#”,说明G的右子树为空,如下图所示。然后递归创建C的右子树。
- 读取先序序列的第15个字符“#”,说明C的右子树为空,如下图所示。序列读取完毕,二叉树创建成功。
[算法代码]
void Createtree(Btree &T){ //创建二叉树函数(补空法)
char ch;
cin >> ch; //二叉树补空后,按先序遍历序列输入字符
if(ch == '#'){
T = NULL; //建空树
}
else{
T = new Bnode;
T-> data = ch; //生成根节点
Createtree(T->lchild); //递归创建左子树
Createtree(T->rchild); //递归创建右子树
}
}