【数据结构学习笔记】1:树和森林,并查集中的部分函数

[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;
}

今天老师指出了一些问题,我又改了一下更新了这篇文章。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值