用完全二叉树的概念,非递归地创建二叉树。
(1)完全二叉树
对于一颗具有n个节点的二叉树按层序编号,如果编号为i(1 <= i <= n)的节点与同样深度的满二叉树中编号为i的节点在二叉树中的位置相同,则这颗二叉树称为完全二叉树。
(2)完全二叉树的特点
<1> 叶子节点只能出现在最下面两层,且最下层的叶子节点都集中在二叉树左侧连续的位置。
<2> 如果有度为1的节点,只可能有一个,且该节点只有左孩子。
(3)完全二叉树具有如下性质。
如果对一棵有 n个结点的完全二叉树按层次次序从 1开始编号,则对任一结点 i有:
1) 若 i=1,序号为 i的结点是根;若 i>1,则其双亲结点是 i/2。
2) 若 2i< =n,序号为 i的结点的左孩子结点的序号为 2i;若 2i>n,序号为 i的结点无左孩子。
3) 若 2i +1 < = n,序号为 i的结点的右孩子结点的序号为 2i +1;若 2i + l > n,序号为 i的结点无右孩子。
注意:若2i>n,或2i + l > n,说明此时序号为i的节点是叶子节点。
根据上述(3)中的性质可知:已知某结点在数组中存储的下标可以很容易的找到它的左孩子和右孩子在数组中的下标位置,例如结点 A,它在数组中的下标为 1,根据性质可知,如果它的左、右孩子存在,则它的左孩子在数组的下标为2 * 1 = 2,它的右孩子在数组中的下标为 2 * 1 + 1 = 3。
如下图所示,二叉树中每个结点的数据和对应完全二叉树的结点编号一致。
具体实现如下:
#include <iostream>
using namespace std;
#include <deque>
#define SIZEMAX 100
typedef struct node
{
char data;
struct node *lchild;
struct node *rchild;
}BiNode, *BiTree;
// 二叉树的建立(非递归)
BiTree createBiTree()
{
BiTree s[SIZEMAX]; // 辅助空间
BiTree root = NULL; // 根节点
int i;
char ch;
cin >> i >> ch;
while (i != 0 && ch != '#') // 输入结束标志
{
BiTree p = new BiNode();
p->data = ch;
p->lchild = NULL;
p->rchild = NULL;
s[i] = p;
if (i == 1) // i为1,即根节点
root = p;
else
{
int j = i / 2;
if (i % 2 == 0)
s[j]->lchild = p; // p是编号为i的节点的左孩子
else
s[j]->rchild = p; // p是编号为i的节点的右孩子
}
cin >> i >> ch;
}
return root;
}
// 二叉树的分层打印
void PrintTreeByLevel(BiTree T)
{
if(T == NULL) return;
deque<BiTree> q;
q.push_back(T);
int curLevelNum; // 当前层的节点数
while (q.size())
{
curLevelNum = (int)q.size(); // 此处要做类型转换,因为size()返回值为size_type类型;
while(curLevelNum-- > 0) // 一直访问到当前层的最后一个节点
{
BiTree tmp = q.front();
q.pop_front();
printf("%c ", tmp->data);
if(tmp->lchild)
q.push_back(tmp->lchild);
if(tmp->rchild)
q.push_back(tmp->rchild);
}
printf("\n"); // 当前层的元素输出完毕后,换行;
}
}
int main(int argc, const char * argv[]) {
BiTree T = createBiTree();
PrintTreeByLevel(T); // 通过二叉树的分层打印,能更直观的验证创建的二叉树是否正确。
return 0;
}
补充说明:
(1)运行时只需输入每个结点的编号和数据,以输入 0和‘#’作为输入的结束标志。创建时要注意:必须先创建根结点,然后再创建其他结点。
(2)输入时,从根节点开始,按照层序的方式,依次输入对应节点的编号和数据。
(3)例如,若想创建如上图所示的二叉树,程序运行后需要输入:1a2b3c5d6f0#
结果如下图所示:(运行环境:Xcode)