第6xx(算法设计)习题练习答案*6.22二叉树的遍历算法可写为通用形式。
例如通用的中序遍历为:void Inorder(BinTree,T,void(* visit)(DataType x)){if (T){Inorder(T->lchild,Visit);//遍历左子树Visit(T->data);//通过函数指针调用它所指的函数来访问结点Inorder(T->rchild,Visit);//遍历右子树}}其中Visit是一个函数指针,它指向形如void f(DataType x)的函数。
因此我们可以将访问结点的操作写在函数f中通过调用语句Inorder(root,f)将f的地址传递给Visit,来执行遍历操作。
请写一个打印结点数据的函数,通过调用上述算法来完成书中6.3节的中序遍历。
解:函数如下:void PrintNode(BinTree T){printf("%c",T->data);}//定义二叉树链式存储结构typedef char DataType;//定义DataType类型typedef struct node{DataType data;struct node *lchild, *rchild;//左右孩子子树}BinTNode; //结点类型typedef BinTNode *BinTree ;//二叉树类型void Inorder(BinTree T,void(* Visit)(DataType x)){if(T){Inorder(T->lchild,Visit);//遍历左子树Visit(T->data); //通过函数指针调用它所指的函数访问结点Inorder(T->rchild,Visit);//遍历右子树}}6.23以二叉链表为存储结构,分别写出求二叉树结点总数及叶子总数的算法。
解:(1)求结点数的递归定义为:若为空树,结点数为0若只有根结点,则结点数为1;否则,结点数为根结点的左子树结点数+右子树结点数+1(2)求xx数的递归定义为:若为空树,xx数为0若只有根结点,则xx数为1;否则,叶子数为根结点的左子树叶子数+右子树叶子数typedef char DataType;//定义DataType类型typedef struct node{DataType data;struct node *lchild, *rchild;//左右孩子子树}BinTNode; //结点类型typedef BinTNode *BinTree ;//二叉树类型int Node(BinTree T){//算结点数if (T->lchild==NULL)&&(T->rchild==NULL)return 1;else return Node(T->lchild)+Node(T->rchild)+1;else return 0;}int Leaf(BinTree T){ //算xx数if(T)if (T->lchild==NULL)&&(T->rchild==NULL)return 1;else return Leaf(T->lchild)+Node(T->rchild);else return 0;}6.24以二叉链表为存储结构,分别写出求二叉树高度及宽度的算法,所谓宽度是指二叉树的各层上,具有结点数最多的那一层上的结点总数。
解:(1)根据递归定义:二叉树的高度为:当为空树时,高度为0;当只有一个结点时,高度为1;其他情况:高度为max(根的左子树高度,根的右子树高度)+1int Height(BinTree T){int hl,hr;{//非空树if(t->lchild==NUll)&&(t->rchild==NULL)//只含一个根结点return 1;else {hl=height(t->lchild);//根的左子树高度hr=height(t->rchild);//根的右子树高度if (hl>=hr)return hl+1;else return h2+1;}}else return 0;}(2)要求二叉树的宽度的话,则可根据树的高度设置一个数组temp。
temp[i]用于存放第i层上的结点数(即宽度)。
在访问结点时,把相应计算该结点下一层的孩子数并存入相应数组元素中,遍历左子树后向上返回一层计算右子树的宽度,并取出最大的一个数组元素作为树的宽度。
#define M 10 //假设二叉树最多的层数int Width(BinTree T){int static n[M];//向量存放各层结点数int static i=1;int static max=0;//最大宽度if(T){if(i==1) //若是访问根结点{n[i]++; //第1层加1i++; //到第2层if(T->lchild)//若有左孩子则该层加1n[i]++;if(T->rchild)//若有右孩子则该层加1n[i]++;}else{ //访问xx结点i++; //下一层结点数if(T->lchild)n[i]++;if(T->rchild)n[i]++;}if(max<n[i])max=n[i];//取出最大值Width(T->lchild);//遍历左子树i--; //往上退一层Width(T->rchild);//遍历右子树}return max;}//算法结束6.25以二叉链表为存储结构,写一算法交换各结点的左右子树。
答:要交换各结点的左右子树,最方便的办法是用后序遍历算法,每访问一个结点时把两棵子树的指针进行交换,最后一次访问是交换根结点的子树。
void ChangeBinTree(BinTree *T){ //交换子树if(*T){ //这里以指针为参数使得交换在实参的结点上进行后序遍历BinTree temp;ChangeBinTree(&(*T)->lchild);ChangeBinTree(&(*T)->rchild);temp=(*T)->lchild;(*T)->lchild=(*T)->rchild;(*T)->rchild=temp;}}6.26以二叉链表为存储结构,写一个拷贝二叉树的算法voidCopyTree(BinTree root,BinTree *newroot),其中新树的结点是动态申请的,为什么newroot要说明为BinTree型指针的指针?解:因为调用函数只能进行值传递,当返回类型为void时,就必须把实参的地址传给函数,否则函数不会对实际参数进行任何操作,也就得不到所需结果了。
所以,newroot要说明为BinTree型指针void CopyTree(BinTree root,BinTree *newroot){ //拷贝二叉树if(root)//如果结点非空{ //按前序序列拷贝*newroot=(BinTNode *)malloc(sizeof(BinTNode));//生成新结点(*newroot)->data=root->data;//拷贝结点数据CopyTree(root->lchild,&(*newroot)->lchild);//拷贝左子树CopyTree(root->rchild,&(*newroot)->rchild);//拷贝右子树}else //如果结点为空*newroot=NULL;//将结点置空}6.27以二叉链表为存储结构,分别写出在二叉树中查找值为x的结点及求x所在结点在树中层数的算法。
解:根据上几题的算法可以得出本题的算法如下:#define M 10 //假设二叉树最多的层数BinTree SearchBTree(BinTree *T,DataType x){//以前序遍历算法查找值为x的结点if(*T){if((*T)->data==x )return *T;SearchBTree(&(*T)->lchild,x);SearchBTree(&(*T)->rchild,x);}}int InLevel(BinTree T,DataType x){int static l=0;//设一静态变量保存层数if(T){if(l==0)//若是访问根结点{l++;//第1层if(T->data==x)return l;if(T->lchild||T->rchild)l++;//若根有子树,则层数加1}else{ //访问xx结点if(T->data==x)return l;if(T->lchild||T->rchild)l++;//若该结点有子树,则层数加1else return 0;}InLevel(T->lchild,x);//遍历左子树InLevel(T->rchild,x);//遍历右子树}}6.28一棵n个结点的完全二叉树以向量作为存储结构,试写一非递归算法实现对该树的前序遍历。
解:以向量为存储结构的完全二叉树,其存储在向量中的结点其实是按层次遍历的次序存放的,可以根据课本第74页的内容设计出算法:typedef char DataType;//设结点数据类型为char#define M 100//设结点数不超过100typedef DataType BinTree[M];void Preorder(BinTree T){ //前序遍历算法int n=T[0];int p[M];//设置一队列存放结点值int i,j;for(i=1;i<=n;i++){if (i==1)//根结点j=1;else if(2*j<=n)//左子树j=2*j;else if(j%2==0&&j<n)//右兄弟j=j+1;else if(j>1)//双亲之右兄弟j=j/2+1;p[i]=T[j];//入队printf("%c",p[i]);//打印结点值}}6.29以二叉链表为存储结构,一算法对二叉树进行层次遍历(层次遍历的定义见6.13).提示:应使用队列来保存各层的结点。
答:#define M 100 //假设结点数最多为100typedef char DataType;//队列结点值类型typedef struct//定义一个队列{int front;int rear;int count;DataType data[M];}QBTree;static QBTree Q;//设一全局静态变量保存遍历结果void Levelorder(BinTree T){//层次遍历if(T){if(QueEmpty(&Q)){ //根结点及子树结点入队EnQue(&Q,T->data);if(T->lchild)EnQue(&Q,T->lchild->data);if(T->rchild)EnQue(&Q,T->rchild->data);}else{ //xx结点入队if(T->lchild)EnQue(&Q,T->lchild->data);if(T->rchild)EnQue(&Q,T->rchild->data);}Levelorder(T->lchild);//遍历左子树Levelorder(T->rchild);//遍历右子树}}6.30以二叉链表为存储结构,写一算法用括号形式(key LT,RT)打印二叉树,其中key是根结点数据,LT和RT是括号形式的左子树和右子树。