A[0]-B[0]) { jmin=i;jmax=A[0]; }//B有一部分在A右端的右边 else { jmin=i;jmax=i+B[0]; }//B在A左右两端之间. //以上是根据A和B不同的相对位置确定A上需要匹配的区间(与B重合的区间)的端点:jmin,jmax. for(k=0,j=jmin;j<=jmax;j++) { if(A[j]==B[j-i])k++; elsek=0; if(k>maxlen) { lps1=j-k+1;lps2=j-i-k+1;maxlen=k; } }//for }//for if(maxlen) { if(S[0]>=T[0]) { lpsS=lps1;lpsT=lps2; } else { lpsS=lps2;lpsT=lps1; }//将A,B上的位置映射回S,T上的位置 printf("LongestPublicSubstringlength:%dn",maxlen); printf("PositioninS:%d PositioninT:%dn",lpsS,lpsT); }//if elseprintf("NoRepeatingSubstring
found!n");}//Get_LPubSub分析:本题基本思路与上题同.唯一的区别是,由于A,B互不相同,因此B不仅要向右错位,而且还要向左错位,以保证不漏掉一些情况.当B相对于A的位置不同时,需要匹配的区间的计算公式也各不相同,请读者自己画图以帮助理解.本算法的时间复杂度是o(strlrn(s)*strlen(t))。第五章数组和广义表5.18voidRSh(intA[n],intk)//把数组A的元素循环右移k位,只用一个辅助存储空间{ for(i=1;i<=k;i++) if(n%i==0&&k%i==0)p=i;//求n和k的最大公约数p for(i=0;iA[6],A[6]->A[12],A[12]->A[3],A[3]->A[9],A[9]->A[0].第二条链:A[1]->A[7],A[7]->A[13],A[13]->A[4],A[4]->A[10],A[10]->A[1].第三条链:A[2]->A[8],A[8]->A[14],A[14]->A[5],A[5]->A[11],A[11]->A[2].恰好使所有元素都右移一次.虽然未经数学证明,但作者相信上述规律应该是正确的.5.19voidGet_Saddle(intA[m][n])//求矩阵A中的马鞍点{ for(i=0;i=0;i--)//按降幂次序,可能出现的最高项次数为mn Get_All(a,m,i,0);//确定并输出所有次数为i的项}//Print_Poly_DescendvoidGet_All(int*a,intm,inti,intseq)//递归求出所有和为i的m个自然数{ if(seq==maxm)Print_Nomial(a,exps);//已经求完时,输出该项 else { min=i-(m-1)*n;//当前数不能小于min if(min<0)min=0; max=n0)printf("+");//系数为正时打印加号 elseif(coef<0)printf("-");//系数为负时打印减号 if(abs(coef)!=1)printf("%d",abs(coef));//当系数的绝对值不为1时打印系数 for(i=0;i1)printf("%d",exp[i]);//系数为1时无需打印 }}//Print_Nomial分析:本算法的关键在于如何按照降幂顺序输出各项.这里采用了一个递归函数来找到所有满足和为i的m个自然数作为各变元的指数.只要先取第一个数为j,然后再找到所有满足和为i-j的m-1个自然数就行了.要注意j的取值范围必须使剩余m-1个自然数能够找到,所以不能小于i-(m-1)*maxn,也不能大于i.只要找到了一组符合条件的数,就可以在存储多项式系数的数组中确定对应的项的系数的位置,并且在系数不为0时输出对应的项.5.21voidTSMatrix_Add(TSMatrixA,TSMatrixB,TSMatrix&C)//三元组表示的稀疏矩阵加法{ C.mu=A.mu;C.nu=A.nu;C.tu=0; pa=1;pb=1;pc=1; for(x=1;x<=A.mu;x++)//对矩阵的每一行进行加法 { while(A.data[pa].iB.data[pb].j) { C.data[pc].i=x;
C.data[pc].j=B.data[pb].j; C.data[pc].e=B.data[pb].e; pb++;pc++; } else { C.data[pc].i=x; C.data[pc].j=A.data[pa].j; C.data[pc].e=A.data[pa].e pa++;pc++; } }//while while(A.data[pa]==x)//插入A中剩余的元素(第x行) { C.data[pc].i=x; C.data[pc].j=A.data[pa].j; C.data[pc].e=A.data[pa].e pa++;pc++; } while(B.data[pb]==x)//插入B中剩余的元素(第x行) { C.data[pc].i=x; C.data[pc].j=B.data[pb].j; C.data[pc].e=B.data[pb].e; pb++;pc++; } }//for C.tu=pc;}//TSMatrix_Add5.22voidTSMatrix_Addto(TSMatrix&A,TSMatrixB)//将三元组矩阵B加到A上{ for(i=1;i<=A.tu;i++) A.data[MAXSIZE-A.tu+i]=A.data[i];/把A的所有元素都移到尾部以腾出位置 pa=MAXSIZE-A.tu+1;pb=1;pc=1; for(x=1;x<=A.mu;x++)//对矩阵的每一行进行加法 { while(A.data[pa].iB.data[pb].j) { A.data[pc].i=x; A.data[pc].j=B.data[pb].j; A.data[pc].e=B.data[pb].e; pb++;pc++; } else { A.data[pc].i=x; A.data[pc].j=A.data[pa].j; A.data[pc].e=A.data[pa].e pa++;pc++; } }//while while(A.data[pa]==x)//插入A中剩余的元素(第x行) { A.data[pc].i=x; A.data[pc].j=A.data[pa].j; A.data[pc].e=A.data[pa].e pa++;pc++; } while(B.data[pb]==x)//插入B中剩余的元素(第x行) { A.data[pc].i=x; A.data[pc].j=B.data[pb].j; A.data[pc].e=B.data[pb].e; pb++;pc++; } }//for A.tu=pc; for(i=A.tu;iright)//逐次遍历每一个行链表 printf("%d%d%dn",i,p->j,p->e; }}//Print_OLMatrix5.27voidOLMatrix_Add(OLMatrix&A,OLMatrixB)//把十字链表表示的矩阵B加到A上{ for(j=1;j<=A.nu;j++)cp[j]=A.chead[j];//向量cp存储每一列当前最后一个元素的指针 for(i=1;i<=A.mu;i++) { pa=A.rhead[i];pb=B.rhead[i];pre=NULL;
while(pb) { if(pa==NULL||pa->j>pb->j)//新插入一个结点 { p=(OLNode*)malloc(sizeof(OLNode)); if(!pre)A.rhead[i]=p; elsepre->right=p; p->right=pa;pre=p; p->i=i;p->j=pb->j;p->e=pb->e;//插入行链表中 if(!A.chead[p->j]) { A.chead[p->j]=p; p->down=NULL; } else { while(cp[p->j]->down)cp[p->j]=cp[p->j]->down; p->down=cp[p->j]->down; cp[p->j]->down=p; } cp[p->j]=p;//插入列链表中 }//if elseif(pa->jj) { pre=pa; pa=pa->right; }//pa右移一步 elseif(pa->e+pb->e) { pa->e+=pb->e; pre=pa;pa=pa->right; pb=pb->right; }//直接相加 else { if(!pre)A.rhead[i]=pa->right; elsepre->right=pa->right; p=pa;pa=pa->right;//从行链表中删除 if(A.chead[p->j]==p) A.chead[p->j]=cp[p->j]=p->down; elsecp[p->j]->down=p->down;//从列链表中删除 free(p); }//else
}//while }//for}//OLMatrix_Add分析:本题的具体思想在课本中有详细的解释说明.5.28voidMPList_PianDao(MPList&L)//对广义表存储结构的多元多项式求第一变元的偏导{ for(p=L->hp->tp;p&&p->exp;pre=p,p=p->tp) { if(p->tag)Mul(p->hp,p->exp); elsep->coef*=p->exp;//把指数乘在本结点或其下属结点上 p->exp--; } pre->tp=NULL; if(p)free(p);//删除可能存在的常数项}//MPList_PianDaovoidMul(MPList&L,intx)//递归算法,对多元多项式L乘以x{ for(p=L;p;p=p->tp) { if(!p->tag)p->coef*=x; elseMul(p->hp,x); }}//Mul 5.29voidMPList_Add(MPListA,MPListB,MPList&C)//广义表存储结构的多项式相加的递归算法{ C=(MPLNode*)malloc(sizeof(MPLNode)); if(!A->tag&&!B->tag)//原子项,可直接相加 { C->coef=A->coef+B->coef; if(!C->coef) { free(C); C=NULL; } }//if elseif(A->tag&&B->tag)//两个多项式相加 { p=A;q=B;pre=NULL; while(p&&q) { if(p->exp==q->exp)
{ C=(MPLNode*)malloc(sizeof(MPLNode)); C->exp=p->exp; MPList_Add(A->hp,B->hp,C->hp); pre->tp=C;pre=C; p=p->tp;q=q->tp; } elseif(p->exp>q->exp) { C=(MPLNode*)malloc(sizeof(MPLNode)); C->exp=p->exp; C->hp=A->hp; pre->tp=C;pre=C; p=p->tp; } else { C=(MPLNode*)malloc(sizeof(MPLNode)); C->exp=q->exp; C->hp=B->hp; pre->tp=C;pre=C; q=q->tp; } }//while while(p) { C=(MPLNode*)malloc(sizeof(MPLNode)); C->exp=p->exp; C->hp=p->hp; pre->tp=C;pre=C; p=p->tp; } while(q) { C=(MPLNode*)malloc(sizeof(MPLNode)); C->exp=q->exp; C->hp=q->hp; pre->tp=C;pre=C; q=q->tp; }//将其同次项分别相加得到新的多项式,原理见第二章多项式相加一题 }//elseif elseif(A->tag&&!B->tag)//多项式和常数项相加 { x=B->coef;
for(p=A;p->tp->tp;p=p->tp); if(p->tp->exp==0)p->tp->coef+=x;//当多项式中含有常数项时,加上常数项 if(!p->tp->coef) { free(p->tp); p->tp=NULL; } else { q=(MPLNode*)malloc(sizeof(MPLNode)); q->coef=x;q->exp=0; q->tag=0;q->tp=NULL; p->tp=q; }//否则新建常数项,下同 }//elseif else { x=A->coef; for(p=B;p->tp->tp;p=p->tp); if(p->tp->exp==0)p->tp->coef+=x; if(!p->tp->coef) { free(p->tp); p->tp=NULL; } else { q=(MPLNode*)malloc(sizeof(MPLNode)); q->coef=x;q->exp=0; q->tag=0;q->tp=NULL; p->tp=q; } }//else}//MPList_Add5.30intGList_Getdeph(GListL)//求广义表深度的递归算法{ if(!L->tag)return0;//原子深度为0 elseif(!L)return1;//空表深度为1 m=GList_Getdeph(L->ptr.hp)+1; n=GList_Getdeph(L->ptr.tp); returnm>n?m:n;}//GList_Getdeph5.31voidGList_Copy(GListA,GList&B)//复制广义表的递归算法
{ if(!A->tag)//当结点为原子时,直接复制 { B->tag=0; B->atom=A->atom; } else//当结点为子表时 { B->tag=1; if(A->ptr.hp) { B->ptr.hp=malloc(sizeof(GLNode)); GList_Copy(A->ptr.hp,B->ptr.hp); }//复制表头 if(A->ptr.tp) { B->ptr.tp=malloc(sizeof(GLNode)); GList_Copy(A->ptr.tp,B->ptr.tp); }//复制表尾 }//else}//GList_Copy5.32intGList_Equal(GListA,GListB)//判断广义表A和B是否相等,是则返回1,否则返回0{//广义表相等可分三种情况: if(!A&&!B)return1;//空表是相等的 if(!A->tag&&!B->tag&&A->atom==B->atom)return1;//原子的值相等 if(A->tag&&B->tag) if(GList_Equal(A->ptr.hp,B->ptr.hp)&&GList_Equal(A->ptr.tp,B->ptr.tp)) return1;//表头表尾都相等 return0;}//GList_Equal5.33voidGList_PrintElem(GListA,intlayer)//递归输出广义表的原子及其所在层次,layer表示当前层次{ if(!A)return; if(!A->tag)printf("%d%dn",A->atom,layer); else { GList_PrintElem(A->ptr.hp,layer+1); GList_PrintElem(A->ptr.tp,layer);//注意尾表与原表是同一层次 }}//GList_PrintElem5.34
voidGList_Reverse(GListA)//递归逆转广义表A{ GLNode*ptr[MAX_SIZE]; if(A->tag&&A->ptr.tp)//当A不为原子且表尾非空时才需逆转 { for(i=0,p=A;p;p=p->ptr.tp,i++) { if(p->ptr.hp)GList_Reverse(p->ptr.hp); //逆转各子表 ptr[i]=p->ptr.hp; } for(p=A;p;p=p->ptr.tp) //重新按逆序排列各子表的顺序 p->ptr.hp=ptr[--i]; }}//GList_Reverse5.35StatusCreate_GList(GList&L)//根据输入创建广义表L,并返回指针{ scanf("%c",&ch); if(ch=="") { L=NULL; scanf("%c",&ch); if(ch!=")")returnERROR; returnOK; } L=(GList)malloc(sizeof(GLNode)); L->tag=1; if(isalphabet(ch))//输入是字母 { p=(GList)malloc(sizeof(GLNode));//建原子型表头 p->tag=0;p->atom=ch; L->ptr.hp=p; } elseif(ch=="(")Create_GList(L->ptr.hp);//建子表型表头 elsereturnERROR; scanf("%c",&ch); if(ch==")")L->ptr.tp=NULL; elseif(ch==",")Create_GList(L->ptr.tp);//建表尾 elsereturnERROR; returnOK;}//Create_GList分析:本题思路见书后解答.5.36voidGList_PrintList(GListA)//按标准形式输出广义表
{ if(!A)printf("()");//空表 elseif(!A->tag)printf("%d",A->atom);//原子 else { printf("("); for(p=A;p;p=p->ptr.tp) { GList_PrintList(p->ptr.hp); if(p->ptr.tp)printf(","); //只有当表尾非空时才需要打印逗号 } printf(")"); }//else}//GList_PrintList5.37voidGList_DelElem(GList&A,intx)//从广义表A中删除所有值为x的原子{ if(A&&A->ptr.hp) { if(A->ptr.hp->tag)GList_DelElem(A->ptr.hp,x); elseif(!A->ptr.hp->tag&&A->ptr.hp->atom==x) { q=A; A=A->ptr.tp; //删去元素值为x的表头 free(q); GList_DelElem(A,x); } } if(A&&A->ptr.tp)GList_DelElem(A->ptr.tp,x);}//GList_DelElem5.39voidGList_PrintElem_LOrder(GListA)//按层序输出广义表A中的所有元素{ InitQueue(Q); for(p=L;p;p=p->ptr.tp)EnQueue(Q,p); while(!QueueEmpty(Q)) { DeQueue(Q,r); if(!r->tag)printf("%d",r->atom); else for(r=r->ptr.hp;r;r=r->ptr.tp)EnQueue(Q,r); }//while}//GList_PrintElem_LOrder分析:层序遍历的问题,一般都是借助队列来完成的,
每次从队头取出一个元素的同时把它下一层的孩子插入队尾.这是层序遍历的基本思想.第六章树和二叉树6.33intIs_Descendant_C(intu,intv)//在孩子存储结构上判断u是否v的子孙,是则返回1,否则返回0{ if(u==v)return1; else { if(L[v]) if(Is_Descendant(u,L[v]))return1; if(R[v]) if(Is_Descendant(u,R[v]))return1;//这是个递归算法 } return0;}//Is_Descendant_C6.34intIs_Descendant_P(intu,intv)//在双亲存储结构上判断u是否v的子孙,是则返回1,否则返回0{ for(p=u;p!=v&&p;p=T[p]); if(p==v)return1; elsereturn0;}//Is_Descendant_P6.35这一题根本不需要写什么算法,见书后注释:两个整数的值是相等的.6.36intBitree_Sim(BitreeB1,BitreeB2)//判断两棵树是否相似的递归算法{ if(!B1&&!B2)return1; elseif(B1&&B2&&Bitree_Sim(B1->lchild,B2->lchild)&&Bitree_Sim(B1->rchild,B2->rchild)) return1; elsereturn0;}//Bitree_Sim6.37voidPreOrder_Nonrecursive(BitreeT)//先序遍历二叉树的非递归算法{ InitStack(S); Push(S,T);//根指针进栈 while(!StackEmpty(S)) { while(Gettop(S,p)&&p) { visit(p->data); push(S,p->lchild); }//向左走到尽头 pop(S,p); if(!StackEmpty(S)) { pop(S,p); push(S,p->rchild);//向右一步
} }//while}//PreOrder_Nonrecursive6.38typedefstruct{ BTNode*ptr; enum{0,1,2}mark; }PMType;//有mark域的结点指针类型voidPostOrder_Stack(BiTreeT)//后续遍历二叉树的非递归算法,用栈{ PMTypea; InitStack(S);//S的元素为PMType类型 Push(S,{T,0});//根结点入栈 while(!StackEmpty(S)) { Pop(S,a); switch(a.mark) { case0: Push(S,{a.ptr,1});//修改mark域 if(a.ptr->lchild)Push(S,{a.ptr->lchild,0});//访问左子树 break; case1: Push(S,{a.ptr,2});//修改mark域 if(a.ptr->rchild)Push(S,{a.ptr->rchild,0});//访问右子树 break; case2: visit(a.ptr);//访问结点,返回 } }//while}//PostOrder_Stack分析:为了区分两次过栈的不同处理方式,在堆栈中增加一个mark域,mark=0表示刚刚访问此结点,mark=1表示左子树处理结束返回,mark=2表示右子树处理结束返回.每次根据栈顶元素的mark域值决定做何种动作.6.39typedefstruct{ intdata; EBTNode*lchild; EBTNode*rchild; EBTNode*parent; enum{0,1,2}mark; }EBTNode,EBitree;//有mark域和双亲指针域的二叉树结点类型voidPostOrder_Nonrecursive(EBitreeT)//后序遍历二叉树的非递归算法,不用栈{ p=T; while(p) switch(p->mark) { case0: p->mark=1; if(p->lchild)p=p->lchild;//访问左子树 break; case1: p->mark=2; if(p->rchild)p=p->rchild;//访问右子树
break; case2: visit(p); p->mark=0;//恢复mark值 p=p->parent;//返回双亲结点 }}//PostOrder_Nonrecursive分析:本题思路与上一题完全相同,只不过结点的mark值是储存在结点中的,而不是暂存在堆栈中,所以访问完毕后要将mark域恢复为0,以备下一次遍历.6.40typedefstruct{ intdata; PBTNode*lchild; PBTNode*rchild; PBTNode*parent; }PBTNode,PBitree;//有双亲指针域的二叉树结点类型voidInorder_Nonrecursive(PBitreeT)//不设栈非递归遍历有双亲指针的二叉树{ p=T; while(p->lchild)p=p->lchild;//向左走到尽头 while(p) { visit(p); if(p->rchild)//寻找中序后继:当有右子树时 { p=p->rchild; while(p->lchild)p=p->lchild;//后继就是在右子树中向左走到尽头 } elseif(p->parent->lchild==p)p=p->parent;//当自己是双亲的左孩子时后继就是双亲 else { p=p->parent; while(p->parent&&p->parent->rchild==p)p=p->parent; p=p->parent; }//当自己是双亲的右孩子时后继就是向上返回直到遇到自己是在其左子树中的祖先 }//while}//Inorder_Nonrecursive6.41intc,k;//这里把k和计数器c作为全局变量处理voidGet_PreSeq(BitreeT)//求先序序列为k的结点的值{ if(T) { c++;//每访问一个子树的根都会使前序序号计数器加1 if(c==k) { printf("Valueis%dn",T->data); exit(1); } else { Get_PreSeq(T->lchild);//在左子树中查找 Get_PreSeq(T->rchild);//在右子树中查找 } }//if}//Get_PreSeq
main(){ ... scanf("%d",&k); c=0;//在主函数中调用前,要给计数器赋初值0 Get_PreSeq(T,k); ...}//main6.42intLeafCount_BiTree(BitreeT)//求二叉树中叶子结点的数目{ if(!T)return0;//空树没有叶子 elseif(!T->lchild&&!T->rchild)return1;//叶子结点 elsereturnLeaf_Count(T->lchild)+Leaf_Count(T->rchild);//左子树的叶子数加上右子树的叶子数}//LeafCount_BiTree6.43voidBitree_Revolute(BitreeT)//交换所有结点的左右子树{ T->lchild<->T->rchild;//交换左右子树 if(T->lchild)Bitree_Revolute(T->lchild); if(T->rchild)Bitree_Revolute(T->rchild);//左右子树再分别交换各自的左右子树}//Bitree_Revolute6.44intGet_Sub_Depth(BitreeT,intx)//求二叉树中以值为x的结点为根的子树深度{ if(T->data==x) { printf("%dn",Get_Depth(T));//找到了值为x的结点,求其深度 exit1; } else { if(T->lchild)Get_Sub_Depth(T->lchild,x); if(T->rchild)Get_Sub_Depth(T->rchild,x);//在左右子树中继续寻找 }}//Get_Sub_DepthintGet_Depth(BitreeT)//求子树深度的递归算法{ if(!T)return0; else { m=Get_Depth(T->lchild); n=Get_Depth(T->rchild); return(m>n?m:n)+1; }}//Get_Depth6.45voidDel_Sub_x(BitreeT,intx)//删除所有以元素x为根的子树{ if(T->data==x)Del_Sub(T);//删除该子树 else { if(T->lchild)Del_Sub_x(T->lchild,x); if(T->rchild)Del_Sub_x(T->rchild,x);//在左右子树中继续查找
}//else}//Del_Sub_xvoidDel_Sub(BitreeT)//删除子树T{ if(T->lchild)Del_Sub(T->lchild); if(T->rchild)Del_Sub(T->rchild); free(T);}//Del_Sub6.46voidBitree_Copy_Nonrecursive(BitreeT,Bitree&U)//非递归复制二叉树{ InitStack(S1);InitStack(S2); push(S1,T);//根指针进栈 U=(BTNode*)malloc(sizeof(BTNode)); U->data=T->data; q=U;push(S2,U); while(!StackEmpty(S)) { while(Gettop(S1,p)&&p) { q->lchild=(BTNode*)malloc(sizeof(BTNode)); q=q->lchild;q->data=p->data; push(S1,p->lchild); push(S2,q); }//向左走到尽头 pop(S1,p); pop(S2,q); if(!StackEmpty(S1)) { pop(S1,p);pop(S2,q); q->rchild=(BTNode*)malloc(sizeof(BTNode)); q=q->rchild;q->data=p->data; push(S1,p->rchild);//向右一步 push(S2,q); } }//while}//BiTree_Copy_Nonrecursive分析:本题的算法系从6.37改写而来.6.47voidLayerOrder(BitreeT)//层序遍历二叉树{ InitQueue(Q);//建立工作队列 EnQueue(Q,T); while(!QueueEmpty(Q)) { DeQueue(Q,p); visit(p); if(p->lchild)EnQueue(Q,p->lchild); if(p->rchild)EnQueue(Q,p->rchild); }}//LayerOrder6.48intfound=FALSE;Bitree*Find_Near_Ancient(BitreeT,Bitreep,Bitreeq)//求二叉树T中结点p和q的最近共同祖先
{ Bitreepathp[100],pathq[100]//设立两个辅助数组暂存从根到p,q的路径 Findpath(T,p,pathp,0); found=FALSE; Findpath(T,q,pathq,0);//求从根到p,q的路径放在pathp和pathq中 for(i=0;pathp[i]==pathq[i]&&pathp[i];i++);//查找两条路径上最后一个相同结点 returnpathp[--i];}//Find_Near_AncientvoidFindpath(BitreeT,Bitreep,Bitreepath[],inti)//求从T到p路径的递归算法{ if(T==p) { found=TRUE; return;//找到 } path[i]=T;//当前结点存入路径 if(T->lchild)Findpath(T->lchild,p,path,i+1);//在左子树中继续寻找 if(T->rchild&&!found)Findpath(T->rchild,p,path,i+1);//在右子树中继续寻找 if(!found)path[i]=NULL;//回溯}//Findpath6.49intIsFull_Bitree(BitreeT)//判断二叉树是否完全二叉树,是则返回1,否则返回0{ InitQueue(Q); flag=0; EnQueue(Q,T);//建立工作队列 while(!QueueEmpty(Q)) { DeQueue(Q,p); if(!p)flag=1; elseif(flag)return0; else { EnQueue(Q,p->lchild); EnQueue(Q,p->rchild);//不管孩子是否为空,都入队列 } }//while return1;}//IsFull_Bitree分析:该问题可以通过层序遍历的方法来解决.与6.47相比,作了一个修改,不管当前结点是否有左右孩子,都入队列.这样当树为完全二叉树时,遍历时得到是一个连续的不包含空指针的序列.反之,则序列中会含有空指针.6.50StatusCreateBitree_Triplet(Bitree&T)//输入三元组建立二叉树{ if(getchar()!="^")returnERROR; T=(BTNode*)malloc(sizeof(BTNode)); p=T;p->data=getchar(); getchar();//滤去多余字符 InitQueue(Q); EnQueue(Q,T); while((parent=getchar())!="^"&&(child=getchar())&&(side=getchar())) { while(QueueHead(Q)!=parent&&!QueueEmpty(Q))DeQueue(Q,e); if(QueueEmpty(Q))returnERROR;//未按层序输入
p=QueueHead(Q); q=(BTNode*)malloc(sizeof(BTNode)); if(side=="L")p->lchild=q; elseif(side=="R")p->rchild=q; elsereturnERROR;//格式不正确 q->data=child; EnQueue(Q,q); } returnOK;}//CreateBitree_Triplet6.51StatusPrint_Expression(BitreeT)//按标准形式输出以二叉树存储的表达式{ if(T->data是字母)printf("%c",T->data); elseif(T->data是操作符) { if(!T->lchild||!T->rchild)returnERROR;//格式错误 if(T->lchild->data是操作符&&T->lchild->data优先级低于T->data) { printf("("); if(!Print_Expression(T->lchild))returnERROR; printf(")"); }//注意在什么情况下要加括号 elseif(!Print_Expression(T->lchild))returnERROR; if(T->rchild->data是操作符&&T->rchild->data优先级低于T->data) { printf("("); if(!Print_Expression(T->rchild))returnERROR; printf(")"); } elseif(!Print_Expression(T->rchild))returnERROR; } elsereturnERROR;//非法字符 returnOK;}//Print_Expression6.52typedefstruct{ BTNodenode; intlayer; }BTNRecord;//包含结点所在层次的记录类型intFanMao(BitreeT)//求一棵二叉树的"繁茂度"{ intcountd;//count数组存放每一层的结点数 InitQueue(Q);//Q的元素为BTNRecord类型 EnQueue(Q,{T,0}); while(!QueueEmpty(Q)) { DeQueue(Q,r); count[r.layer]++; if(r.node->lchild)EnQueue(Q,{r.node->lchild,r.layer+1}); if(r.node->rchild)EnQueue(Q,{r.node->rchild,r.layer+1}); }//利用层序遍历来统计各层的结点数 h=r.layer;//最后一个队列元素所在层就是树的高度 for(maxn=count[0],i=1;count[i];i++) if(count[i]>maxn)maxn=count[i];//求层最大结点数 return
h*maxn;}//FanMao分析:如果不允许使用辅助数组,就必须在遍历的同时求出层最大结点数,形式上会复杂一些,你能写出来吗?6.53intmaxh;StatusPrintpath_MaxdepthS1(BitreeT)//求深度等于树高度减一的最靠左的结点{ Bitreepathd; maxh=Get_Depth(T);//Get_Depth函数见6.44 if(maxh<2)returnERROR;//无符合条件结点 Find_h(T,1); returnOK;}//Printpath_MaxdepthS1voidFind_h(BitreeT,inth)//寻找深度为maxh-1的结点{ path[h]=T; if(h==maxh-1) { for(i=1;path[i];i++)printf("%c",path[i]->data); exit;//打印输出路径 } else { if(T->lchild)Find_h(T->lchild,h+1); if(T->rchild)Find_h(T->rchild,h+1); } path[h]=NULL;//回溯}//Find_h6.54StatusCreateBitree_SqList(Bitree&T,SqListsa)//根据顺序存储结构建立二叉链表{ Bitreeptr[sa.last+1];//该数组储存与sa中各结点对应的树指针 if(!sa.last) { T=NULL;//空树 return; } ptr[1]=(BTNode*)malloc(sizeof(BTNode)); ptr[1]->data=sa.elem[1];//建立树根 T=ptr[1]; for(i=2;i<=sa.last;i++) { if(!sa.elem[i])returnERROR;//顺序错误 ptr[i]=(BTNode*)malloc(sizeof(BTNode)); ptr[i]->data=sa.elem[i]; j=i/2;//找到结点i的双亲j if(i-j*2)ptr[j]->rchild=ptr[i];//i是j的右孩子 elseptr[j]->lchild=ptr[i];//i是j的左孩子 } returnOK;}//CreateBitree_SqList6.55intDescNum(BitreeT)//求树结点T的子孙总数填入DescNum域中,并返回该数{ if(!T)return
-1; elsed=(DescNum(T->lchild)+DescNum(T->rchild)+2);//计算公式 T->DescNum=d; returnd;}//DescNum分析:该算法时间复杂度为O(n),n为树结点总数.注意:为了能用一个统一的公式计算子孙数目,所以当T为空指针时,要返回-1而不是0.6.56BTNode*PreOrder_Next(BTNode*p)//在先序后继线索二叉树中查找结点p的先序后继,并返回指针{ if(p->lchild)returnp->lchild; elsereturnp->rchild;}//PreOrder_Next分析:总觉得不会这么简单.是不是哪儿理解错了?6.57BitreePostOrder_Next(Bitreep)//在后序后继线索二叉树中查找结点p的后序后继,并返回指针{ if(p->rtag)returnp->rchild;//p有后继线索 elseif(!p->parent)returnNULL;//p是根结点 elseif(p==p->parent->rchild)returnp->parent;//p是右孩子 elseif(p==p->parent->lchild&&p->parent->rtag) returnp->parent;//p是左孩子且双亲没有右孩子 else//p是左孩子且双亲有右孩子 { q=p->parent->rchild; while(q->lchild||!q->rtag) { if(q->lchild)q=q->lchild; elseq=q->rchild; }//从p的双亲的右孩子向下走到底 returnq; }//else}//PostOrder_Next6.58StatusInsert_BiThrTree(BiThrTree&T,BiThrTree&p,BiThrTree&x)//在中序线索二叉树T的结点p下插入子树x{ if(p->ltag)//x作为p的左子树 { s=p->lchild;//s为p的前驱 p->ltag=Link; p->lchild=x; q=x; while(q->lchild&&!q->ltag)q=q->lchild; q->lchild=s;//找到子树中的最左结点,并修改其前驱指向s x->rtag=Thread; x->rchild=p;//x的后继指向p } elseif(p->rtag)//x作为p的右子树 { s=p->rchild;//s为p的后继 p->rtag=Link; p->rchild=x;
q=x; while(q->lchild&&!q->ltag)q=q->lchild; q->lchild=p;//找到子树中的最左结点,并修改其前驱指向p x->rtag=Thread; x->rchild=s;//x的后继指向p的后继 } else//x作为p的左子树,p的左子树作为x的右子树 { s=p->lchild;t=s; while(t->lchild&&!t->ltag)t=t->lchild; u=t->lchild;//找到p的左子树的最左节点t和前驱u p->lchild=x; x->rtag=Link; x->rchild=s;//x作为p的左子树,p的左子树s作为x的右子树 t->lchild=x; q=x; while(q->lchild&&!q->ltag)q=q->lchild; q->lchild=u;//找到子树中的最左结点,并修改其前驱指向u } returnOK;}//Insert_BiThrTree6.59voidPrint_CSTree(CSTreeT)//输出孩子兄弟链表表示的树T的各边{ for(child=T->firstchild;child;child=child->nextsib) { printf("(%c,%c),",T->data,child->data); Print_CSTree(child); }}//Print_CSTree6.60intLeafCount_CSTree(CSTreeT)//求孩子兄弟链表表示的树T的叶子数目{ if(!T->firstchild)return1;//叶子结点 else { count=0; for(child=T->firstchild;child;child=child->nextsib) count+=LeafCount_CSTree(child); returncount;//各子树的叶子数之和 }}//LeafCount_CSTree6.61intGetDegree_CSTree(CSTreeT)//求孩子兄弟链表表示的树T的度{ if(!T->firstchild)return0;//空树 else { degree=0; for(p=T->firstchild;p;p=p->nextsib)degree++;//本结点的度 for(p=T->firstchild;p;p=p->nextsib) { d=GetDegree_CSTree(p); if(d>degree)degree=d;//孩子结点的度的最大值 } return
degree; }//else}//GetDegree_CSTree6.62intGetDepth_CSTree(CSTreeT)//求孩子兄弟链表表示的树T的深度{ if(!T)return0;//空树 else { for(maxd=0,p=T->firstchild;p;p=p->nextsib) if((d=GetDepth_CSTree(p))>maxd)maxd=d;//子树的最大深度 returnmaxd+1; }}//GetDepth_CSTree6.63intGetDepth_CTree(CTreeA)//求孩子链表表示的树A的深度{ returnSubDepth(A.r);}//GetDepth_CTreeintSubDepth(intT)//求子树T的深度{ if(!A.nodes[T].firstchild)return1; for(sd=1,p=A.nodes[T].firstchild;p;p=p->next) if((d=SubDepth(p->child))>sd)sd=d; returnsd+1;}//SubDepth6.64intGetDepth_PTree(PTreeT)//求双亲表表示的树T的深度{ maxdep=0; for(i=0;i=0;j=T.nodes[j].parent)dep++;//求每一个结点的深度 if(dep>maxdep)maxdep=dep; } returnmaxdep;}//GetDepth_PTree6.65charPred,Ind;//假设前序序列和中序序列已经分别储存在数组Pre和In中BitreeBuild_Sub(intPre_Start,intPre_End,intIn_Start,intIn_End)//由子树的前序和中序序列建立其二叉链表{ sroot=(BTNode*)malloc(sizeof(BTNode));//建根 sroot->data=Pre[Pre_Start]; for(i=In_Start;In[i]!=sroot->data;i++);//在中序序列中查找子树根 leftlen=i-In_Start; rightlen=In_End-i;//计算左右子树的大小 if(leftlen) { lroot=Build_Sub(Pre_Start+1,Pre_Start+leftlen,In_Start,In_Start+leftlen-1); sroot->lchild=lroot; }//建左子树,注意参数表的计算 if(rightlen) { rroot=Build_Sub(Pre_End-rightlen+1,Pre_End,In_End-rightlen+1,In_End);
sroot->rchild=rroot; }//建右子树,注意参数表的计算 returnsroot;//返回子树根}//Build_Submain(){ ... Build_Sub(1,n,1,n);//初始调用参数,n为树结点总数 ...}分析:本算法利用了这样一个性质,即一棵子树在前序和中序序列中所占的位置总是连续的.因此,就可以用起始下标和终止下标来确定一棵子树.Pre_Start,Pre_End,In_Start和In_End分别指示子树在前序子序列里的起始下标,终止下标,和在中序子序列里的起始和终止下标.6.66typedefstruct{ CSNode*ptr; CSNode*lastchild; }NodeMsg;//结点的指针和其最后一个孩子的指针StatusBuild_CSTree_PTree(PTreeT)//由树T的双亲表构造其孩子兄弟链表{ NodeMsgTree[MAXSIZE]; for(i=0;idata=T.node[i].data;//建结点 if(T.nodes[i].parent>=0)//不是树根 { j=T.nodes[i].parent;//本算法要求双亲表必须是按层序存储 if(!(Tree[j].lastchild))//双亲当前还没有孩子 Tree[j].ptr->firstchild=Tree[i].ptr;//成为双亲的第一个孩子 else//双亲已经有了孩子 Tree[j].lastchild->nextsib=Tree[i].ptr;//成为双亲最后一个孩子的下一个兄弟 Tree[j].lastchild=Tree[i].ptr;//成为双亲的最后一个孩子 }//if }//for}//Build_CSTree_PTree6.67typedefstruct{ chardata; CSNode*ptr; CSNode*lastchild; }NodeInfo;//结点数据,结点指针和最后一个孩子的指针StatusCreateCSTree_Duplet(CSTree&T)//输入二元组建立树的孩子兄弟链表{ NodeInfoTreed; n=1;k=0; if(getchar()!="^")returnERROR;//未按格式输入 if((c=getchar())=="^")T=NULL;//空树 Tree[0].ptr=(CSNode*)malloc(sizeof(CSNode)); Tree[0].data=c; Tree[0].ptr->data=c; while((p=getchar())!="^"&&(c=getchar())!="^") { Tree[n].ptr=(CSNode*)malloc(sizeof(CSNode)); Tree[n].data=c;
Tree[n].ptr->data=c; for(k=0;Tree[k].data!=p;k++);//查找当前边的双亲结点 if(Tree[k].data!=p)returnERROR;//未找到:未按层序输入 r=Tree[k].ptr; if(!r->firstchild) r->firstchild=Tree[n].ptr; elseTree[k].lastchild->nextsib=Tree[n].ptr; Tree[k].lastchild=Tree[n].ptr;//这一段含义同上一题 n++; }//while returnOK;}//CreateCSTree_Duplet6.68StatusCreateCSTree_Degree(charnode[],intdegree[])//由结点的层序序列和各结点的度构造树的孩子兄弟链表{ CSNode*ptr[MAXSIZE];//树结点指针的辅助存储 ptr[0]=(CSNode*)malloc(sizeof(CSNode)); i=0;k=1;//i为当前结点序号,k为当前孩子的序号 while(node[i]) { ptr[i]->data=node[i]; d=degree[i]; if(d) { ptr[k]=(CSNode*)malloc(sizeof(CSNode));//k为当前孩子的序号 ptr[i]->firstchild=ptr[k];//建立i与第一个孩子k之间的联系 for(j=2;j<=d;j++) { ptr[k]=(CSNode*)malloc(sizeof(CSNode)); ptr[k-1]->nextsib=ptr[k];//当结点的度大于1时,为其孩子建立兄弟链表 k++; }//for ptr[k-1]->nextsib=NULL; }//if i++; }//while}//CreateCSTree_Degree6.69voidPrint_BiTree(BiTreeT,inti)//按树状打印输出二叉树的元素,i表示结点所在层次,初次调用时i=0{ if(T->rchild)Print_BiTree(T->rchild,i+1); for(j=1;j<=i;j++)printf("");//打印i个空格以表示出层次 printf("%cn",T->data);//打印T元素,换行 if(T->lchild)Print_BiTree(T->rchild,i+1);}//Print_BiTree分析:该递归算法实际上是带层次信息的中序遍历,只不过按照题目要求,顺序为先右后左.6.70StatusCreateBiTree_GList(BiTree&T)//由广义表形式的输入建立二叉链表{ c=getchar(); if(c=="#")T=NULL;//空子树 else {
T=(CSNode*)malloc(sizeof(CSNode)); T->data=c; if(getchar()!="(")returnERROR; if(!CreateBiTree_GList(pl))returnERROR; T->lchild=pl; if(getchar()!=",")returnERROR; if(!CreateBiTree_GList(pr))returnERROR; T->rchild=pr; if(getchar()!=")")returnERROR;//这些语句是为了保证输入符合A(B,C)的格式 } returnOK;}//CreateBiTree_GList6.71voidPrint_CSTree(CSTreeT,inti)//按凹入表形式打印输出树的元素,i表示结点所在层次,初次调用时i=0{ for(j=1;j<=i;j++)printf("");//留出i个空格以表现出层次 printf("%cn",T->data);//打印元素,换行 for(p=T->firstchild;p;p=p->nextsib) Print_CSTree(p,i+1);//打印子树}//Print_CSTree6.72voidPrint_CTree(inte,inti)//按凹入表形式打印输出树的元素,i表示结点所在层次{ for(j=1;j<=i;j++)printf("");//留出i个空格以表现出层次 printf("%cn",T.nodes[e].data);//打印元素,换行 for(p=T.nodes[e].firstchild;p;p=p->next) Print_CSTree(p->child,i+1);//打印子树}//Print_CSTreemain(){ ... Print_CTree(T.r,0);//初次调用时i=0 ...}//main6.73charc;//全局变量,指示当前字符StatusCreateCSTree_GList(CSTree&T)//由广义表形式的输入建立孩子兄弟链表{ c=getchar(); T=(CSNode*)malloc(sizeof(CSNode)); T->data=c; if((c=getchar())=="(")//非叶结点 { if(!CreateCSTree_GList(fc))returnERROR;//建第一个孩子 T->firstchild=fc; for(p=fc;c==",";p->nextsib=nc,p=nc)//建兄弟链 if(!CreateCSTree_GList(nc))returnERROR; p->nextsib=NULL; if((c=getchar())!=")")returnERROR;//括号不配对 } elseT->firtchild=NULL;//叶子结点 returnOK;}//CreateBiTree_GList分析:书后给出了两个间接递归的算法,事实上合成一个算法在形式上可能更好一些.本算法另一个改进之处在于加入了广义表格式是否合法的判断
.6.74voidPrintGlist_CSTree(CSTreeT)//按广义表形式输出孩子兄弟链表表示的树{ printf("%c",T->data); if(T->firstchild)//非叶结点 { printf("("); for(p=T->firstchild;p;p=p->nextsib) { PrintGlist_CSTree(p); if(p->nextsib)printf(",");//最后一个孩子后面不需要加逗号 } printf(")"); }//if}//PrintGlist_CSTree6.75charc;intpos=0;//pos是全局变量,指示已经分配到了哪个结点StatusCreateCTree_GList(CTree&T,int&i)//由广义表形式的输入建立孩子链表{ c=getchar(); T.nodes[pos].data=c; i=pos++;//i是局部变量,指示当前正在处理的子树根 if((c=getchar())=="(")//非叶结点 { CreateCTree_GList(); p=(CTBox*)malloc(sizeof(CTBox)); T.nodes[i].firstchild=p; p->child=pos;//建立孩子链的头 for(;c==",";p=p->next)//建立孩子链 { CreateCTree_GList(T,j);//用j返回分配得到的子树根位置 p->child=j; p->next=(CTBox*)malloc(sizeof(CTBox)); } p->next=NULL; if((c=getchar())!=")")returnERROR;//括号不配对 }//if elseT.nodes[i].firtchild=NULL;//叶子结点 returnOK;}//CreateBiTree_GList分析:该算法中,pos变量起着"分配"结点在表中的位置的作用,是按先序序列从上向下分配,因此树根T.r一定等于0,而最终的pos值就是结点数T.n.6.76voidPrintGList_CTree(CTreeT,inti)//按广义表形式输出孩子链表表示的树{ printf("%c",T.nodes[i].data); if(T.nodes[i].firstchild)//非叶结点 { printf("("); for(p=T->firstchild;p;p=p->nextsib) { PrintGlist_CSTree(T,p->child); if(p->nextsib)printf(",");//最后一个孩子后面不需要加逗号
} printf(")"); }//if}//PrintGlist_CTree第七章图7.14StatusBuild_AdjList(ALGraph&G)//输入有向图的顶点数,边数,顶点信息和边的信息建立邻接表{ InitALGraph(G); scanf("%d",&v); if(v<0)returnERROR;//顶点数不能为负 G.vexnum=v; scanf("%d",&a); if(a<0)returnERROR;//边数不能为负 G.arcnum=a; for(m=0;mnextarc;q=q->nextarc); q->nextarc=p; } p->adjvex=j;p->nextarc=NULL; }//while returnOK;}//Build_AdjList7.15//本题中的图G均为有向无权图,其余情况容易由此写出StatusInsert_Vex(MGraph&G,charv)//在邻接矩阵表示的图G上插入顶点v{ if(G.vexnum+1)>MAX_VERTEX_NUMreturnINFEASIBLE; G.vexs[++G.vexnum]=v; returnOK;}//Insert_VexStatusInsert_Arc(MGraph&G,charv,charw)//在邻接矩阵表示的图G上插入边(v,w){ if((i=LocateVex(G,v))<0)returnERROR; if((j=LocateVex(G,w))<0)returnERROR; if(i==j)returnERROR; if(!G.arcs[i][j].adj) { G.arcs[i][j].adj=1; G.arcnum++; } returnOK;}//Insert_ArcStatusDelete_Vex(MGraph&G,charv)//在邻接矩阵表示的图G上删除顶点
v{ n=G.vexnum; if((m=LocateVex(G,v))<0)returnERROR; G.vexs[m]<->G.vexs[n];//将待删除顶点交换到最后一个顶点 for(i=0;iadjvex=j;p->nextarc=NULL; if(!G.vertices[i].firstarc)G.vertices[i].firstarc=p; else { for(q=G.vertices[i].firstarc;q->q->nextarc;q=q->nextarc) if(q->adjvex==j)returnERROR;//边已经存在 q->nextarc=p; } G.arcnum++; returnOK;}//Insert_Arc7.17//为节省篇幅,本题只给出较为复杂的Delete_Vex算法.其余算法请自行写出.StatusDelete_Vex(OLGraph&G,charv)//在十字链表表示的图G上删除顶点v{ if((m=LocateVex(G,v))<0)returnERROR; n=G.vexnum; for(i=0;itailvex==m)//如果待删除的边是头链上的第一个结点 { q=G.xlist[i].firstin; G.xlist[i].firstin=q->hlink;
free(q);G.arcnum--; } else//否则 { for(p=G.xlist[i].firstin;p&&p->hlink->tailvex!=m;p=p->hlink); if(p) { q=p->hlink; p->hlink=q->hlink; free(q);G.arcnum--; } }//else }//for for(i=0;iheadvex==m)//如果待删除的边是尾链上的第一个结点 { q=G.xlist[i].firstout; G.xlist[i].firstout=q->tlink; free(q);G.arcnum--; } else//否则 { for(p=G.xlist[i].firstout;p&&p->tlink->headvex!=m;p=p->tlink); if(p) { q=p->tlink; p->tlink=q->tlink; free(q);G.arcnum--; } }//else }//for for(i=m;ihlink) p->headvex--; for(p=G.xlist[i].firstout;p;p=p->tlink) p->tailvex--;//修改各链中的顶点序号 } G.vexnum--; returnOK;}//Delete_Vex7.18//为节省篇幅,本题只给出Delete_Arc算法.其余算法请自行写出.StatusDelete_Arc(AMLGraph&G,charv,charw)////在邻接多重表表示的图G上删除边(v,w){ if((i=LocateVex(G,v))<0)returnERROR; if((j=LocateVex(G,w))<0)returnERROR; if(G.adjmulist[i].firstedge->jvex==j) G.adjmulist[i].firstedge=G.adjmulist[i].firstedge->ilink; else { for(p=G.adjmulist[i].firstedge;p&&p->ilink->jvex!=j;p=p->ilink); if(!p)returnERROR;//未找到 p->ilink=p->ilink->ilink; }//在i链表中删除该边
if(G.adjmulist[j].firstedge->ivex==i) G.adjmulist[j].firstedge=G.adjmulist[j].firstedge->jlink; else { for(p=G.adjmulist[j].firstedge;p&&p->jlink->ivex!=i;p=p->jlink); if(!p)returnERROR;//未找到 q=p->jlink; p->jlink=q->jlink; free(q); }//在i链表中删除该边 G.arcnum--; returnOK;}//Delete_Arc7.19StatusBuild_AdjMulist(AMLGraph&G)//输入有向图的顶点数,边数,顶点信息和边的信息建立邻接多重表{ InitAMLGraph(G); scanf("%d",&v); if(v<0)returnERROR;//顶点数不能为负 G.vexnum=v; scanf(%d",&a); if(a<0)returnERROR;//边数不能为负 G.arcnum=a; for(m=0;mivex=i;p->jvex=j; p->ilink=NULL;p->jlink=NULL;//边结点赋初值 if(!G.adjmulist[i].firstedge)G.adjmulist[i].firstedge=p; else { q=G.adjmulist[i].firstedge; while(q) { r=q; if(q->ivex==i)q=q->ilink; elseq=q->jlink; } if(r->ivex==i)r->ilink=p;//注意i值既可能出现在边结点的ivex域中, elser->jlink=p;//又可能出现在边结点的jvex域中 }//else//插入i链表尾部 if(!G.adjmulist[j].firstedge)G.adjmulist[j].firstedge=p; else { q=G.adjmulist[i].firstedge; while(q) { r=q; if(q->jvex==j)q=q->jlink; else
q=q->ilnk; } if(r->jvex==j)r->jlink=p; elser->ilink=p; }//else//插入j链表尾部 }//for returnOK;}//Build_AdjList7.20intPass_MGraph(MGraphG)//判断一个邻接矩阵存储的有向图是不是可传递的,是则返回1,否则返回0{ for(x=0;xnextarc) { y=p->adjvex; for(q=G.vertices[y].firstarc;q;q=q->nextarc) { z=q->adjvex; if(z!=x&&!is_adj(G,x,z))return0; }//for }//for}//Pass_ALGraphintis_adj(ALGraphG,intm,intn)//判断有向图G中是否存在边(m,n),是则返回1,否则返回0{ for(p=G.vertices[m].firstarc;p;p=p->nextarc) if(p->adjvex==n)return1; return0;}//is_adj7.22intvisited[MAXSIZE];//指示顶点是否在当前路径上intexist_path_DFS(ALGraphG,inti,intj)//深度优先判断有向图G中顶点i到顶点j是否有路径,是则返回1,否则返回0{ if(i==j)return1;//i就是j else { visited[i]=1; for(p=G.vertices[i].firstarc;p;p=p->nextarc) { k=p->adjvex; if(!visited[k]&&exist_path(k,j))return1;//i下游的顶点到j有路径
}//for }//else}//exist_path_DFS7.23intexist_path_BFS(ALGraphG,inti,intj)//广度优先判断有向图G中顶点i到顶点j是否有路径,是则返回1,否则返回0{ intvisited[MAXSIZE]; InitQueue(Q); EnQueue(Q,i); while(!QueueEmpty(Q)) { DeQueue(Q,u); visited[u]=1; for(p=G.vertices[i].firstarc;p;p=p->nextarc) { k=p->adjvex; if(k==j)return1; if(!visited[k])EnQueue(Q,k); }//for }//while return0;}//exist_path_BFS7.24voidSTraverse_Nonrecursive(GraphG)//非递归遍历强连通图G{ intvisited[MAXSIZE]; InitStack(S); Push(S,GetVex(S,1));//将第一个顶点入栈 visit(1); visited=1; while(!StackEmpty(S)) { while(Gettop(S,i)&&i) { j=FirstAdjVex(G,i); if(j&&!visited[j]) { visit(j); visited[j]=1; Push(S,j);//向左走到尽头 } }//while if(!StackEmpty(S)) { Pop(S,j); Gettop(S,i); k=NextAdjVex(G,i,j);//向右走一步 if(k&&!visited[k]) { visit(k); visited[k]=1; Push(S,k); } }//if }//while}//Straverse_Nonrecursive
分析:本算法的基本思想与二叉树的先序遍历非递归算法相同,请参考6.37.由于是强连通图,所以从第一个结点出发一定能够访问到所有结点.7.25见书后解答.7.26StatusTopoNo(ALGraphG)//按照题目要求顺序重排有向图中的顶点{ intnew[MAXSIZE],indegree[MAXSIZE];//储存结点的新序号 n=G.vexnum; FindInDegree(G,indegree); InitStack(S); for(i=1;inextarc) { k=p->adjvex; if(!(--indegree[k]))Push(S,k); }//for }//while if(count0) { visited[i]=1; for(p=G.vertices[i].firstarc;p;p=p->nextarc) { l=p->adjvex; if(!visited[l]) if(exist_path_len(G,l,j,k-1))return1;//剩余路径长度减一 }//for visited[i]=0;//本题允许曾经被访问过的结点出现在另一条路径中 }//else return0;//没找到}//exist_path_len7.28intpath[MAXSIZE],visited[MAXSIZE];//暂存遍历过程中的路径intFind_All_Path(ALGraphG,intu,intv,intk)//求有向图G中顶点u到v之间的所有简单路径,k表示当前路径长度{ path[k]=u;//加入当前路径中
visited[u]=1; if(u==v)//找到了一条简单路径 { printf("Foundonepath!n"); for(i=0;path[i];i++)printf("%d",path[i]);//打印输出 } else for(p=G.vertices[u].firstarc;p;p=p->nextarc) { l=p->adjvex; if(!visited[l])Find_All_Path(G,l,v,k+1);//继续寻找 } visited[u]=0; path[k]=0;//回溯}//Find_All_Pathmain(){ ... Find_All_Path(G,u,v,0);//在主函数中初次调用,k值应为0 ...}//main7.29intGetPathNum_Len(ALGraphG,inti,intj,intlen)//求邻接表方式存储的有向图G的顶点i到j之间长度为len的简单路径条数{ if(i==j&&len==0)return1;//找到了一条路径,且长度符合要求 elseif(len>0) { sum=0;//sum表示通过本结点的路径数 visited[i]=1; for(p=G.vertices[i].firstarc;p;p=p->nextarc) { l=p->adjvex; if(!visited[l]) sum+=GetPathNum_Len(G,l,j,len-1)//剩余路径长度减一 }//for visited[i]=0;//本题允许曾经被访问过的结点出现在另一条路径中 }//else returnsum;}//GetPathNum_Len7.30intvisited[MAXSIZE];intpath[MAXSIZE];//暂存当前路径intcycles[MAXSIZE][MAXSIZE];//储存发现的回路所包含的结点intthiscycle[MAXSIZE];//储存当前发现的一个回路intcycount=0;//已发现的回路个数voidGetAllCycle(ALGraphG)//求有向图中所有的简单回路{ for(v=0;vnextarc) { w=p->adjvex; if(!visited[w])DFS(G,w,k+1); else//发现了一条回路 { for(i=0;path[i]!=w;i++);//找到回路的起点 for(j=0;path[i+j];i++)thiscycle[j]=path[i+j];//把回路复制下来 if(!exist_cycle())cycles[cycount++]=thiscycle;//如果该回路尚未被记录过,就添加到记录中 for(i=0;i=0;i--)//第二次逆向的深度优先遍历 { v=finished(i); if(!visited[v]) { printf("n");//不同的强连通分量在不同的行输出 DFS2(G,v); } }//for}//Get_SGraphvoidDFS1(OLGraphG,intv)//第一次深度优先遍历的算法{ visited[v]=1; for(p=G.xlist[v].firstout;p;p=p->tlink) { w=p->headvex; if(!visited[w])DFS1(G,w); }//for finished[++count]=v;//在第一次遍历中建立finished数组}//DFS1voidDFS2(OLGraphG,intv)//第二次逆向的深度优先遍历的算法{ visited[v]=1; printf("%d",v);//在第二次遍历中输出结点序号 for(p=G.xlist[v].firstin;p;p=p->hlink) { w=p->tailvex; if(!visited[w])DFS2(G,w); }//for}//DFS2分析:求有向图的强连通分量的算法的时间复杂度和深度优先遍历相同,也为O(n+e).7.32voidForest_Prim(ALGraphG,intk,CSTree&T)//从顶点k出发,构造邻接表结构的有向图G的最小生成森林T,用孩子兄弟链表存储{ for(j=0;jnextarc) if(p->adjvex==k)closedge[j].lowcost=p->cost; }//if closedge[k].lowcost=0; for(i=1;inextarc) if(p->costadjvex].lowcost) closedge[p->adjvex]={k,p->cost}; }//if elseForest_Prim(G,k);//对另外一个连通分量执行算法 }//for}//Forest_PrimvoidAddto_Forest(CSTree&T,inti,intj)//把边(i,j)添加到孩子兄弟链表表示的树T中{ p=Locate(T,i);//找到结点i对应的指针p,过程略 q=(CSTNode*)malloc(sizeof(CSTNode)); q->data=j; if(!p)//起始顶点不属于森林中已有的任何一棵树 { p=(CSTNode*)malloc(sizeof(CSTNode)); p->data=i; for(r=T;r->nextsib;r=r->nextsib); r->nextsib=p; p->firstchild=q; }//作为新树插入到最右侧 elseif(!p->firstchild)//双亲还没有孩子 p->firstchild=q;//作为双亲的第一个孩子 else//双亲已经有了孩子 { for(r=p->firstchild;r->nextsib;r=r->nextsib); r->nextsib=q;//作为双亲最后一个孩子的兄弟 }}//Addto_Forestmain(){ ... T=(CSTNode*)malloc(sizeof(CSTNode));//建立树根 T->data=1; Forest_Prim(G,1,T); ...}//main分析:这个算法是在Prim算法的基础上添加了非连通图支持和孩子兄弟链表构建模块而得到的,其时间复杂度为O(n^2).7.33typedefstruct{ intvex;//结点序号 intecno;//结点所属的连通分量号 }VexInfo;VexInfovexs[MAXSIZE];//记录结点所属连通分量号的数组voidInit_VexInfo(VexInfo&vexs[],intvexnum)//初始化{ for(i=0;i1) { GetMinEdge(EdgeSet,u,v);//选出最短边 if(!is_ec(vexs,u,v))//u和v属于不同连通分量 { Addto_CSTree(T,u,v);//加入到生成树中 merge_ec(vexs,vexs[u].ecno,vexs[v].ecno);//合并连通分量 ecnum--; } DelMinEdge(EdgeSet,u,v);//从边集中删除 }//while}//MinSpanTree_KruscalvoidAddto_CSTree(CSTree&T,inti,intj)//把边(i,j)添加到孩子兄弟链表表示的树T中{ p=Locate(T,i);//找到结点i对应的指针p,过程略 q=(CSTNode*)malloc(sizeof(CSTNode)); q->data=j; if(!p->firstchild)//双亲还没有孩子 p->firstchild=q;//作为双亲的第一个孩子 else//双亲已经有了孩子 { for(r=p->firstchild;r->nextsib;r=r->nextsib); r->nextsib=q;//作为双亲最后一个孩子的兄弟 }}//Addto_CSTree分析:本算法使用一维结构体变量数组来表示等价类,每个连通分量所包含的所有结点属于一个等价类.在这个结构上实现了初始化,判断元素是否等价(两个结点是否属于同一个连通分量),合并等价类(连通分量)的操作.7.34StatusTopoSeq(ALGraphG,intnew[])//按照题目要求给有向无环图的结点重新编号,并存入数组new中{ intindegree[MAXSIZE];//本算法就是拓扑排序 FindIndegree(G,indegree); Initstack(S); for(i=0;inextarc) { k=p->adjvex; if(!(--indegree[k]))Push(S,k);
} }//while if(countnextarc) { w=p->adjvex; if(!visited[w])DFS(G,w); }}//DFS7.36voidFill_MPL(ALGraph&G)//为有向无环图G添加MPL域{ FindIndegree(G,indegree); for(i=0;inextarc) { j=p->adjvex; if(G.vertices[j].MPL==0)k=Get_MPL(G,j); if(k>max)max=k;//求其直接后继顶点MPL的最大者 } G.vertices[i]=max+1;//再加一,就是当前顶点的MPL returnmax+1; }//else}//Get_MPL7.37intmaxlen,path[MAXSIZE];//数组path用于存储当前路径intmlp[MAXSIZE];//数组mlp用于存储已发现的最长路径voidGet_Longest_Path(ALGraphG)//求一个有向无环图中最长的路径
{ maxlen=0; FindIndegree(G,indegree); for(i=0;imaxlen&&!G.vertices[i].firstarc)//新的最长路径 { for(j=0;j<=len;j++)mlp[j]=path[j];//保存下来 maxlen=len; } else { for(p=G.vertices[i].firstarc;p;p=p->nextarc) { j=p->adjvex; if(!visited[j])DFS(G,j,len+1); } }//else path[i]=0; visited[i]=0;}//DFS7.38voidNiBoLan_DAG(ALGraphG)//输出有向无环图形式表示的表达式的逆波兰式{ FindIndegree(G,indegree); for(i=0;iadjvex); PrintNiBoLan_DAG(G,p->nexarc->adjvex); printf("%c",c); }}//PrintNiBoLan_DAG7.39voidPrintNiBoLan_Bitree(BitreeT)//在二叉链表存储结构上重做上一题{ if(T->lchild)
PrintNiBoLan_Bitree(T->lchild); if(T->rchild)PrintNiBoLan_Bitree(T->rchild); printf("%c",T->data);}//PrintNiBoLan_Bitree7.40intEvaluate_DAG(ALGraphG)//给有向无环图表示的表达式求值{ FindIndegree(G,indegree); for(i=0;iadjvex); v2=Evaluate_imp(G,p->nextarc->adjvex); returncalculate(v1,G.vertices[i].optr,v2); }}//Evaluate_imp分析:本题中,邻接表的vertices向量的元素类型修改如下:struct{ enumtag{NUM,OPTR}; union{ intvalue; charoptr; }; ArcNode*firstarc; }Elemtype;7.41voidCritical_Path(ALGraphG)//利用深度优先遍历求网的关键路径{ FindIndegree(G,indegree); for(i=0;inextarc) { dut=*p->info; if(ve[i]+dut>ve[p->adjvex]) ve[p->adjvex]=ve[i]+dut; DFS1(G,p->adjvex); }}//DFS1voidDFS2(ALGraphG,inti){ if(!G.vertices[i].firstarc)
vl[i]=ve[i]; else { for(p=G.vertices[i].firstarc;p;p=p->nextarc) { DFS2(G,p->adjvex); dut=*p->info; if(vl[p->adjvex]-dutadjvex]-dut; } }//else}//DFS27.42voidALGraph_DIJ(ALGraphG,intv0,Pathmatrix&P,ShortestPathTable&D)//在邻接表存储结构上实现迪杰斯特拉算法{ for(v=0;vnextarc) D[p->adjvex]=*p->info;//给D数组赋初值 for(v=0;vnextarc) { w=p->adjvex; if(!final[w]&&(min+(*p->info)size; f=p+n-1;//f指向空闲块底部 if((p-1)->tag&&(f+1)->tag)//回收块上下邻块均为占用块 { p->tag=0;f->tag=0; f->uplink=p; if(!pav) { p->llink=p; p->rlink=p; } else { q=pav->llink; p->llink=q;p->rlink=pav; q->rlink=p;pav->llink=p; } pav=p; }//if elseif(!(p-1)->tag&&(f+1)->tag)//上邻块为空闲块 { q=(p-1)->uplink; q->size+=n; f->uplink=q; f->tag=0; } elseif((p-1)->tag&&!(f+1)->tag)//下邻块为空闲块 { q=f+1; s=q->llink;t=q->rlink; p->llink=s;p->rlink=t; s->rlink=p;t->llink=p; p->size+=q->size; (q+q->size-1)->uplink=p; p->tag=0; } else//上下邻块均为空闲块 { s=(p-1)->uplink; t=f+1; s->size+=n+t->size; t->llink->rlink=t->rlink; t->rlink->llink=t->llink; (t+t->size-1)->uplink=s; }}//Free_BT,该算法在课本里有详细的描述.8.14voidFree_BS(freelist&avail,char*addr,intn)//伙伴系统的空闲块回收算法{ buddy=addr%(2*n)?(addr-n):(addr+n);//求回收块的伙伴地址
addr->tag=0; addr->kval=n; for(i=0;avail[i].nodesizellink=addr; addr->rlink=addr; avail[i].first=addr;//作为唯一一个该大小的空闲块 } else { for(p=avail[i].first;p!=buddy&&p!=avail[i].first;p=p->rlink);//寻找伙伴 if(p==buddy)//伙伴为空闲块,此时进行合并 { if(p->rlink==p)avail[i].first=NULL;//伙伴是此大小的唯一空闲块 else { p->llink->rlink=p->rlink; p->rlink->llink=p->llink; }//从空闲块链中删去伙伴 new=addr>p?p:addr;//合并后的新块首址 Free_BS(avail,new,2*n);//递归地回收新块 }//if else//伙伴为占用块,此时插入空闲块链头部 { q=p->rlink; p->rlink=addr;addr->llink=p; q->llink=addr;addr->rlink=q; } }//else}//Free_BS8.15FBList*MakeList(char*highbound,char*lowbound)//把堆结构存储的的所有空闲块链接成可利用空间表,并返回表头指针{ p=lowbound; while(p->tag&&p=highbound)returnNULL;//没有空闲块 head=p; for(q=p;ptag) { q->next=p; q=p; }//if p->next=NULL; returnhead;//返回头指针}//MakeList8.16voidMem_Contract(Heap&H)//对堆H执行存储紧缩{ q=MemStart;j=0; for(i=0;itag)
{ s=H.list[i].length; p=H.list[i].stadr; for(k=0;kkey;i++); if(i>ST.length||ST.elem[i].keyhigh)return0;//查找不到时返回0 mid=(low+high)/2; if(ST.elem[mid].key==key)returnmid; elseif(ST.elem[mid].key>key) returnSearch_Bin_Recursive(ST,key,low,mid-1); elsereturnSearch_Bin_Recursive(ST,key,mid+1,high); }}//Search_Bin_Recursive9.27intLocate_Bin(SSTableST,intkey)//折半查找,返回小于或等于待查元素的最后一个结点号{ int*r; r=ST.elem; if(key=r[ST.length].key)returnST.length; low=1;high=ST.length; while(low<=high) { mid=(low+high)/2; if(key>=r[mid].key&&keyL.idx[L.blknum].maxkey)returnERROR;//超过最大元素 low=1;high=L.blknum; found=0; while(low<=high&&!found)//折半查找记录所在块号mid { mid=(low+high)/2; if(key<=L.idx[mid].maxkey&&key>L.idx[mid-1].maxkey) found=1; elseif(key>L.idx[mid].maxkey) low=mid+1; elsehigh=mid-1; } i=L.idx[mid].firstloc;//块的下界 j=i+blksize-1;//块的上界 temp=L.elem[i-1];//保存相邻元素 L.elem[i-1]=key;//设置监视哨 for(k=j;L.elem[k]!=key;k--);//顺序查找 L.elem[i-1]=temp;//恢复元素 if(kdata==key)returnL.t; elseif(L.t->data>key) for(p=L.h,i=1;p->data!=key;p=p->next,i++); else for(p=L.t,i=L.tpos;p->data!=key;p=p->next,i++); L.t=p;//更新t指针 returnp;}//Search_CSList分析:由于题目中假定每次查找都是成功的,所以本算法中没有关于查找失败的处理.由微积分可得,在等概率情况下,平均查找长度约为n/3.9.30typedefstruct{ DLNode*pre; int
data; DLNode*next; }DLNode;typedefstruct{ DLNode*sp; intlength; }DSList;//供查找的双向循环链表类型DLNode*Search_DSList(DSList&L,intkey)//在有序双向循环链表存储结构上的查找算法,假定每次查找都成功{ p=L.sp; if(p->data>key) { while(p->data>key)p=p->pre; L.sp=p; } elseif(p->datadatanext; L.sp=p; } returnp;}//Search_DSList分析:本题的平均查找长度与上一题相同,也是n/3.9.31intlast=0,flag=1;intIs_BSTree(BitreeT)//判断二叉树T是否二叉排序树,是则返回1,否则返回0{ if(T->lchild&&flag)Is_BSTree(T->lchild); if(T->datadata; if(T->rchild&&flag)Is_BSTree(T->rchild); returnflag;}//Is_BSTree9.32intlast=0;voidMaxLT_MinGT(BiTreeT,intx)//找到二叉排序树T中小于x的最大元素和大于x的最小元素{ if(T->lchild)MaxLT_MinGT(T->lchild,x);//本算法仍是借助中序遍历来实现 if(lastdata>=x)//找到了小于x的最大元素 printf("a=%dn",last); if(last<=x&&T->data>x)//找到了大于x的最小元素 printf("b=%dn",T->data); last=T->data; if(T->rchild)MaxLT_MinGT(T->rchild,x);}//MaxLT_MinGT9.33voidPrint_NLT(BiTreeT,intx)//从大到小输出二叉排序树T中所有不小于x的元素{ if(T->rchild)Print_NLT(T->rchild,x); if(T->datadata); if(T->lchild)Print_NLT(T->lchild,x);//先右后左的中序遍历}//Print_NLT9.34
voidDelete_NLT(BiTree&T,intx)//删除二叉排序树T中所有不小于x元素结点,并释放空间{ if(T->rchild)Delete_NLT(T->rchild,x); if(T->datalchild; free(q);//如果树根不小于x,则删除树根,并以左子树的根作为新的树根 if(T)Delete_NLT(T,x);//继续在左子树中执行算法}//Delete_NLT9.35voidPrint_Between(BiThrTreeT,inta,intb)//打印输出后继线索二叉排序树T中所有大于a且小于b的元素{ p=T; while(!p->ltag)p=p->lchild;//找到最小元素 while(p&&p->datadata>a)printf("%dn",p->data);//输出符合条件的元素 if(p->rtag)p=p->rtag; else { p=p->rchild; while(!p->ltag)p=p->lchild; }//转到中序后继 }//while}//Print_Between9.36voidBSTree_Insert_Key(BiThrTree&T,intx)//在后继线索二叉排序树T中插入元素x{ if(T->datartag)//T没有右子树时,作为右孩子插入 { p=T->rchild; q=(BiThrNode*)malloc(sizeof(BiThrNode)); q->data=x; T->rchild=q;T->rtag=0; q->rtag=1;q->rchild=p;//修改原线索 } elseBSTree_Insert_Key(T->rchild,x);//T有右子树时,插入右子树中 }//if elseif(T->data>x)//插入到左子树中 { if(!T->lchild)//T没有左子树时,作为左孩子插入 { q=(BiThrNode*)malloc(sizeof(BiThrNode)); q->data=x; T->lchild=q; q->rtag=1;q->rchild=T;//修改自身的线索 } elseBSTree_Insert_Key(T->lchild,x);//T有左子树时,插入左子树中 }//if}//BSTree_Insert_Key9.37StatusBSTree_Delete_key(BiThrTree&T,intx)//在后继线索二叉排序树T中删除元素
x{ BTNode*pre,*ptr,*suc;//ptr为x所在结点,pre和suc分别指向ptr的前驱和后继 p=T;last=NULL;//last始终指向当前结点p的前一个(前驱) while(!p->ltag)p=p->lchild;//找到中序起始元素 while(p) { if(p->data==x)//找到了元素x结点 { pre=last; ptr=p; } elseif(last&&last->data==x)suc=p;//找到了x的后继 if(p->rtag)p=p->rtag; else { p=p->rchild; while(!p->ltag)p=p->lchild; }//转到中序后继 last=p; }//while//借助中序遍历找到元素x及其前驱和后继结点 if(!ptr)returnERROR;//未找到待删结点 Delete_BSTree(ptr);//删除x结点 if(pre&&pre->rtag) pre->rchild=suc;//修改线索 returnOK;}//BSTree_Delete_keyvoidDelete_BSTree(BiThrTree&T)//课本上给出的删除二叉排序树的子树T的算法,按照线索二叉树的结构作了一些改动{ q=T; if(!T->ltag&&T->rtag)//结点无右子树,此时只需重接其左子树 T=T->lchild; elseif(T->ltag&&!T->rtag)//结点无左子树,此时只需重接其右子树 T=T->rchild; elseif(!T->ltag&&!T->rtag)//结点既有左子树又有右子树 { p=T;r=T->lchild; while(!r->rtag) { s=r; r=r->rchild;//找到结点的前驱r和r的双亲s } T->data=r->data;//用r代替T结点 if(s!=T) s->rchild=r->lchild; elses->lchild=r->lchild;//重接r的左子树到其双亲结点上 q=r; }//else free(q);//删除结点}//Delete_BSTree分析:本算法采用了先求出x结点的前驱和后继,再删除x结点的办法,这样修改线索时会比较简单,直接让前驱的线索指向后继就行了.如果试图在删除x结点的同时修改线索,则问题反而复杂化了.9.38
voidBSTree_Merge(BiTree&T,BiTree&S)//把二叉排序树S合并到T中{ if(S->lchild)BSTree_Merge(T,S->lchild); if(S->rchild)BSTree_Merge(T,S->rchild);//合并子树 Insert_Key(T,S);//插入元素}//BSTree_MergevoidInsert_Node(Bitree&T,BTNode*S)//把树结点S插入到T的合适位置上{ if(S->data>T->data) { if(!T->rchild)T->rchild=S; elseInsert_Node(T->rchild,S); } elseif(S->datadata) { if(!T->lchild)T->lchild=S; elseInsert_Node(T->lchild,S); } S->lchild=NULL;//插入的新结点必须和原来的左右子树断绝关系 S->rchild=NULL;//否则会导致树结构的混乱}//Insert_Node分析:这是一个与课本上不同的插入算法.在合并过程中,并不释放或新建任何结点,而是采取修改指针的方式来完成合并.这样,就必须按照后序序列把一棵树中的元素逐个连接到另一棵树上,否则将会导致树的结构的混乱.9.39voidBSTree_Split(BiTree&T,BiTree&A,BiTree&B,intx)//把二叉排序树T分裂为两棵二叉排序树A和B,其中A的元素全部小于等于x,B的元素全部大于x{ if(T->lchild)BSTree_Split(T->lchild,A,B,x); if(T->rchild)BSTree_Split(T->rchild,A,B,x);//分裂左右子树 if(T->data<=x)Insert_Node(A,T); elseInsert_Node(B,T);//将元素结点插入合适的树中}//BSTree_SplitvoidInsert_Node(Bitree&T,BTNode*S)//把树结点S插入到T的合适位置上{ if(!T)T=S;//考虑到刚开始分裂时树A和树B为空的情况 elseif(S->data>T->data)//其余部分与上一题同 { if(!T->rchild)T->rchild=S; elseInsert_Node(T->rchild,S); } elseif(S->datadata) { if(!T->lchild)T->lchild=S; elseInsert_Node(T->lchild,S); } S->lchild=NULL; S->rchild=NULL; }//Insert_Key9.40typedefstruct{ intdata; intbf; intlsize;//lsize域表示该结点的左子树的结点总数加1 BlcNode
*lchild,*rchild; }BlcNode,*BlcTree;//含lsize域的平衡二叉排序树类型BTNode*Locate_BlcTree(BlcTreeT,intk)//在含lsize域的平衡二叉排序树T中确定第k小的结点指针{ if(!T)returnNULL;//k小于1或大于树结点总数 if(T->lsize==k)returnT;//就是这个结点 elseif(T->lsize>k) returnLocate_BlcTree(T->lchild,k);//在左子树中寻找 elsereturnLocate_BlcTree(T->rchild,k-T->lsize);//在右子树中寻找,注意要修改k的值}//Locate_BlcTree9.41typedefstruct{ enum{LEAF,BRANCH}tag;//结点类型标识 intkeynum; BPLinkparent;//双亲指针 intkey[MAXCHILD];//关键字 union{ BPLinkchild[MAXCHILD];//非叶结点的孩子指针 struct{ rectype*info[MAXCHILD];//叶子结点的信息指针 BPNode*next;//指向下一个叶子结点的链接 }leaf; } }BPNode,*BPLink,*BPTree;//B+树及其结点类型StatusBPTree_Search(BPTreeT,intkey,BPNode*ptr,intpos)//B+树中按关键字随机查找的算法,返回包含关键字的叶子结点的指针ptr以及关键字在叶子结点中的位置pos{ p=T; while(p.tag==BRANCH)//沿分支向下查找 { for(i=0;ikeynum&&key>p->key[i];i++);//确定关键字所在子树 if(i==p->keynum)returnERROR;//关键字太大 p=p->child[i]; } for(i=0;ikeynum&&key!=p->key[i];i++);//在叶子结点中查找 if(i==p->keynum)returnERROR;//找不到关键字 ptr=p;pos=i; returnOK;}//BPTree_Search 9.42voidTrieTree_Insert_Key(TrieTree&T,StringTypekey)//在Trie树T中插入字符串key,StringType的结构见第四章{ q=(TrieNode*)malloc(sizeof(TrieNode)); q->kind=LEAF; q->lf.k=key;//建叶子结点 klen=key[0]; p=T;i=1; while(p&&i<=klen&&p->bh.ptr[ord(key[i])]) { last=p; p=p->bh.ptr[ord(key[i])]; i++; }//自上而下查找
if(p->kind==BRANCH)//如果最后落到分支结点(无同义词): { p->bh.ptr[ord(key[i])]=q;//直接连上叶子 p->bh.num++; } else//如果最后落到叶子结点(有同义词): { r=(TrieNode*)malloc(sizeof(TrieNode));//建立新的分支结点 last->bh.ptr[ord(key[i-1])]=r;//用新分支结点取代老叶子结点和上一层的联系 r->kind=BRANCH;r->bh.num=2; r->bh.ptr[ord(key[i])]=q; r->bh.ptr[ord(p->lf.k[i])]=p;//新分支结点与新老两个叶子结点相连 }}//TrieTree_Insert_Key分析:当自上而下的查找结束时,存在两种情况.一种情况,树中没有待插入关键字的同义词,此时只要新建一个叶子结点并连到分支结点上即可.另一种情况,有同义词,此时要把同义词的叶子结点与树断开,在断开的部位新建一个下一层的分支结点,再把同义词和新关键字的叶子结点连到新分支结点的下一层.9.43StatusTrieTree_Delete_Key(TrieTree&T,StringTypekey)//在Trie树T中删除字符串key{ p=T;i=1; while(p&&p->kind==BRANCH&&i<=key[0])//查找待删除元素 { last=p; p=p->bh.ptr[ord(key[i])]; i++; } if(p&&p->kind==LEAF&&p->lf.k=key)//找到了待删除元素 { last->bh.ptr[ord(key[i-1])]=NULL; free(p); returnOK; } elsereturnERROR;//没找到待删除元素}//TrieTree_Delete_Key9.44voidPrint_Hash(HashTableH)//按第一个字母顺序输出Hash表中的所有关键字,其中处理冲突采用线性探测开放定址法{ for(i=1;i<=26;i++) for(j=i;H.elem[j].key;j=(j+1)%hashsize[sizeindex])//线性探测 if(H(H.elem[j].key)==i)printf("%sn",H.elem[j]);}//Print_HashintH(char*s)//求Hash函数{ if(s)returns[0]-96;//求关键字第一个字母的字母序号(小写) elsereturn0;}//H9.45typedef*LNode[MAXSIZE]CHashTable;//链地址Hash表类型StatusBuild_Hash(CHashTable&T,intm)//输入一组关键字,建立Hash表,表长为m,用链地址法处理冲突
.{ if(m<1)returnERROR; T=malloc(m*sizeof(WORD));//建立表头指针向量 for(i=0;idata=key;q->next=NULL; n=H(key); if(!T[n])T[n]=q;//作为链表的第一个结点 else { for(p=T[n];p->next;p=p->next); p->next=q;//插入链表尾部.本算法不考虑排序问题. } }//while returnOK;}//Build_Hash9.46StatusLocate_Hash(HashTableH,introw,intcol,KeyTypekey,int&k)//根据行列值在Hash表表示的稀疏矩阵中确定元素key的位置k{ h=2*(100*(row/10)+col/10);//作者设计的Hash函数 while(H.elem[h].key&&!EQ(H.elem[h].key,key)) h=(h+1)%20000; if(EQ(H.elem[h].key,key))k=h; elsek=NULL;}//Locate_Hash分析:本算法所使用的Hash表长20000,装填因子为50%,Hash函数为行数前两位和列数前两位所组成的四位数再乘以二,用线性探测法处理冲突.当矩阵的元素是随机分布时,查找的时间复杂度为O(1).第十章内部排序10.23voidInsert_Sort1(SqList&L)//监视哨设在高下标端的插入排序算法{ k=L.length; for(i=k-1;i;--i)//从后向前逐个插入排序 if(L.r[i].key>L.r[i+1].key) { L.r[k+1].key=L.r[i].key;//监视哨 for(j=i+1;L.r[j].key>L.r[i].key;++j) L.r[j-1].key=L.r[j].key;//前移 L.r[j-1].key=L.r[k+1].key;//插入 }}//Insert_Sort110.24voidBiInsert_Sort(SqList&L)//二路插入排序的算法{ intd[MAXSIZE];//辅助存储 x=L.r.key;d
=x; first=1;final=1; for(i=2;i<=L.length;i++) { if(L.r[i].key>=x)//插入前部 { for(j=final;d[j]>L.r[i].key;j--) d[j+1]=d[j]; d[j+1]=L.r[i].key; final++; } else//插入后部 { for(j=first;d[j]L.r[i]; L.r[i].next=p; } p=q; }//for}//SLInsert_Sort10.26voidBubble_Sort1(inta[],intn)//对包含n个元素的数组a进行改进的冒泡排序{ change=n-1;//change指示上一趟冒泡中最后发生交换的元素 while(change) { for(c=0,i=0;ia[i+1]) {
a[i]<->a[i+1]; c=i+1;//c指示这一趟冒泡中发生交换的元素 } change=c; }//while}//Bubble_Sort110.27voidBubble_Sort2(inta[],intn)//相邻两趟是反方向起泡的冒泡排序算法{ low=0;high=n-1;//冒泡的上下界 change=1; while(lowa[i+1]) { a[i]<->a[i+1]; change=1; } high--;//修改上界 for(i=high;i>low;i--)//从下向上起泡 if(a[i]a[i-1]; change=1; } low++;//修改下界 }//while}//Bubble_Sort210.28voidBubble_Sort3(inta[],intn)//对上一题的算法进行化简,循环体中只包含一次冒泡{ intb[3];//b[0]为冒泡的下界,b[2]为上界,b[1]无用 d=1;b[0]=0;b[2]=n-1;//d为冒泡方向的标识,1为向上,-1为向下 change=1; while(b[0]0)//注意这个交换条件 { a[i]<->a[i+d]; change=1; } b[1+d]-=d;//修改边界 d*=-1;//换个方向 }//while}//Bubble_Sort310.29voidOE_Sort(inta[],intn)//奇偶交换排序的算法{ change=1; while(change) {
change=0; for(i=1;ia[i+1]) { a[i]<->a[i+1]; change=1; } for(i=0;ia[i+1]) { a[i]<->a[i+1]; change=1; } }//while}//OE_Sort分析:本算法的结束条件是连续两趟比较无交换发生10.30typedefstruct{ intlow; inthigh; }boundary;//子序列的上下界类型voidQSort_NotRecurve(intSQList&L)//快速排序的非递归算法{ low=1;high=L.length; InitStack(S);//S的元素为boundary类型 while(low2)//如果当前子序列长度大于3且尚未排好序 { pivot=Partition(L,low,high);//进行一趟划分 if(high-pivot>pivot-low) { Push(S,{pivot+1,high});//把长的子序列边界入栈 high=pivot-1;//短的子序列留待下次排序 } else { Push(S,{low,pivot-1}); low=pivot+1; } }//if elseif(low=pivotkey) high--; L.r[low]=L.r[high]; while(lowL.r[high].key)L.r[low]<->L.r[high]; else//子序列含有三个元素 { if(L.r[low].key>L.r[low+1].key)L.r[low]<->L.r[low+1]; if(L.r[low+1].key>L.r[high].key)L.r[low+1]<->L.r[high]; if(L.r[low].key>L.r[low+1].key)L.r[low]<->L.r[low+1]; }}//Easy_Sort10.31voidDivide(inta[],intn)//把数组a中所有值为负的记录调到非负的记录之前{ low=0;high=n-1; while(low=0)high--;//以0作为虚拟的枢轴记录 a[low]<->a[high]; while(lowa[high]; }}//Divide10.32typedefenum{RED,WHITE,BLUE}color;//三种颜色voidFlag_Arrange(colora[],intn)//把由三种颜色组成的序列重排为按照红,白,蓝的顺序排列{ i=0;j=0;k=n-1; while(j<=k) switch(a[j]) { caseRED: a[i]<->a[j]; i++; j++; break; caseWHITE: j++; break; caseBLUE: a[j]<->a[k]; k--;//这里没有j++;语句是为了防止交换后a[j]仍为蓝色的情况
}}//Flag_Arrange分析:这个算法中设立了三个指针.其中,j表示当前元素;i以前的元素全部为红色;k以后的元素全部为蓝色.这样,就可以根据j的颜色,把其交换到序列的前部或者后部.10.33voidLinkedList_Select_Sort(LinkedList&L)//单链表上的简单选择排序算法{ for(p=L;p->next->next;p=p->next) { q=p->next;x=q->data; for(r=q,s=q;r->next;r=r->next)//在q后面寻找元素值最小的结点 if(r->next->datanext->data; s=r; } if(s!=q)//找到了值比q->data更小的最小结点s->next { p->next=s->next;s->next=q; t=q->next;q->next=p->next->next; p->next->next=t; }//交换q和s->next两个结点 }//for}//LinkedList_Select_Sort10.34voidBuild_Heap(Heap&H,intn)//从低下标到高下标逐个插入建堆的算法{ for(i=2;iH.r[k].key) H.r[j]<->H.r[k]; j=k; } }//for}//Build_Heap10.35voidTriHeap_Sort(Heap&H)//利用三叉树形式的堆进行排序的算法{ for(i=H.length/3;i>0;i--) Heap_Adjust(H,i,H.length); for(i=H.length;i>1;i--) { H.r[1]<->H.r[i]; Heap_Adjust(H,1,i-1); }}//TriHeap_SortvoidHeap_Adjust(Heap&H,ints,intm)//顺序表H中,H.r[s+1]到H.r[m]已经是堆,把H.r[s]插入并调整成堆
{ rc=H.r[s]; for(j=3*s-1;j<=m;j=3*j-1) { if(j(n-1)?(n-1):(start2+l-1);//注意end2可能超出边界 Merge(a,start1,end1,start2,end2);//归并 }}//Merge_SortvoidMerge(inta[],ints1,inte1,ints2,inte2)//将有序子序列a[s1]到a[e1]和a[s2]到a[e2]归并为有序序列a[s1]到a[e2]{ intb[MAXSIZE];//设立辅助存储数组b for(i=s1,j=s2,k=s1;i<=e1&&j<=e2;k++) { if(a[i]next,e2=p;p->next;p=e2) { for(i=1,q=p;i<=l&&q->next;i++,q=q->next); e1=q; for(i=1;i<=l&&q->next;i++,q=q->next); e2=q;//求出两个待归并子序列的尾指针 if(e1!=e2)LinkedList_Merge(L,p,e1,e2);//归并 }}//LinkedList_Merge_Sort1voidLinkedList_Merge(LinkedList&L,LNode*p,LNode*e1,LNode*e2)//对链表上的子序列进行归并,第一个子序列是从p->next到e1,第二个是从e1->next到e2{ q=p->next;r=e1->next;//q和r为两个子序列的起始位置
while(q!=e1->next&&r!=e2->next) { if(q->datadata)//选择关键字较小的那个结点接在p的后面 { p->next=q;p=q; q=q->next; } else { p->next=r;p=r; r=r->next; } }//while while(q!=e1->next)//接上剩余部分 { p->next=q;p=q; q=q->next; } while(r!=e2->next) { p->next=r;p=r; r=r->next; }}//LinkedList_Merge10.38voidLinkedList_Merge_Sort2(LinkedList&L)//初始归并段为最大有序子序列的归并排序,采用链表存储结构{ LNode*end[MAXSIZE];//设立一个数组来存储各有序子序列的尾指针 for(p=L->next->next,i=0;p;p=p->next)//求各有序子序列的尾指针 if(!p->next||p->data>p->next->data)end[i++]=p; while(end[0]->next)//当不止一个子序列时进行两两归并 { j=0;k=0;//j:当前子序列尾指针存储位置;k:归并后的子序列尾指针存储位置 for(p=L->next,e2=p;p->next;p=e2)//两两归并所有子序列 { e1=end[j];e2=end[j+1];//确定两个子序列 if(e1->next)LinkedList_Merge(L,p,e1,e2);//归并 end[k++]=e2;//用新序列的尾指针取代原来的尾指针 j+=2;//转到后面两个子序列 } }//while}//LinkedList_Merge_Sort2voidLinkedList_Merge(LinkedList&L,LNode*p,LNode*e1,LNode*e2)//对链表上的子序列进行归并,第一个子序列是从p->next到e1,第二个是从e1->next到e2{ q=p->next;r=e1->next; while(q!=e1->next&&r!=e2->next) { if(q->datadata) { p->next=q;p=q; q=q->next; } else
{ p->next=r;p=r; r=r->next; } }//while while(q!=e1->next) { p->next=q;p=q; q=q->next; } while(r!=e2->next) { p->next=r;p=r; r=r->next; }}//LinkedList_Merge,与上一题完全相同10.39voidSL_Merge(inta[],intl1,intl2)//把长度分别为l1,l2且l1^2<(l1+l2)的两个有序子序列归并为有序序列{ start1=0;start2=l1;//分别表示序列1和序列2的剩余未归并部分的起始位置 for(i=0;ia[i])b[i].gt++; elseif(a[j]a[min];//与第i个记录交换 c[min]=INFINITY;//修改该记录的c值为无穷大以便下一次选取
}}//Count_Sort10.44voidEnum_Sort(inta[],intn)//对关键字只能取v到w之间任意整数的序列进行排序{ intnumber[w+1],pos[w+1]; for(i=0;i1&&change;i--)//对影子序列执行冒泡排序 { change=0; for(j=0;jd[j+1].key)
{ d[j]<->d[j+1]; change=1; } }//for for(i=0;i'