严蔚敏C语言版《数据结构》习题集答案

更新时间:2023-11-04 04:14:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

第一章 绪论

1.16

void print_descending(int x,int y,int z)//按从大到小顺序输出三个数 {

scanf(\

if(xy; //<->为表示交换的双目运算符,以下同 if(yz;

if(xy; //冒泡排序 printf(\}//print_descending 1.17

Status fib(int k,int m,int &f)//求k阶斐波那契序列的第m项的值f {

int tempd;

if(k<2||m<0) return ERROR; if(m

else if (m==k-1 || m==k) f=1; else {

for(i=0;i<=k-2;i++) temp[i]=0; temp[k-1]=1;temp[k]=1; //初始化 sum=1; j=0;

for(i=k+1;i<=m;i++,j++) //求出序列第k至第m个元素的值 temp[i]=2*sum-temp[j]; f=temp[m]; }

return OK; }//fib

分析: k阶斐波那契序列的第m项的值f[m]=f[m-1]+f[m-2]+......+f[m-k] =f[m-1]+f[m-2]+......+f[m-k]+f[m-k-1]-f[m-k-1] =2*f[m-1]-f[m-k-1]

所以上述算法的时间复杂度仅为O(m). 如果采用递归设计,将达到O(k^m). 即使采用暂存中间结果的方法,也将达到O(m^2). 1.18

typedef struct{

char *sport;

enum{male,female} gender;

char schoolname; //校名为'A','B','C','D'或'E' char *result; int score; } resulttype; typedef struct{

int malescore; int femalescore; int totalscore; } scoretype;

void summary(resulttype result[ ])//求各校的男女总分和团体总分,假设结果已经储存在result[ ]数组中 {

scoretype score[MAXSIZE]; i=0;

while(result[i].sport!=NULL) {

switch(result[i].schoolname)

{

case 'A':

score[ 0 ].totalscore+=result[i].score;

if(result[i].gender==0) score[ 0 ].malescore+=result[i].score; else score[ 0 ].femalescore+=result[i].score; break; case 'B':

score[ 0 ].totalscore+=result[i].score;

if(result[i].gender==0) score[ 0 ].malescore+=result[i].score; else score[ 0 ].femalescore+=result[i].score; break;

…… …… …… } i++; }

for(i=0;i<5;i++) {

printf(\

printf(\ printf(\ printf(\ }

}//summary 1.19

Status algo119(int a[ARRSIZE])//求i!*2^i序列的值且不超过maxint {

last=1;

for(i=1;i<=ARRSIZE;i++) {

a[i-1]=last*2*i;

if((a[i-1]/last)!=(2*i)) reurn OVERFLOW; last=a[i-1]; return OK; }

}//algo119

分析:当某一项的结果超过了maxint时,它除以前面一项的商会发生异常. 1.20

void polyvalue() {

float temp; float *p=a;

printf(\ scanf(\

printf(\ scanf(\

printf(\ p=a;xp=1;sum=0; //xp用于存放x的i次方 for(i=0;i<=n;i++) {

scanf(\ sum+=xp*(temp); xp*=x; }

printf(\}//polyvalue

第二章 线性表

2.10

Status DeleteK(SqList &a,int i,int k)//删除线性表a中第i个元素起的k个元素 {

if(i<1||k<0||i+k-1>a.length) return INFEASIBLE;

for(count=1;i+count-1<=a.length-k;count++) //注意循环结束的条件 a.elem[i+count-1]=a.elem[i+count+k-1]; a.length-=k; return OK; }//DeleteK 2.11

Status Insert_SqList(SqList &va,int x)//把x插入递增有序表va中 {

if(va.length+1>va.listsize) return ERROR; va.length++;

for(i=va.length-1;va.elem[i]>x&&i>=0;i--) va.elem[i+1]=va.elem[i]; va.elem[i+1]=x; return OK;

}//Insert_SqList 2.12

int ListComp(SqList A,SqList B)//比较字符表A和B,并用返回值表示结果,值为1,表示A>B;值为-1,表示A

for(i=1;i<=A.length&&i<=B.length;i++) if(A.elem[i]!=B.elem[i])

return A.elem[i]>B.elem[i]?1:-1; if(A.length==B.length) return 0;

return A.length>B.length?1:-1; //当两个字符表可以互相比较的部分完全相同时,哪个较长,哪个就较大 }//ListComp 2.13

LNode* Locate(LinkList L,int x)//链表上的元素查找,返回指针 {

for(p=l->next;p&&p->data!=x;p=p->next); return p; }//Locate 2.14

int Length(LinkList L)//求链表的长度 {

for(k=0,p=L;p->next;p=p->next,k++); return k; }//Length 2.15

void ListConcat(LinkList ha,LinkList hb,LinkList &hc)//把链表hb接在ha后面形成链表hc {

hc=ha;p=ha;

while(p->next) p=p->next; p->next=hb; }//ListConcat 2.16

见书后答案. 2.17

Status Insert(LinkList &L,int i,int b)//在无头结点链表L的第i个元素之前插入元素b {

p=L;q=(LinkList*)malloc(sizeof(LNode)); q.data=b; if(i==1) {

q.next=p;L=q; //插入在链表头部 } else {

while(--i>1) p=p->next;

q->next=p->next;p->next=q; //插入在第i个元素的位置 }

}//Insert 2.18

Status Delete(LinkList &L,int i)//在无头结点链表L中删除第i个元素 {

if(i==1) L=L->next; //删除第一个元素 else {

p=L;

while(--i>1) p=p->next;

p->next=p->next->next; //删除第i个元素 }

}//Delete 2.19

Status Delete_Between(Linklist &L,int mink,int maxk)//删除元素递增排列的链表L中值大于mink且小于maxk的所有元素 { p=L;

while(p->next->data<=mink) p=p->next; //p是最后一个不大于mink的元素 if(p->next) //如果还有比mink更大的元素 {

q=p->next;

while(q->datanext; //q是第一个不小于maxk的元素 p->next=q; }

}//Delete_Between 2.20

Status Delete_Equal(Linklist &L)//删除元素递增排列的链表L中所有值相同的元素 {

p=L->next;q=p->next; //p,q指向相邻两元素 while(p->next) {

if(p->data!=q->data) {

p=p->next;q=p->next; //当相邻两元素不相等时,p,q都向后推一步 } else {

while(q->data==p->data) {

free(q); q=q->next; }

p->next=q;p=q;q=p->next; //当相邻元素相等时删除多余元素 }//else }//while

}//Delete_Equal 2.21

void reverse(SqList &A)//顺序表的就地逆置 {

for(i=1,j=A.length;iA.elem[j]; }//reverse 2.22

void LinkList_reverse(Linklist &L)//链表的就地逆置;为简化算法,假设表长大于2 {

p=L->next;q=p->next;s=q->next;p->next=NULL; while(s->next) {

q->next=p;p=q;

q=s;s=s->next; //把L的元素逐个插入新表表头 }

q->next=p;s->next=q;L->next=s; }//LinkList_reverse

分析:本算法的思想是,逐个地把L的当前元素q插入新的链表头部,p为新表表头. 2.23

void merge1(LinkList &A,LinkList &B,LinkList &C)//把链表A和B合并为C,A和B的元素间隔排列,且使用原存储空间 {

p=A->next;q=B->next;C=A; while(p&&q) {

s=p->next;p->next=q; //将B的元素插入 if(s) {

t=q->next;q->next=s; //如A非空,将A的元素插入 }

p=s;q=t; }//while }//merge1 2.24

void reverse_merge(LinkList &A,LinkList &B,LinkList &C)//把元素递增排列的链表A和B合并为C,且C中元素递减排列,使用原空间 {

pa=A->next;pb=B->next;pre=NULL; //pa和pb分别指向A,B的当前元素 while(pa||pb) {

if(pa->datadata||!pb) {

pc=pa;q=pa->next;pa->next=pre;pa=q; //将A的元素插入新表 } else {

pc=pb;q=pb->next;pb->next=pre;pb=q; //将B的元素插入新表 }

pre=pc; }

C=A;A->next=pc; //构造新表头 }//reverse_merge

分析:本算法的思想是,按从小到大的顺序依次把A和B的元素插入新表的头部pc处,最后处理A或B的剩余元素.

void Subtract_SqPoly(SqPoly P1,SqPoly P2,SqPoly &P3)//求稀疏多项式P1减P2的差式P3 {

PolyTerm *p,*q,*r;

Create_SqPoly(P3); //建立空多项式P3 p=P1.data;q=P2.data;r=P3.data; while(p->coef&&q->coef) {

if(p->expexp) {

r->coef=p->coef; r->exp=p->exp; p++;r++; }

else if(p->expexp) {

r->coef=-q->coef; r->exp=q->exp; q++;r++; } else {

if((p->coef-q->coef)!=0) //只有同次项相减不为零时才需要存入P3中 {

r->coef=p->coef-q->coef; r->exp=p->exp;r++; }//if

p++;q++; }//else }//while

while(p->coef) //处理P1或P2的剩余项 {

r->coef=p->coef; r->exp=p->exp; p++;r++; }

while(q->coef) {

r->coef=-q->coef; r->exp=q->exp; q++;r++; }

}//Subtract_SqPoly 2.41

void QiuDao_LinkedPoly(LinkedPoly &L)//对有头结点循环链表结构存储的稀疏多项式L求导 {

p=L->next; if(!p->data.exp) {

L->next=p->next;p=p->next; //跳过常数项 }

while(p!=L) {

p->data.coef*=p->data.exp--;//对每一项求导 p=p->next; }

}//QiuDao_LinkedPoly 2.42

void Divide_LinkedPoly(LinkedPoly &L,&A,&B)//把循环链表存储的稀疏多项式L拆成只含奇次项的A和只含偶次项的B {

p=L->next;

A=(PolyNode*)malloc(sizeof(PolyNode)); B=(PolyNode*)malloc(sizeof(PolyNode)); pa=A;pb=B; while(p!=L) {

if(p->data.exp!=2*(p->data.exp/2)) {

pa->next=p;pa=p; } else {

pb->next=p;pb=p; }

p=p->next; }//while

pa->next=A;pb->next=B; }//Divide_LinkedPoly

第三章 栈与队列

3.15

typedef struct{

Elemtype *base[2]; Elemtype *top[2];

}BDStacktype; //双向栈类型

Status Init_Stack(BDStacktype &tws,int m)//初始化一个大小为m的双向栈tws {

tws.base[0]=(Elemtype*)malloc(sizeof(Elemtype)); tws.base[1]=tws.base[0]+m; tws.top[0]=tws.base[0]; tws.top[1]=tws.base[1]; return OK; }//Init_Stack

Status push(BDStacktype &tws,int i,Elemtype x)//x入栈,i=0表示低端栈,i=1表示高端栈 {

if(tws.top[0]>tws.top[1]) return OVERFLOW; //注意此时的栈满条件 if(i==0) *tws.top[0]++=x; else if(i==1) *tws.top[1]--=x; else return ERROR; return OK; }//push

Status pop(BDStacktype &tws,int i,Elemtype &x)//x出栈,i=0表示低端栈,i=1表示高端栈 {

if(i==0) {

if(tws.top[0]==tws.base[0]) return OVERFLOW; x=*--tws.top[0]; }

else if(i==1)

{

if(tws.top[1]==tws.base[1]) return OVERFLOW; x=*++tws.top[1]; }

else return ERROR; return OK; }//pop 3.16

void Train_arrange(char *train)//这里用字符串train表示火车,'H'表示硬席,'S'表示软席 {

p=train;q=train; InitStack(s); while(*p) {

if(*p=='H') push(s,*p); //把'H'存入栈中 else *(q++)=*p; //把'S'调到前部 p++; }

while(!StackEmpty(s)) {

pop(s,c);

*(q++)=c; //把'H'接在后部 }

}//Train_arrange 3.17

int IsReverse()//判断输入的字符串中'&'前和'&'后部分是否为逆串,是则返回1,否则返回0 {

InitStack(s);

while((e=getchar())!='&') {

if(e==’@’) return 0;//不允许在’&’之前出现’@’ push(s,e); }

while( (e=getchar())!='@') {

if(StackEmpty(s)) return 0; pop(s,c);

if(e!=c) return 0; }

if(!StackEmpty(s)) return 0; return 1; }//IsReverse 3.18

Status Bracket_Test(char *str)//判别表达式中小括号是否匹配 {

count=0;

for(p=str;*p;p++) {

if(*p=='(') count++; else if(*p==')') count--; if (count<0) return ERROR; }

if(count) return ERROR; //注意括号不匹配的两种情况 return OK; }//Bracket_Test 3.19

Status AllBrackets_Test(char *str)//判别表达式中三种括号是否匹配 {

InitStack(s);

for(p=str;*p;p++) {

if(*p=='('||*p=='['||*p=='{') push(s,*p); else if(*p==')'||*p==']'||*p=='}') {

if(StackEmpty(s)) return ERROR; pop(s,c);

if(*p==')'&&c!='(') return ERROR; if(*p==']'&&c!='[') return ERROR;

if(*p=='}'&&c!='{') return ERROR; //必须与当前栈顶括号匹配 } }//for

if(!StackEmpty(s)) return ERROR; return OK;

}//AllBrackets_Test 3.20

typedef struct { . int x; int y;

} coordinate;

void Repaint_Color(int g[m][n],int i,int j,int color)//把点(i,j)相邻区域的颜色置换为color {

old=g[i][j]; InitQueue(Q); EnQueue(Q,{I,j});

while(!QueueEmpty(Q)) {

DeQueue(Q,a); x=a.x;y=a.y; if(x>1)

if(g[x-1][y]==old) {

g[x-1][y]=color;

EnQueue(Q,{x-1,y}); //修改左邻点的颜色 } if(y>1)

if(g[x][y-1]==old) {

g[x][y-1]=color;

EnQueue(Q,{x,y-1}); //修改上邻点的颜色 }

if(x

if(g[x+1][y]==old) {

g[x+1][y]=color;

EnQueue(Q,{x+1,y}); //修改右邻点的颜色 } if(y

if(g[x][y+1]==old) {

g[x][y+1]=color;

EnQueue(Q,{x,y+1}); //修改下邻点的颜色 } }//while

}//Repaint_Color

分析:本算法采用了类似于图的广度优先遍历的思想,用两个队列保存相邻同色点的横坐标和纵坐标.递归形式的算法该怎么写呢? 3.21

void NiBoLan(char *str,char *new)//把中缀表达式str转换成逆波兰式new {

p=str;q=new; //为方便起见,设str的两端都加上了优先级最低的特殊符号 InitStack(s); //s为运算符栈 while(*p) {

if(*p是字母)) *q++=*p; //直接输出 else {

c=gettop(s);

if(*p优先级比c高) push(s,*p); else {

while(gettop(s)优先级不比*p低) {

pop(s,c);*(q++)=c; }//while

push(s,*p); //运算符在栈内遵循越往栈顶优先级越高的原则 }//else }//else p++; }//while

}//NiBoLan //参见编译原理教材 3.22

int GetValue_NiBoLan(char *str)//对逆波兰式求值 {

p=str;InitStack(s); //s为操作数栈 while(*p) {

if(*p是数) push(s,*p); else {

pop(s,a);pop(s,b);

r=compute(b,*p,a); //假设compute为执行双目运算的过程 push(s,r); }//else p++; }//while

pop(s,r);return r;

}//GetValue_NiBoLan 3.23

Status NiBoLan_to_BoLan(char *str,stringtype &new)//把逆波兰表达式str转换为波兰式new {

p=str;Initstack(s); //s的元素为stringtype类型 while(*p) {

if(*p为字母) push(s,*p); else

{

if(StackEmpty(s)) return ERROR; pop(s,a);

if(StackEmpty(s)) return ERROR; pop(s,b);

c=link(link(*p,b),a); push(s,c); }//else p++; }//while pop(s,new);

if(!StackEmpty(s)) return ERROR; return OK;

}//NiBoLan_to_BoLan

分析:基本思想见书后注释.本题中暂不考虑串的具体操作的实现,而将其看作一种抽象数据类型stringtype,对其可以进行连接操作:c=link(a,b). 3.24

Status g(int m,int n,int &s)//求递归函数g的值s {

if(m==0&&n>=0) s=0;

else if(m>0&&n>=0) s=n+g(m-1,2*n); else return ERROR; return OK; }//g 3.25

Status F_recursive(int n,int &s)//递归算法 {

if(n<0) return ERROR; if(n==0) s=n+1; else {

F_recurve(n/2,r); s=n*r; }

return OK; }//F_recursive

Status F_nonrecursive(int n,int s)//非递归算法 {

if(n<0) return ERROR; if(n==0) s=n+1; else {

InitStack(s); //s的元素类型为struct {int a;int b;} while(n!=0) {

a=n;b=n/2; push(s,{a,b}); n=b; }//while s=1;

while(!StackEmpty(s)) {

pop(s,t); s*=t.a; }//while }

return OK;

}//F_nonrecursive 3.26

float Sqrt_recursive(float A,float p,float e)//求平方根的递归算法 {

if(abs(p^2-A)<=e) return p;

else return sqrt_recurve(A,(p+A/p)/2,e); }//Sqrt_recurve

float Sqrt_nonrecursive(float A,float p,float e)//求平方根的非递归算法 {

while(abs(p^2-A)>=e) p=(p+A/p)/2; return p;

}//Sqrt_nonrecursive 3.27

这一题的所有算法以及栈的变化过程请参见《数据结构(pascal版)》,作者不再详细写出. 3.28

void InitCiQueue(CiQueue &Q)//初始化循环链表表示的队列Q {

Q=(CiLNode*)malloc(sizeof(CiLNode)); Q->next=Q; }//InitCiQueue

void EnCiQueue(CiQueue &Q,int x)//把元素x插入循环链表表示的队列Q,Q指向队尾元素,Q->next指向头结点,Q->next->next指向队头元素 {

p=(CiLNode*)malloc(sizeof(CiLNode)); p->data=x;

p->next=Q->next; //直接把p加在Q的后面 Q->next=p;

Q=p; //修改尾指针 }

Status DeCiQueue(CiQueue &Q,int x)//从循环链表表示的队列Q头部删除元素x {

if(Q==Q->next) return INFEASIBLE; //队列已空 p=Q->next->next; x=p->data;

Q->next->next=p->next; free(p); return OK; }//DeCiQueue 3.29

