[1]在树的孩子兄弟链表模板类中增加下列函数成员,并验证
(1)在孩子兄弟链表模板类中增加函数成员PostRootOrder(),实现树的后根遍历。
template <class ElemType>
void ChildSiblingTree<ElemType>::PostRootOrder(ChildSiblingTreeNode<ElemType> *r,
void (*Visit)(const ElemType &)) const
// 操作结果:按后根序依次对以r为根的树的每个元素调用函数(*visit)访问
{
ChildSiblingTreeNode<ElemType> *p;
if (r != NULL) {
for (p = FirstChild(r); p != NULL; p = NextSibling(p))
PostRootOrder(p, Visit);// 依次后根序遍历根结点的每棵子树
(*Visit)(r->data); // 访问根结点
}
}
(2)在孩子兄弟链表模板类中增加函数成员Height (),求树的高度。
template <class ElemType>
int ChildSiblingTree<ElemType>::Height(ChildSiblingTreeNode<ElemType> *r) const
// 操作结果: 求以r为根的树的高
{
ChildSiblingTreeNode<ElemType> *p;
int k,max=-1;
if (r != NULL)
{
max=Height(FirstChild(r));
for (p = FirstChild(r); p != NULL; p = NextSibling(p))
{
k=Height(p);
if(k>max)
max=k;
}
}
return max+1;
}
(3)在孩子兄弟链表模板类中增加函数成员LeafCount(),统计树中叶子结点的数目
template <class ElemType>
int ChildSiblingTree<ElemType>::LeafCount(ChildSiblingTreeNode<ElemType> *r) const
// 操作结果: 求以r为根的树的叶子数
{
ChildSiblingTreeNode<ElemType> *p;
int sum=0;
if (r != NULL)
{
if(r->firstChild==NULL)
return 1;
for (p = FirstChild(r); p != NULL; p = NextSibling(p))
{
if(p->firstChild==NULL)
sum=sum+1;
else
sum=LeafCount(p)+sum;
}
}
return sum;
}
[2]树的孩子兄弟表示法验证
(1)在树的孩子兄弟链表示中,利用二叉树的相应遍历算法实现树的先根遍历和后根遍历,完成算法的设计与实行,并进行测试验证,再与原有的算法进行比较。
template <class ElemType>
void ChildSiblingTree<ElemType>::PreRootOrder(ChildSiblingTreeNode<ElemType> *r,
void (*Visit)(const ElemType &)) const
// 操作结果:按先根序依次对以r为根的树的每个元素调用函数(*visit)访问
{
if (r != NULL) {
(*Visit)(r->data); // 访问根结点
PreRootOrder(r->firstChild, Visit);//left
PreRootOrder(r->nextSibling, Visit);//right
}
}
template <class ElemType>
void ChildSiblingTree<ElemType>::PostRootOrder(ChildSiblingTreeNode<ElemType> *r,
void (*Visit)(const ElemType &)) const
// 操作结果:按后根序依次对以r为根的树的每个元素调用函数(*visit)访问
{
if (r != NULL) {
PostRootOrder(r->firstChild, Visit);//left
(*Visit)(r->data); // 访问根结点
PostRootOrder(r->nextSibling, Visit);//right
}
}
(2)在孩子兄弟链表模板类中,设计并实现相应函数,求该树指定层次的叶子数。
template <class ElemType>
int ChildSiblingTree<ElemType>::lzh3(int n) const
{
LinkQueue<ChildSiblingTreeNode<ElemType> *> q; // 定义队列对象
ChildSiblingTreeNode<ElemType> *cur=root, *p, *k1;//cur指示上一层层尾
int sum=0,index=1;
if(root!=NULL)
q.EnQueue(root);
while(!q.Empty())
{
q.DelQueue(p);
if(p->firstChild!=NULL)
{
q.EnQueue(p=p->firstChild);
for(; p->nextSibling!= NULL; p= NextSibling(p))
q.EnQueue(p->nextSibling);
}
for(k1=cur->firstChild;k1!=NULL;k1=k1->nextSibling)//看最后加入的对象是否是层尾
{
if(k1==p)//如果是
{
index++;//层次加1
if(index==n)//如果是我们要的层次
{
while(!q.Empty())//对整个队列
{
q.DelQueue(p);//依次出队
if(p!=NULL&&p->firstChild==NULL)//如果是叶子
sum++;//叶子加1
}
return sum;
}
else//不是我们要的层次,层尾也需要更新
cur=p;
}
//如果不是,什么都不做,等待下次大while()出队入队即可
}
}
return 0;
}
(3) 在孩子兄弟链表模板类中,设计并实现相应函数,求相应二叉树的高度和叶子数。
template <class ElemType>
int ChildSiblingTree<ElemType>::lzh1(ChildSiblingTreeNode<ElemType> *r) const
// 操作结果: 求以r为根的树相应二叉树的高
{
int k1,k2,max=-1;
if (r != NULL)
{
k1=lzh1(r->firstChild);
k2=lzh1(r->nextSibling);
if(k1>k2)
max=k1;
else
max=k2;
}
return max+1;
}
template <class ElemType>
int ChildSiblingTree<ElemType>::lzh2(ChildSiblingTreeNode<ElemType> *r) const
// 操作结果: 求以r为根的树相应二叉树的叶子数
{
int sum=0;
if (r != NULL)
{
if(r->firstChild==NULL && r->nextSibling==NULL)
return 1;
else
sum=sum+lzh2(r->firstChild)+lzh2(r->nextSibling);
}
return sum;
}
[3]等价类模板的验证
(1)对等价类模板中的函数成员Union()利用加权规则(将高度较低的树并入高度较高的树)进行修改,以改善等价类树的查找性能。
template <class ElemType>
int Equivalence<ElemType>::Height(int r) const
//求下标r为根的树高度
{
int s=0,maxHeight=0,p=0;
for(p=0;p<size;p++)
if(set[p].parent==r) //当p为r的孩子时
{
if(maxHeight==0) //maxHeight还没有值的话
maxHeight=Height(p); //这个值要给它
else //否则比较maxSize和临时值s=Height(p)
if(s=Height(p)>maxHeight) //如果s比maxHeight还大
maxHeight=s; //显然应给maxHeight更新
}
return maxHeight+1; //返回maxHeight+1
}
template <class ElemType>
void Equivalence<ElemType>::Union(ElemType a, ElemType b)
// 操作结果:合并a与b所在的等价类(题目所要的,由于新的Find会改变树的结构,判定高度就没有意义了,故这里用了oldFind)
{
int root1 = oldFind(a); // 查找a所在树(等价类)的根
int root2 = oldFind(b); // 查找b所在树(等价类)的根
if (root1 != root2 && root1 != -1 && root2 != -1) //-1表示找不到元素(Find方法的返回值)
{
int temp=set[root1].parent+set[root2].parent; //两个双亲加和
if(Height(root1)>Height(root2)) //root1为高树
{
set[root2].parent=root1; //使root2的根连接到root1上(root2本身的叶子已经被temp记录)
set[root1].parent=temp; //root1的根的parent域记录总节点数
}
else //root2为高树,反过来做
{
set[root1].parent=root2; //使root1的根连接到root2上(root1本身的叶子已经被temp记录)
set[root2].parent=temp; //root2的根的parent域记录总节点数
}
}
}
(2)对等价类模板中的函数成员Find()利用折叠规则来“压缩路径”,以改善等价类树的查找性能。
template <class ElemType>
int Equivalence<ElemType>::Find(ElemType e) const
// 操作结果:查找结点p所在树的根
{
int i,k,p = 0;
while (p < size && set[p].data != e) //遍历寻e
p++;
if (p == size) //如果是因为寻完而退出
throw Error("元素不存在!"); // 抛出异常,表示元素并不在集中
//否则说明元素是存在集合中的,并且此时set[p]存的就是元素e
for(i=p;set[i].parent>=0;i=set[i].parent) //从p开始向上找p的根节点的序号i
; //找到就OK,不用多做什么,至此i已经找到,树的重构尚未执行
//重构过程
if(p!=i) //p不是根
{
while(i!=set[p].parent) //从p开始向上逐层压缩(变化的p指示着要修剪重构的节点)
{
k=set[p].parent; //用局部自动变量k记录这个p的双亲,为的是一次重构后还能把p指向向上的双亲继续执行
set[p].parent=i; //直接改变其双亲为根节点i就可以了,因为重构过程总元素数目没变,i是不用动的
p=k; //把双亲还给p,为p的下一次执行做好准备
}
}
return i;
}
今天老师指出了一些问题,我又改了一下更新了这篇文章。