二叉树的建立可以通过带空指针的遍历序列建立,例如有如下二叉树。
其三种遍历序列分别为:
- DLR: ABDFGCEH
- LDR: BFDGACEH
- LRD: FGDBHECA
那么可以通过带空节点的前序序列AB#DF##G##C#E#H##(其中‘#’表示空节点)来创立并使用递归输入存储二叉树。
有时候需要通过两个无空节点的遍历序列来确立二叉树,例如上树中的DLR和LDR序列,这里考虑的一种方法便是将给定的前序:“ABDFGCEH” 和中序:“BFDGACEH"转化为带空节点的前序列"AB#DF##G##C#E#H##”。由此以来便可以将问题转化为带空节点的前序序列输入。而这种输入方式简单易懂,只需要考虑如何进行中间过程的转化即可。
(这里以前序和中序序列转化为前序带空节点为例)
想想根据人的思维是如何通过两个序列来确定一颗二叉树的,然后将这个思维过程加以改造形成代码即可。
- 通常我们会将前序每一个(字符串遍历)字符与中序进行查找对比。
相应地可以将中序分割成如下两部分,
而这个中序序列便可以表示成一个如下图的形式。
继续依据前序字串的下个字符,将其在中序字串也就是相应子树进行划分。
这样不断往复循环,直到形成一颗真正的二叉树。
注:有时可能会出现某一子树为空的情况,例如:
这两种情况分别对应中序序列的"ACEH" 和"BFDGA"。
至此,可以将上述过程其归结为这样几步(使用字符向量或字符串存储最终结果):
- 遍历前序字符串
- 将指针在前序中所指的字符入队
- 如果该字符在中序序列中左侧无子符或左侧字符在队中已存在:’#'入队。
- 如果该字符在中序序列中右侧字符在队中已存在:’#'入队;如果右侧无子符:标识符flag为true
- 重复步骤1~4直到将前序字串全部遍历完成
- 如果flag为true:’#'入队。
- 返回空节点的前序序列字符串。
样例代码:
//bintree为自定义二叉树类。
string bintree::decode(string dlr, string ldr)
{
bool flag = false; //标识符
unsigned int si, si2;
string str = "";
for (si = 0; si < dlr.size(); si++)
{
str += dlr[si];
si2 = ldr.find(dlr[si]);
if (si2 == 0)
str += '#';
else if (str.find(ldr[si2 - 1]) != string::npos)
str += '#';
if (si2 + 1 == ldr.size())
flag = true;
else if (str.find(ldr[si2 + 1]) != string::npos)
str += '#';
}
if (flag == true)
str += '#';
return str;
}
之后将函数返回值str按照前序空节点递归方式创建二叉树即可。