Status EnCyQueue(CyQueue &Q,int x)//带tag域的循环队列入队算法 {

if(Q.front==Q.rear&&Q.tag==1) //tag域的值为0表示\空\表示\满\ return OVERFLOW; Q.base[Q.rear]=x;

Q.rear=(Q.rear+1)%MAXSIZE;

if(Q.front==Q.rear) Q.tag=1; //队列满 }//EnCyQueue

Status DeCyQueue(CyQueue &Q,int &x)//带tag域的循环队列出队算法 {

if(Q.front==Q.rear&&Q.tag==0) return INFEASIBLE; Q.front=(Q.front+1)%MAXSIZE; x=Q.base[Q.front];

if(Q.front==Q.rear) Q.tag=1; //队列空 return OK;

}//DeCyQueue

分析:当循环队列容量较小而队列中每个元素占的空间较多时,此种表示方法可以节约较多的存储空间,较有价值. 3.30

Status EnCyQueue(CyQueue &Q,int x)//带length域的循环队列入队算法 {

if(Q.length==MAXSIZE) return OVERFLOW; Q.rear=(Q.rear+1)%MAXSIZE; Q.base[Q.rear]=x; Q.length++; return OK; }//EnCyQueue

Status DeCyQueue(CyQueue &Q,int &x)//带length域的循环队列出队算法 {

