说到二叉树的创建,我们一般会想到用递归的方法,因为利用递归写的代码看起来很简洁,但是递归的使用也同样存在效率不够高的问题。所以这里我们要说的是如何利用前序遍历序列和中序遍历序列非递归的创建二叉树。
思想:利用两个栈实现(当然也可以用一个栈,这里针对自己的数据类型设计),一个栈s用来存放树的各个结点,另一个栈isindex用来存放第一个栈中元素对应于中序序列中的下标。首先,我们先将根结点(即前序序列中的第一个元素)及其在中序序列中相应的下标分别入栈s和isindex,并将根结点置于当前结点。然后,从前序序列中首元素开始,依次比较相邻两个元素在中序序列中对应的下标,来确定后一个元素是当前结点的左子树还是右子树,具体有以下几种情况:
1. index2 == -1 这是在中序序列中没找到前序序列中的元素,说明是遍历序列有问题,直接退出
2. index1 > index2 前序序列中后一个元素在中序序列中相对较前的位置,说明后一个元素是当前结点的左子树
3. index1 < index2 前序序列中后一个元素在中序序列中相对较后的位置,说明后一个元素是当前结点的右子树,至于是那棵右子树,还需对index2和栈isindex栈顶元素作循环比较
说到这里就有一个疑问了:为什么index2要和isindex栈顶元素比较呢?首先我们得知道isindex2里面存的是什么,前面已经说过,isindex里面存的是已经创建好的部分树的结点在中序序列中的下标,根据中序遍历的特点:中序遍历左子树,访问根节点,中序遍历右子树,我们知道,中序序列中右结点总是在左结点以及根结点的后边,即右结点在中序序列中的下标要大于左结点和根结点的下标,所以要想知道index2所对应的元素是已创建好的部分树的哪一个结点的右孩子结点,我们需要循环比较index2和栈isindex的栈顶元素的结点,如果栈顶元素较index2小,则栈s和isindex同时出栈,并将出栈结点作为当前结点,直到两栈为空或者遇到第一个比index2大的元素(即我们循环的目的就是找到最后一个比index2小的元素,这样index2所对应的元素就是找到的元素的右孩子结点),此时index2对应的元素就是当前结点的右孩子结点。
那么index1==index2这种情况有没有可能出现呢?在这里我们一般不考虑重结点的情况,所以这种情况不会出现。
变量说明:
ps 前序序列指针
is 中序序列指针
s 栈,存放树的各个结点
isindex 利用数组模拟的栈,用来存放栈s中对应元素在中序序列中的下标
index1 前序序列中前一个元素在中序序列中的下标
index2 前序序列中后一个元素的中序序列中的下标
参考代码:“
typedef char ElemType;
typedef struct btnode //二叉树的结点定义
{
ElemType data;
btnode *leftchild;
btnode *rightchild;
}BtNode,*BtTree;
//在中序序列中查找元素函数
int find (char *is,char ch)
{
if (is == NULL)
{
exit (1);
}
int i = 0;
while (is[i] != 0)
{
if (is[i] == ch)
{
return i;
}
else
{
i ++;
}
}
return -1;
}
BtNode *NiceCreatTreePI (char *ps,char *is)
{
if (NULL == ps && NULL == is)
{
return NULL;
}
int isindex[MAXSIZE] = {0}; //用数组模拟一个顺序栈 (从数组最后入栈和出栈)
for (int j = 0;j < MAXSIZE;j ++) //初始化全用-1表示,以便出栈处理
{
isindex[j] = -1;
}
int i = 0;
SeqStack s;
Init_stack (&s);
BtNode * p = BuyNode ();
p -> data = *ps;
Push (&s,p);
BtNode *child = NULL;
BtNode *tree = p;
int index1 = find (is,*ps);
isindex[i ++] = index1; //相当于进栈
int index2 = index1;
while (*(ps + 1) != 0)
{
index1 = index2;
index2 = find (is,*(ps + 1));
if (index1 == -1 || index2 == -1)
{
exit (1);
}
if (index1 > index2) //左子树
{
child = BuyNode ();
ps ++;
child -> data = *ps;
p -> leftchild = child;
p = p -> leftchild;
Push (&s,child);
isindex[i ++] = index2;
}
else //右子树
{
i --;
while (i >= 0 && index2 > isindex[i])
{
p = top (&s);
pop (&s);
isindex[i] = -1;
i --;
}
child = BuyNode ();
ps ++;
child -> data = *ps;
p -> rightchild = child;
p = p -> rightchild;
Push (&s,child);
i ++;
isindex[i ++] = index2;
}
}
return tree;
}
本文如有需要改进的地方,还请各位大神指点。