if(Q.length==0) return INFEASIBLE;

head=(Q.rear-Q.length+1)%MAXSIZE; //详见书后注释 x=Q.base[head]; Q.length--; }//DeCyQueue 3.31

int Palindrome_Test()//判别输入的字符串是否回文序列,是则返回1,否则返回0 {

InitStack(S);InitQueue(Q); while((c=getchar())!='@') {

Push(S,c);EnQueue(Q,c); //同时使用栈和队列两种结构 }

while(!StackEmpty(S)) {

Pop(S,a);DeQueue(Q,b)); if(a!=b) return ERROR; }

return OK;

}//Palindrome_Test 3.32

void GetFib_CyQueue(int k,int n)//求k阶斐波那契序列的前n+1项 {

InitCyQueue(Q); //其MAXSIZE设置为k for(i=0;i

for(i=0;i

m=i%k;sum=0;

for(j=0;j

Q.base[m]=sum; //求第i项的值存入队列中并取代已无用的第一项 printf(\ }

}//GetFib_CyQueue 3.33

Status EnDQueue(DQueue &Q,int x)//输出受限的双端队列的入队操作 {

if((Q.rear+1)%MAXSIZE==Q.front) return OVERFLOW; //队列满 avr=(Q.base[Q.rear-1]+Q.base[Q.front])/2;

if(x>=avr) //根据x的值决定插入在队头还是队尾 {

Q.base[Q.rear]=x;

Q.rear=(Q.rear+1)%MAXSIZE; } //插入在队尾 else {

Q.front=(Q.front-1)%MAXSIZE; Q.base[Q.front]=x; } //插入在队头 return OK; }//EnDQueue

Status DeDQueue(DQueue &Q,int &x)//输出受限的双端队列的出队操作 {

if(Q.front==Q.rear) return INFEASIBLE; //队列空 x=Q.base[Q.front];

Q.front=(Q.front+1)%MAXSIZE; return OK; }//DeDQueue 3.34

void Train_Rearrange(char *train)//这里用字符串train表示火车,'P'表示硬座,'H'表示硬卧,'S'表示软卧,最终按PSH的顺序排列 {

r=train;

InitDQueue(Q); while(*r) {

if(*r=='P') {

printf(\

printf(\实际上等于不入队列,直接输出P车厢 }

else if(*r=='S') {

printf(\

EnDQueue(Q,*r,0); //0表示把S车厢从头端入队列 } else {

printf(\

EnDQueue(Q,*r,1); //1表示把H车厢从尾端入队列 } }//while

while(!DQueueEmpty(Q)) {

printf(\ DeDQueue(Q);

}//while //从头端出队列的车厢必然是先S后H的顺序 }//Train_Rearrange

第四章 串

4.10

void String_Reverse(Stringtype s,Stringtype &r)//求s的逆串r {

StrAssign(r,''); //初始化r为空串

for(i=Strlen(s);i;i--) {

StrAssign(c,SubString(s,i,1));

StrAssign(r,Concat(r,c)); //把s的字符从后往前添加到r中 }

}//String_Reverse 4.11

void String_Subtract(Stringtype s,Stringtype t,Stringtype &r)//求所有包含在串s中而t中没有的字符构成的新串r {

StrAssign(r,'');

for(i=1;i<=Strlen(s);i++) {

StrAssign(c,SubString(s,i,1));

for(j=1;j

for(k=1;k<=Strlen(t)&&StrCompare(c,SubString(t,k,1));k++); //判断当前字符是否包含在t中

if(k>Strlen(t)) StrAssign(r,Concat(r,c)); } }//for

}//String_Subtract 4.12

int Replace(Stringtype &S,Stringtype T,Stringtype V);//将串S中所有子串T替换为V,并返回置换次数 {

for(n=0,i=1;i<=Strlen(S)-Strlen(T)+1;i++) //注意i的取值范围

if(!StrCompare(SubString(S,i,Strlen(T)),T)) //找到了与T匹配的子串 { //分别把T的前面和后面部分保存为head和tail StrAssign(head,SubString(S,1,i-1));

StrAssign(tail,SubString(S,i+Strlen(T),Strlen(S)-i-Strlen(T)+1)); StrAssign(S,Concat(head,V));

StrAssign(S,Concat(S,tail)); //把head,V,tail连接为新串 i+=Strlen(V); //当前指针跳到插入串以后 n++; }//if return n; }//Replace

分析:i+=Strlen(V);这一句是必需的,也是容易忽略的.如省掉这一句,则在某些情况下,会引起不希望的后果,虽然在大多数情况下没有影响.请思考:设S='place', T='ace', V='face',则省掉i+=Strlen(V);运行时会出现什么结果? 4.13

int Delete_SubString(Stringtype &s,Stringtype t)//从串s中删除所有与t相同的子串,并返回删除次数 {

for(n=0,i=1;i<=Strlen(s)-Strlen(t)+1;i++) if(!StrCompare(SubString(s,i,Strlen(t)),t)) {

StrAssign(head,SubString(S,1,i-1));

StrAssign(tail,SubString(S,i+Strlen(t),Strlen(s)-i-Strlen(t)+1)); StrAssign(S,Concat(head,tail)); //把head,tail连接为新串 n++; }//if return n,

c=0; //在主函数中调用前,要给计数器赋初值0 Get_PreSeq(T,k); ...

}//main 6.42

int LeafCount_BiTree(Bitree T)//求二叉树中叶子结点的数目 {

if(!T) return 0; //空树没有叶子

else if(!T->lchild&&!T->rchild) return 1; //叶子结点

else return Leaf_Count(T->lchild)+Leaf_Count(T->rchild);//左子树的叶子数加上右子树的叶子数

}//LeafCount_BiTree 6.43

void Bitree_Revolute(Bitree T)//交换所有结点的左右子树 {

T->lchild<->T->rchild; //交换左右子树 if(T->lchild) Bitree_Revolute(T->lchild);

if(T->rchild) Bitree_Revolute(T->rchild); //左右子树再分别交换各自的左右子树 }//Bitree_Revolute 6.44

int Get_Sub_Depth(Bitree T,int x)//求二叉树中以值为x的结点为根的子树深度 {

if(T->data==x) {

printf(\找到了值为x的结点,求其深度 exit 1; } else {

if(T->lchild) Get_Sub_Depth(T->lchild,x);

if(T->rchild) Get_Sub_Depth(T->rchild,x); //在左右子树中继续寻找 }

}//Get_Sub_Depth

int Get_Depth(Bitree T)//求子树深度的递归算法 {

if(!T) return 0; else {

m=Get_Depth(T->lchild); n=Get_Depth(T->rchild); return (m>n?m:n)+1; }

}//Get_Depth 6.45

void Del_Sub_x(Bitree T,int x)//删除所有以元素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_x

void Del_Sub(Bitree T)//删除子树T {

if(T->lchild) Del_Sub(T->lchild); if(T->rchild) Del_Sub(T->rchild); free(T); }//Del_Sub 6.46

void Bitree_Copy_Nonrecursive(Bitree T,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.47

void LayerOrder(Bitree T)//层序遍历二叉树 {

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

}//LayerOrder 6.48

int found=FALSE;

Bitree* Find_Near_Ancient(Bitree T,Bitree p,Bitree q)//求二叉树T中结点p和q的最近共同祖先 {

Bitree pathp[ 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++); //查找两条路径上最后一个相同结点 return pathp[--i];

}//Find_Near_Ancient

void Findpath(Bitree T,Bitree p,Bitree path[ ],int i)//求从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; //回溯 }//Findpath 6.49

int IsFull_Bitree(Bitree T)//判断二叉树是否完全二叉树,是则返回1,否则返回0 {

InitQueue(Q); flag=0;

EnQueue(Q,T); //建立工作队列 while(!QueueEmpty(Q)) {

DeQueue(Q,p); if(!p) flag=1;

else if(flag) return 0; else {

EnQueue(Q,p->lchild);

EnQueue(Q,p->rchild); //不管孩子是否为空,都入队列 } }//while return 1;

}//IsFull_Bitree

分析:该问题可以通过层序遍历的方法来解决.与6.47相比,作了一个修改,不管当前结点是否有左右孩子,都入队列.这样当树为完全二叉树时,遍历时得到是一个连续的不包含空指针的序列.反之,则序列中会含有空指针. 6.50

Status CreateBitree_Triplet(Bitree &T)//输入三元组建立二叉树 {

if(getchar()!='^') return ERROR;

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)) return ERROR; //未按层序输入 p=QueueHead(Q);

q=(BTNode*)malloc(sizeof(BTNode)); if(side=='L') p->lchild=q; else if(side=='R') p->rchild=q; else return ERROR; //格式不正确

q->data=child; EnQueue(Q,q); }

return OK;

}//CreateBitree_Triplet 6.51

Status Print_Expression(Bitree T)//按标准形式输出以二叉树存储的表达式 {

if(T->data是字母) printf(\ else if(T->data是操作符) {

if(!T->lchild||!T->rchild) return ERROR; //格式错误

if(T->lchild->data是操作符&&T->lchild->data优先级低于T->data) {

printf(\

if(!Print_Expression(T->lchild)) return ERROR; printf(\

} //注意在什么情况下要加括号

else if(!Print_Expression(T->lchild)) return ERROR;

if(T->rchild->data是操作符&&T->rchild->data优先级低于T->data) {

printf(\

if(!Print_Expression(T->rchild)) return ERROR; printf(\ }

else if(!Print_Expression(T->rchild)) return ERROR; }

else return ERROR; //非法字符 return OK;

}//Print_Expression 6.52

typedef struct{

BTNode node; int layer;

} BTNRecord; //包含结点所在层次的记录类型 int FanMao(Bitree T)//求一棵二叉树的\繁茂度\{

int countd; //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.53

int maxh;

Status Printpath_MaxdepthS1(Bitree T)//求深度等于树高度减一的最靠左的结点 {

Bitree pathd;

maxh=Get_Depth(T); //Get_Depth函数见6.44 if(maxh<2) return ERROR; //无符合条件结点 Find_h(T,1); return OK;

}//Printpath_MaxdepthS1

void Find_h(Bitree T,int h)//寻找深度为maxh-1的结点 {

path[h]=T; if(h==maxh-1) {

for(i=1;path[i];i++) printf(\ exit; //打印输出路径 } else {

if(T->lchild) Find_h(T->lchild,h+1); if(T->rchild) Find_h(T->rchild,h+1); }

path[h]=NULL; //回溯 }//Find_h 6.54

Status CreateBitree_SqList(Bitree &T,SqList sa)//根据顺序存储结构建立二叉链表 {

Bitree ptr[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]) return ERROR; //顺序错误 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的右孩子 else ptr[j]->lchild=ptr[i]; //i是j的左孩子 }

return OK;

}//CreateBitree_SqList 6.55

int DescNum(Bitree T)//求树结点T的子孙总数填入DescNum域中,并返回该数 {

if(!T) return -1;

else d=(DescNum(T->lchild)+DescNum(T->rchild)+2); //计算公式 T->DescNum=d; return d; }//DescNum

}//Delete_SubString 4.14

Status NiBoLan_to_BoLan(Stringtype str,Stringtype &new)//把前缀表达式str转换为后缀式new {

Initstack(s); //s的元素为Stringtype类型 for(i=1;i<=Strlen(str);i++) {

r=SubString(str,i,1); if(r为字母) push(s,r); else {

if(StackEmpty(s)) return ERROR; pop(s,a);

if(StackEmpty(s)) return ERROR; pop(s,b);

StrAssign(t,Concat(r,b));

StrAssign(c,Concat(t,a)); //把算符r,子前缀表达式a,b连接为新子前缀表达式c push(s,c); } }//for

pop(s,new);

if(!StackEmpty(s)) return ERROR; return OK;

}//NiBoLan_to_BoLan

分析:基本思想见书后注释3.23.请读者用此程序取代作者早些时候对3.23题给出的程序. 4.15

void StrAssign(Stringtype &T,char chars&#;)//用字符数组chars给串T赋值,Stringtype的定义见课本 {

for(i=0,T[0]=0;chars[i];T[0]++,i++) T[i+1]=chars[i]; }//StrAssign 4.16

char StrCompare(Stringtype s,Stringtype t)//串的比较,s>t时返回正数,s=t时返回0,s

for(i=1;i<=s[0]&&i<=t[0]&&s[i]==t[i];i++); if(i>s[0]&&i>t[0]) return 0; else if(i>s[0]) return -t[i]; else if(i>t[0]) return s[i]; else return s[i]-t[i]; }//StrCompare 4.17

int String_Replace(Stringtype &S,Stringtype T,Stringtype V);//将串S中所有子串T替换为V,并返回置换次数 {

for(n=0,i=1;i<=S[0]-T[0]+1;i++) {

for(j=i,k=1;T[k]&&S[j]==T[k];j++,k++);

if(k>T[0]) //找到了与T匹配的子串:分三种情况处理 {

if(T[0]==V[0])

for(l=1;l<=T[0];l++) //新子串长度与原子串相同时:直接替换 S[i+l-1]=V[l];

else if(T[0]

for(l=S[0];l>=i+T[0];l--) S[l+V[0]-T[0]]=S[l]; for(l=1;l<=V[0];l++) S[i+l-1]=V[l]; }

else //新子串长度小于原子串时:先将后部左移 {

for(l=i+V[0];l<=S[0]+V[0]-T[0];l++) S[l]=S[l-V[0]+T[0]]; for(l=1;l<=V[0];l++) S[i+l-1]=V[l]; }

S[0]=S[0]-T[0]+V[0]; i+=V[0];n++; }//if }//for return n;

}//String_Replace 4.18

typedef struct {

char ch; int num; } mytype;

void StrAnalyze(Stringtype S)//统计串S中字符的种类和个数 {

mytype T[MAXSIZE]; //用结构数组T存储统计结果 for(i=1;i<=S[0];i++) {

c=S[i];j=0;

while(T[j].ch&&T[j].ch!=c) j++; //查找当前字符c是否已记录过 if(T[j].ch) T[j].num++; else T[j]={c,1}; }//for

for(j=0;T[j].ch;j++)

printf(\}//StrAnalyze 4.19

void Subtract_String(Stringtype s,Stringtype t,Stringtype &r)//求所有包含在串s中而t中没有的字符构成的新串r {

r[0]=0;

for(i=1;i<=s[0];i++) {

c=s[i];

for(j=1;j

for(k=1;k<=t[0]&&t[k]!=c;k++); //判断当前字符是否包含在t中 if(k>t[0]) r[++r[0]]=c; } }//for

}//Subtract_String 4.20

int SubString_Delete(Stringtype &s,Stringtype t)//从串s中删除所有与t相同的子串,并返回删除次数 {

for(n=0,i=1;i<=s[0]-t[0]+1;i++) {

for(j=1;j<=t[0]&&s[i+j-1]==t[i];j++); if(j>m) //找到了与t匹配的子串 {

for(k=i;k<=s[0]-t[0];k++) s[k]=s[k+t[0]]; //左移删除 s[0]-=t[0];n++; } }//for return n;

}//Delete_SubString 4.21

typedef struct{

char ch;

LStrNode *next;

} LStrNode,*LString; //链串结构

void StringAssign(LString &s,LString t)//把串t赋值给串s {

s=malloc(sizeof(LStrNode)); for(q=s,p=t->next;p;p=p->next) {

r=(LStrNode*)malloc(sizeof(LStrNode)); r->ch=p->ch; q->next=r;q=r; }

q->next=NULL; }//StringAssign

void StringCopy(LString &s,LString t)//把串t复制为串s.与前一个程序的区别在于,串s业已存在. {

for(p=s->next,q=t->next;p&&q;p=p->next,q=q->next) {

p->ch=q->ch;pre=p; }

while(q) {

p=(LStrNode*)malloc(sizeof(LStrNode)); p->ch=q->ch;

pre->next=p;pre=p; }

p->next=NULL; }//StringCopy

char StringCompare(LString s,LString t)//串的比较,s>t时返回正数,s=t时返回0,s

for(p=s->next,q=t->next;p&&q&&p->ch==q->ch;p=p->next,q=q->next); if(!p&&!q) return 0;

else if(!p) return -(q->ch); else if(!q) return p->ch; else return p->ch-q->ch; }//StringCompare

int StringLen(LString s)//求串s的长度(元素个数) {

for(i=0,p=s->next;p;p=p->next,i++); return i; }//StringLen

LString * Concat(LString s,LString t)//连接串s和串t形成新串,并返回指针

{

p=malloc(sizeof(LStrNode)); for(q=p,r=s->next;r;r=r->next) {

q->next=(LStrNode*)malloc(sizeof(LStrNode)); q=q->next; q->ch=r->ch; }//for //复制串s

for(r=t->next;r;r=r->next) {

q->next=(LStrNode*)malloc(sizeof(LStrNode)); q=q->next; q->ch=r->ch; }//for //复制串t q->next=NULL; return p; }//Concat

LString * Sub_String(LString s,int start,int len)//返回一个串,其值等于串s从start位置起长为len的子串 {

p=malloc(sizeof(LStrNode));q=p;

for(r=s;start;start--,r=r->next); //找到start所对应的结点指针r for(i=1;i<=len;i++,r=r->next) {

q->next=(LStrNode*)malloc(sizeof(LStrNode)); q=q->next; q->ch=r->ch; } //复制串t q->next=NULL; return p;

}//Sub_String 4.22

void LString_Concat(LString &t,LString &s,char c)//用块链存储结构,把串s插入到串t的字符c之后 {

p=t.head;

while(p&&!(i=Find_Char(p,c))) p=p->next; //查找字符c if(!p) //没找到 {

t.tail->next=s.head;

t.tail=s.tail; //把s连接在t的后面 } else {

q=p->next;

r=(Chunk*)malloc(sizeof(Chunk)); //将包含字符c的节点p分裂为两个 for(j=0;jch[j]='#'; //原结点p包含c及其以前的部分 for(j=i;j

r->ch[j]=p->ch[j];

p->ch[j]='#'; //p的后半部分和r的前半部分的字符改为无效字符'#' }

p->next=s.head; s.tail->next=r;

r->next=q; //把串s插入到结点p和r之间

}//else

t.curlen+=s.curlen; //修改串长 s.curlen=0;

}//LString_Concat

int Find_Char(Chunk *p,char c)//在某个块中查找字符c,如找到则返回位置是第几个字符,如没找到则返回0 {

for(i=0;ich[i]!=c;i++); if(i==CHUNKSIZE) return 0; else return i+1; }//Find_Char

4.23

int LString_Palindrome(LString L)//判断以块链结构存储的串L是否为回文序列,是则返回1,否则返回0 {

InitStack(S);

p=S.head;i=0;k=1; //i指示元素在块中的下标,k指示元素在整个序列中的序号(从1开始) for(k=1;k<=S.curlen;k++) {

if(k<=S.curlen/2) Push(S,p->ch[i]); //将前半段的字符入串 else if(k>(S.curlen+1)/2) {

Pop(S,c); //将后半段的字符与栈中的元素相匹配 if(p->ch[i]!=c) return 0; //失配 }

if(++i==CHUNKSIZE) //转到下一个元素,当为块中最后一个元素时,转到下一块 {

p=p->next; i=0; } }//for

return 1; //成功匹配 }//LString_Palindrome 4.24

void HString_Concat(HString s1,HString s2,HString &t)//将堆结构表示的串s1和s2连接为新串t {

if(t.ch) free(t.ch);

t.ch=malloc((s1.length+s2.length)*sizeof(char)); for(i=1;i<=s1.length;i++) t.ch[i-1]=s1.ch[i-1]; for(j=1;j<=s2.length;j++,i++) t.ch[i-1]=s2.ch[j-1]; t.length=s1.length+s2.length; }//HString_Concat 4.25

int HString_Replace(HString &S,HString T,HString V)//堆结构串上的置换操作,返回置换次数 {

for(n=0,i=0;i<=S.length-T.length;i++) {

for(j=i,k=0;k

if(k==T.length) //找到了与T匹配的子串:分三种情况处理 {

if(T.length==V.length)

for(l=1;l<=T.length;l++) //新子串长度与原子串相同时:直接替换 S.ch[i+l-1]=V.ch[l-1];

else if(T.length

for(l=S.length-1;l>=i+T.length;l--) S.ch[l+V.length-T.length]=S.ch[l]; for(l=0;l

else //新子串长度小于原子串时:先将后部左移 {

for(l=i+V.length;l

S.length+=V.length-T.length; i+=V.length;n++; }//if }//for return n;

}//HString_Replace 4.26

Status HString_Insert(HString &S,int pos,HString T)//把T插入堆结构表示的串S的第pos个字符之前 {

if(pos<1) return ERROR;

if(pos>S.length) pos=S.length+1;//当插入位置大于串长时,看作添加在串尾 S.ch=realloc(S.ch,(S.length+T.length)*sizeof(char)); for(i=S.length-1;i>=pos-1;i--)

S.ch[i+T.length]=S.ch[i]; //后移为插入字符串让出位置 for(i=0;i

S.ch[pos+i-1]=T.ch[pos]; //插入串T S.length+=T.length; return OK;

}//HString_Insert 4.27

int Index_New(Stringtype s,Stringtype t)//改进的定位算法 {

i=1;j=1;

while(i<=s[0]&&j<=t[0]) {

if((j!=1&&s[i]==t[j])||(j==1&&s[i]==t[j]&&s[i+t[0]-1]==t[t[0]])) { //当j==1即匹配模式串的第一个字符时,需同时匹配其最后一个 i=i+j-2; j=1; } else {

i++;j++; } }//while

if(j>t[0]) return i-t[0]; }//Index_New 4.28

void LGet_next(LString &T)//链串上的get_next算法 {

p=T->succ;p->next=T;q=T;

while(p->succ) {

if(q==T||p->data==q->data) {

p=p->succ;q=q->succ; p->next=q; }

else q=q->next; }//while

}//LGet_next 4.29

LStrNode * LIndex_KMP(LString S,LString T,LStrNode *pos)//链串上的KMP匹配算法,返回值为匹配的子串首指针 {

p=pos;q=T->succ; while(p&&q) {

if(q==T||p->chdata==q->chdata) {

p=p->succ; q=q->succ; }

else q=q->next; }//while if(!q) {

for(i=1;i<=Strlen(T);i++) p=p->next; return p;

} //发现匹配后,要往回找子串的头 return NULL; }//LIndex_KMP 4.30

void Get_LRepSub(Stringtype S)//求S的最长重复子串的位置和长度 {

for(maxlen=0,i=1;i

for(k=0,j=1;j<=S[0]-i;j++)//j为串S2的当前指针,此时串S1的当前指针为i+j,两指针同步移动 {

if(S[j]==S[j+i]) k++; //用k记录连续相同的字符数 else k=0; //失配时k归零

if(k>maxlen) //发现了比以前发现的更长的重复子串 {

lrs1=j-k+1;lrs2=mrs1+i;maxlen=k; //作记录 } }//for }//for

if(maxlen) {

printf(\ printf(\ }

else printf(\}//Get_LRepSub

分析:i代表\错位值\本算法的思想是,依次把串S的一个副本S2向右错位平移1格,2格,3格,...

与自身S1相匹配,如果存在最长重复子串,则必然能在此过程中被发现.用变量lrs1,lrs2,maxlen来记录已发现的最长重复子串第一次出现位置,第二次出现位置和长度.题目中未说明\重复子串\是否允许有重叠部分,本算法假定允许.如不允许,只需在第二个for语句的循环条件中加上k<=i即可.本算法时间复杂度为O(Strlen(S)^2). 4.31

void Get_LPubSub(Stringtype S,Stringtype T)//求串S和串T的最长公共子串位置和长度 {

if(S[0]>=T[0]) {

StrAssign(A,S);StrAssign(B,T); } else {

StrAssign(A,T);StrAssign(B,S);

} //为简化设计,令S和T中较长的那个为A,较短的那个为B for(maxlen=0,i=1-B[0];i

if(i<0) //i为B相对于A的错位值,向左为负,左端对齐为0,向右为正 {

jmin=1;jmax=i+B[0];

}//B有一部分在A左端的左边 else if(i>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++; else k=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(\ printf(\ }//if

else printf(\}//Get_LPubSub

分析:本题基本思路与上题同.唯一的区别是,由于A,B互不相同,因此B不仅要向右错位,而且还要向左错位,以保证不漏掉一些情况.当B相对于A的位置不同时,需要匹配的区间的计算公式也各不相同,请读者自己画图以帮助理解.本算法的时间复杂度是o(strlrn(s)*strlen(t))。

第五章 数组和广义表

5.18

void RSh(int A[n],int k)//把数组A的元素循环右移k位,只用一个辅助存储空间 {

for(i=1;i<=k;i++)

if(n%i==0&&k%i==0) p=i;//求n和k的最大公约数p for(i=0;i

j=i;l=(i+n-k)%n;temp=A[i]; while(l!=i) {

A[j]=A[l];

j=l;l=(j+n-k)%n; }// 循环右移一步 A[j]=temp; }//for }//RSh

分析:要把A的元素循环右移k位,则A[0]移至A[k],A[k]移至A[2k]......直到最终回到A[0].然而这并没有全部解决问题,因为有可能有的元素在此过程中始终没有被访问过,而是被跳了过去.分析可知,当n和k的最大公约数为p时,只要分别以A[0],A[1],...A[p-1]为起点执行上述算法,就可以保证每一个元素都被且仅被右移一次,从而满足题目要求.也就是说,A的所有元素分别处在p个\循环链\上面.举例如下: n=15,k=6,则p=3.

第一条链:A[0]->A[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.19

void Get_Saddle(int A[m][n])//求矩阵A中的马鞍点 {

for(i=0;i

for(min=A[i][0],j=0;j

if(A[i][j]

if(A[i][j]==min) //判断这个(些)最小值是否鞍点 {

for(flag=1,k=0;k

if(min

printf(\ } }//for

}//Get_Saddle 5.20

int exps[MAXSIZE]; //exps数组用于存储某一项的各变元的指数 int maxm,n; //maxm指示变元总数,n指示一个变元的最高指数

void Print_Poly_Descend(int *a,int m)//按降幂顺序输出m元多项式的项,各项的系数已经按照题目要求存储于m维数组中,数组的头指针为a {

maxm=m;

for(i=m*n;i>=0;i--) //按降幂次序,可能出现的最高项次数为mn Get_All(a,m,i,0); //确定并输出所有次数为i的项 }//Print_Poly_Descend

void Get_All(int *a,int m,int i,int seq)//递归求出所有和为i的m个自然数 {

if(seq==maxm) Print_Nomial(a,exps); //已经求完时,输出该项 else {

min=i-(m-1)*n; //当前数不能小于min if(min<0) min=0;

max=n

exps[seq]=j; //依次取符合条件的数 Get_All(a,m-1,i-j,seq+1); //取下一个数 } }//else

exps[seq]=0; //返回 }//Get_All

void Print_Nomial(int *a,int exps[ ])//输出一个项,项的各变元的指数已经存储在数组exps中 {

pos=0;

for(i=0;i

pos*=n;

pos+=exps[i]; }

coef=*(a+pos); //取得该系数coef

if(!coef) return; //该项为0时无需输出

else if(coef>0) printf(\系数为正时打印加号 else if(coef<0) printf(\系数为负时打印减号

if(abs(coef)!=1) printf(\当系数的绝对值不为1时打印系数 for(i=0;i

if(exps[i]) //打印各变元及其系数 {

printf(\ printf(\ printf(\

if(exps[i]>1) printf(\系数为1时无需打印 }

}//Print_Nomial

分析:本算法的关键在于如何按照降幂顺序输出各项.这里采用了一个递归函数来找到所有满足和为i的m个自然数作为各变元的指数.只要先取第一个数为j,然后再找到所有满足和为i-j的m-1个自然数就行了.要注意j的取值范围必须使剩余m-1个自然数能够找到,所以不能小于i-(m-1)*maxn,也不能大于i.只要找到了一组符合条件的数,就可以在存储多项式系数的数组中确定对应的项的系数的位置,并且在系数不为0时输出对应的项.

5.21

void TSMatrix_Add(TSMatrix A,TSMatrix B,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].i

while(A.data[pa].i==x&&B.data[pb].i==x)//行列值都相等的元素 {

if(A.data[pa].j==B.data[pb].j) {

ce=A.data[pa].e+B.data[pb].e; if(ce) //和不为0 {

C.data[pc].i=x;

C.data[pc].j=A.data[pa].j; C.data[pc].e=ce; pa++;pb++;pc++; } }//if

else if(A.data[pa].j>B.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_Add 5.22

void TSMatrix_Addto(TSMatrix &A,TSMatrix B)//将三元组矩阵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].i

while(A.data[pa].i==x&&B.data[pb].i==x)//行列值都相等的元素 {

if(A.data[pa].j==B.data[pb].j) {

ne=A.data[pa].e+B.data[pb].e; if(ne) //和不为0 {

A.data[pc].i=x;

A.data[pc].j=A.data[pa].j; A.data[pc].e=ne; pa++;pb++;pc++; } }//if

else if(A.data[pa].j>B.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;i

typedef struct{

int j; int e;

} DSElem; typedef struct{

DSElem data[MAXSIZE];

int cpot[MAXROW];//这个向量存储每一行在二元组中的起始位置 int mu,nu,tu;

} DSMatrix; //二元组矩阵类型

Status DSMatrix_Locate(DSMatrix A,int i,int j,int &e)//求二元组矩阵的元素A[i][j]的值e {

for(s=A.cpot[i];s

e=A.data[s]; return OK; }

return ERROR; }//DSMatrix_Locate 5.24

typedef struct{

int seq; //该元素在以行为主序排列时的序号 int e; } SElem; typedef struct{

SElem data[MAXSIZE]; int mu,nu,tu;

} SMatrix; //单下标二元组矩阵类型

Status SMatrix_Locate(SMatrix A,int i,int j,int &e)//求单下标二元组矩阵的元素A[i][j]的值e {

s=i*A.nu+j+1;p=1;

while(A.data[p].seq

e=A.data[p].e; return OK; }

return ERROR; }//SMatrix_Locate 5.25

typedef enum{0,1} bool; typedef struct{

int mu,nu;

int elem[MAXSIZE]; bool map[mu][nu];

} BMMatrix; //用位图表示的矩阵类型

void BMMatrix_Add(BMMatrix A,BMMatrix B,BMMatrix &C)//位图矩阵的加法 {

C.mu=A.mu;C.nu=A.nu;

pa=1;pb=1;pc=1;

for(i=0;i

for(j=0;j

if(A.map[i][j]&&B.map[i][j]&&(A.elem[pa]+B.elem[pb]))//结果不为0 {

C.elem[pc]=A.elem[pa]+B.elem[pb]; C.map[i][j]=1; pa++;pb++;pc++; }

else if(A.map[i][j]&&!B.map[i][j]) {

C.elem[pc]=A.elem[pa]; C.map[i][j]=1; pa++;pc++; }

else if(!A.map[i][j]&&B.map[i][j]) {

C.elem[pc]=B.elem[pb]; C.map[i][j]=1; pb++;pc++; } }

}//BMMatrix_Add 5.26

void Print_OLMatrix(OLMatrix A)//以三元组格式输出十字链表表示的矩阵 {

for(i=0;i

if(A.rhead[i])

for(p=A.rhead[i];p;p=p->right) //逐次遍历每一个行链表 printf(\ }

}//Print_OLMatrix 5.27

void OLMatrix_Add(OLMatrix &A,OLMatrix B)//把十字链表表示的矩阵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; else pre->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

else if(pa->jj) {

pre=pa;

pa=pa->right; } //pa右移一步 else if(pa->e+pb->e) {

pa->e+=pb->e;

pre=pa;pa=pa->right; pb=pb->right; } //直接相加 else {

if(!pre) A.rhead[i]=pa->right; else pre->right=pa->right;

p=pa;pa=pa->right; //从行链表中删除 if(A.chead[p->j]==p)

A.chead[p->j]=cp[p->j]=p->down;

else cp[p->j]->down=p->down; //从列链表中删除 free (p); }//else }//while }//for

}//OLMatrix_Add

分析:本题的具体思想在课本中有详细的解释说明.

5.28

void MPList_PianDao(MPList &L)//对广义表存储结构的多元多项式求第一变元的偏导 {

for(p=L->hp->tp;p&&p->exp;pre=p,p=p->tp) {

if(p->tag) Mul(p->hp,p->exp);

else p->coef*=p->exp; //把指数乘在本结点或其下属结点上 p->exp--; }

pre->tp=NULL;

if(p) free (p); //删除可能存在的常数项 }//MPList_PianDao

void Mul(MPList &L,int x)//递归算法,对多元多项式L乘以x {

for(p=L;p;p=p->tp) {

if(!p->tag) p->coef*=x; else Mul(p->hp,x); } }//Mul 5.29

void MPList_Add(MPList A,MPList B,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

else if(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; }

else if(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;

} //将其同次项分别相加得到新的多项式,原理见第二章多项式相加一题 }//else if

else if(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;

} //否则新建常数项,下同 }//else if 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_Add 5.30

int GList_Getdeph(GList L)//求广义表深度的递归算法 {

if(!L->tag) return 0; //原子深度为0 else if(!L) return 1; //空表深度为1 m=GList_Getdeph(L->ptr.hp)+1; n=GList_Getdeph(L->ptr.tp); return m>n?m:n; }//GList_Getdeph 5.31

void GList_Copy(GList A,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_Copy 5.32

int GList_Equal(GList A,GList B)//判断广义表A和B是否相等,是则返回1,否则返回0 { //广义表相等可分三种情况:

if(!A&&!B) return 1; //空表是相等的

if(!A->tag&&!B->tag&&A->atom==B->atom) return 1;//原子的值相等 if(A->tag&&B->tag)

if(GList_Equal(A->ptr.hp,B->ptr.hp)&&GList_Equal(A->ptr.tp,B->ptr.tp)) return 1; //表头表尾都相等 return 0;

}//GList_Equal 5.33

void GList_PrintElem(GList A,int layer)//递归输出广义表的原子及其所在层次,layer表示当前层次 {

if(!A) return;

if(!A->tag) printf(\ else {

GList_PrintElem(A->ptr.hp,layer+1);

GList_PrintElem(A->ptr.tp,layer); //注意尾表与原表是同一层次 }

}//GList_PrintElem 5.34

void GList_Reverse(GList A)//递归逆转广义表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_Reverse 5.35

Status Create_GList(GList &L)//根据输入创建广义表L,并返回指针 {

scanf(\ if(ch==' ') {

L=NULL;

scanf(\

if(ch!=')') return ERROR; return OK; }

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

else if(ch=='(') Create_GList(L->ptr.hp); //建子表型表头 else return ERROR; scanf (\

if(ch==')') L->ptr.tp=NULL;

else if(ch==',') Create_GList(L->ptr.tp); //建表尾 else return ERROR; return OK; }//Create_GList

分析:本题思路见书后解答. 5.36

void GList_PrintList(GList A)//按标准形式输出广义表 {

if(!A) printf(\空表

else if(!A->tag) printf(\原子

else {

printf(\

for(p=A;p;p=p->ptr.tp) {

GList_PrintList(p->ptr.hp);

if(p->ptr.tp) printf(\ //只有当表尾非空时才需要打印逗号 }

printf(\ }//else

}//GList_PrintList 5.37

void GList_DelElem(GList &A,int x)//从广义表A中删除所有值为x的原子 {

if(A&&A->ptr.hp) {

if(A->ptr.hp->tag) GList_DelElem(A->ptr.hp,x); else if(!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_DelElem 5.39

void GList_PrintElem_LOrder(GList A)//按层序输出广义表A中的所有元素 {

InitQueue(Q);

for(p=L;p;p=p->ptr.tp) EnQueue(Q,p); while(!QueueEmpty(Q)) {

DeQueue(Q,r);

if(!r->tag) printf(\ else

for(r=r->ptr.hp;r;r=r->ptr.tp) EnQueue(Q,r); }//while

}//GList_PrintElem_LOrder

分析:层序遍历的问题,一般都是借助队列来完成的,每次从队头取出一个元素的同时把它下一层的孩子插入队尾.这是层序遍历的基本思想.

第六章 树和二叉树

6.33

int Is_Descendant_C(int u,int v)//在孩子存储结构上判断u是否v的子孙,是则返回1,否则返回0 {

if(u==v) return 1; else {

if(L[v])

if (Is_Descendant(u,L[v])) return 1; if(R[v])

if (Is_Descendant(u,R[v])) return 1; //这是个递归算法 }

return 0;

}//Is_Descendant_C 6.34

int Is_Descendant_P(int u,int v)//在双亲存储结构上判断u是否v的子孙,是则返回1,否则返回0 {

for(p=u;p!=v&&p;p=T[p]); if(p==v) return 1; else return 0;

}//Is_Descendant_P 6.35

这一题根本不需要写什么算法,见书后注释:两个整数的值是相等的. 6.36

int Bitree_Sim(Bitree B1,Bitree B2)//判断两棵树是否相似的递归算法 {

if(!B1&&!B2) return 1;

else if(B1&&B2&&Bitree_Sim(B1->lchild,B2->lchild)&&Bitree_Sim(B1->rchild,B2->rchild)) return 1; else return 0; }//Bitree_Sim 6.37

void PreOrder_Nonrecursive(Bitree T)//先序遍历二叉树的非递归算法 {

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_Nonrecursive 6.38

typedef struct {

BTNode* ptr;

enum {0,1,2} mark;

} PMType; //有mark域的结点指针类型

void PostOrder_Stack(BiTree T)//后续遍历二叉树的非递归算法,用栈 {

PMType a;

InitStack(S); //S的元素为PMType类型 Push (S,{T,0}); //根结点入栈 while(!StackEmpty(S)) {

Pop(S,a);

switch(a.mark) {

case 0:

Push(S,{a.ptr,1}); //修改mark域

if(a.ptr->lchild) Push(S,{a.ptr->lchild,0}); //访问左子树 break; case 1:

Push(S,{a.ptr,2}); //修改mark域

if(a.ptr->rchild) Push(S,{a.ptr->rchild,0}); //访问右子树 break; case 2:

visit(a.ptr); //访问结点,返回 } }//while

}//PostOrder_Stack

分析:为了区分两次过栈的不同处理方式,在堆栈中增加一个mark域,mark=0表示刚刚访问此结点,mark=1表示左子树处理结束返回,mark=2表示右子树处理结束返回.每次根据栈顶元素的mark域值决定做何种动作. 6.39

typedef struct {

int data;

EBTNode *lchild; EBTNode *rchild; EBTNode *parent; enum {0,1,2} mark;

} EBTNode,EBitree; //有mark域和双亲指针域的二叉树结点类型 void PostOrder_Nonrecursive(EBitree T)//后序遍历二叉树的非递归算法,不用栈 { p=T; while(p)

switch(p->mark) {

case 0:

p->mark=1;

if(p->lchild) p=p->lchild; //访问左子树 break; case 1:

p->mark=2;

if(p->rchild) p=p->rchild; //访问右子树 break; case 2: visit(p);

p->mark=0; //恢复mark值 p=p->parent; //返回双亲结点

}

}//PostOrder_Nonrecursive

分析:本题思路与上一题完全相同,只不过结点的mark值是储存在结点中的,而不是暂存在堆栈中,所以访问完毕后要将mark域恢复为0,以备下一次遍历. 6.40

typedef struct {

int data;

PBTNode *lchild; PBTNode *rchild; PBTNode *parent;

} PBTNode,PBitree; //有双亲指针域的二叉树结点类型

void Inorder_Nonrecursive(PBitree T)//不设栈非递归遍历有双亲指针的二叉树 { p=T;

while(p->lchild) p=p->lchild; //向左走到尽头 while(p) {

visit(p);

if(p->rchild) //寻找中序后继:当有右子树时 {

p=p->rchild;

while(p->lchild) p=p->lchild; //后继就是在右子树中向左走到尽头 }

else if(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_Nonrecursive 6.41

int c,k; //这里把k和计数器c作为全局变量处理

void Get_PreSeq(Bitree T)//求先序序列为k的结点的值 { if(T) {

c++; //每访问一个子树的根都会使前序序号计数器加1 if(c==k) {

printf(\ exit (1); } else {

Get_PreSeq(T->lchild); //在左子树中查找 Get_PreSeq(T->rchild); //在右子树中查找 } }//if

}//Get_PreSeq main() { ...

scanf(\

本文来源:https://www.bwwdw.com/article/0dw2.html

Top