注意:此处代码可能并非最优化结果,等待代码优化中。。。。 ◆1.16② 试写一算法,如果三个整数X,Y和Z 的值不是依次非递增的,则通过交换,令其为 非递增。
要求实现下列函数:
void Descend(int &x, int &y, int &z); /* 按从大到小顺序返回x,y和z的值 */
void Descend(int &x, int &y, int &z) /* 按从大到小顺序返回x,y和z的值 */ {
int temp;
if(x 试编写求k阶裴波那契序列的第m项值的函数算法, k和m均以值调用的形式在函数参数表中出现。 要求实现下列函数: Status Fibonacci(int k, int m, int &f); /* 如果能求得k阶斐波那契序列的第m项的值f,则返回OK;*/ /* 否则(比如,参数k和m不合理)返回ERROR */ Status Fibonacci(int k, int m, int &f) /* 求k阶斐波那契序列的第m项的值f */ //没想到m竟然是从0开始的∵ ∵ { int i; long temp; int a[1000]; if(k<=1||m<0){return ERROR;} for(i=0;i if(temp>MAXINT) return ERROR; temp=temp-a[i-k-1]+a[i-1]; a[i]=temp; } f=a[m]; return OK; } 1.18③ 假设有A、B、C、D、E五个高等院校进行田径对抗赛, 各院校的单项成绩均以存入计算机并构成一张表,表中每一 行的形式为 项目名称 性别 校名 成绩 得分 编写算法,处理上述表格,以统计各院校的男、女总分和团 体总分,并输出。 要求实现下列函数: void Scores(ResultType *result, ScoreType *score); /* 求各校的男、女总分和团体总分, 并依次存入数组score */ /* 假设比赛结果已经储存在result[ ]数组中, */ /* 并以特殊记录 {“”, male, „ „, “”, 0 }(域scorce=0)*/ /* 表示结束 */ 相关数据类型定义如下: typedef enum {female,male} Sex; typedef struct{ char *sport; // 项目名称 Sex gender; // 性别(女:female;男:male) char schoolname; // 校名为’A',’B',’C',’D'或’E’ char *result; // 成绩 int score; // 得分(7,5,4,3,2或1) } ResultType; typedef struct{ int malescore; // 男子总分 int femalescore; // 女子总分 int totalscore; // 男女团体总分 } ScoreType; void Scores(ResultType *result, ScoreType *score) /* 求各校的男、女总分和团体总分, 并依次存入数组score */ /* 假设比赛结果已经储存在result[ ]数组中, */ /* 并以特殊记录 {\"\(域scorce=0)*/ /* 表示结束 */ //感觉这道题题意有点模糊.... { int i,j; for(j=0;j<5;++j){ i=0; score[j].malescore=0; score[j].femalescore=0; while(result[i].score!=0) { if('A'+j==result[i].schoolname){ if(male==result[i].gender) score[j].malescore+=result[i].score; if(female==result[i].gender) score[j].femalescore+=result[i].score; } score[j].totalscore=score[j].malescore+score[j].femalescore; ++i; } } } ◆1.19④ 试编写算法,计算i!×2^i的值并存入数组 a[0..ARRSIZE-1]的第i-1个分量中 (i=1,2,…,n)。 假设计算机中允许的整数最大值为MAXINT,则当n> ARRSIZE或对某个k(1≤k≤n)使k!×2^k>MAXINT时,应 按出错处理。注意选择你认为较好的出错处理方法。 要求实现下列函数: Status Series(int ARRSIZE, int a[]); /* 求i!*2^i序列的值并依次存入长度为ARRSIZE的数组a; */ /* 若所有值均不超过MAXINT,则返回OK,否则返回OVERFLOW */ Status Series(int ARRSIZE, int a[]) /* 求i!*2^i序列的值并依次存入长度为ARRSIZE的数组a; */ /* 若所有值均不超过MAXINT,则返回OK,否则返回OVERFLOW */ { int i=1,temp=1; while(i<=ARRSIZE){ if(MAXINT/temp<2*i)return OVERFLOW; temp*=2; temp*=i; a[i-1]=temp; ++i; } return OK; } ◆1.20④ 试编写算法求一元多项式 P(x) = a0 + a1x + a2x^2 + … + anx^n 的值P(x0),并确定算法中每一语句的执行次数和整个算法 的时间复杂度。注意选择你认为较好的输入和输出方法。 要求实现下列函数: float Polynomial(int n, int a[], float x0); /* 求一元多项式的值P(x0)。 */ /* 数组a的元素a[i]为i次项的系数,i=0,1,…,n */ float Polynomial(int n, int a[], float x) /* 求一元多项式的值P(x)。 */ /* 数组a的元素a[i]为i次项的系数,i=0,...,n */ { int i=1; float temp=1; float total=a[0]; if(0==n){return total;} while(i<=n){ temp*=x; total+=a[i]*temp; ++i; } return total; } 数据结构习题集 第2章答案 ◆2.11② 设顺序表L中的数据元素递增有序。 试写一算法,将x插入到L的适当位置上,并保 持该表的有序性。 要求实现下列函数: void InsertOrderList(SqList &L, ElemType x) /* 在有序的顺序表 L 中保序插入数据元素 x */ 顺序表类型定义如下: typedef struct { ElemType *elem; int length; int listsize; } SqList; void InsertOrderList(SqList &L, ElemType x) // 在有序的顺序表 L 中保序插入数据元素 x { ElemType *p,*q; p=L.elem; while(*p L.elem=(ElemType *)realloc(L.elem,L.listsize+10); if(L.elem){ exit(OVERFLOW); } L.listsize+=10; } for(q=L.elem+L.length-1;q>=p;q--){ *(q+1)=*q; } *p=x; ++L.length; } ◆2.12③ 设A=(a1,…,am)和B=(b1,…,bn)均为有序顺序表, A‟和B‟分别为A和B中除去最大共同前缀后的子表(例如, A=(x,y,y,z,x,z),B=(x,y,y,z,y,x,x,z),则两者中最大 的共同前缀为(x,y,y,z), 在两表中除去最大共同前缀后 的子表分别为A‟=(x,z)和B‟=(y,x,x,z))。若A‟=B‟=空表, 则A=B;若A‟=空表,而B‟≠ 空表,或者两者均不为空表, 且A‟的首元小于B‟的首元,则AB。试写一个比 较A和B大小的算法。(注意:在算法中,不要破坏原表A 和B,也不一定先求得A‟和B‟才进行比较)。 要求实现下列函数: char Compare(SqList A, SqList B); /* 比较顺序表A和B, */ /* 返回‟<', 若A /* '=', 若A=B; */ /* '>„, 若A>B */ 顺序表类型定义如下: typedef struct { ElemType *elem; int length; int listsize; } SqList; char Compare(SqList A, SqList B) // 比较顺序表A和B, // 返回'<', 若A', 若A>B { char a,b; int la=1,lb=1; while(la<=A.length&&lb<=B.length){ if(*(A.elem+la-1)>*(B.elem+lb-1)){return '>';} else if(*(A.elem+la-1)<*(B.elem+lb-1)){return '<';} ++la; ++lb; } if(A.length==B.length) return '='; //此处应先判断长度是否相等!! if(la==A.length+1){return '<';} if(lb==B.length+1){return '>';} } 2.13② 试写一算法在带头结点的单链表结构上实现线性表操作 Locate(L,x)。 实现下列函数: LinkList Locate(LinkList L, ElemType x); // If „x‟ in the linked list whose head node is pointed // by „L‟, then return pointer pointing node „x‟, // otherwise return „NULL‟ 单链表类型定义如下: typedef struct LNode { ElemType data; struct LNode *next; } LNode, *LinkList; LinkList Locate(LinkList &L, ElemType x) // If 'x' in the linked list whose head node is pointed // by 'L', then return pointer ha pointing node 'x', // otherwise return 'NULL' { LinkList p=L->next; while(p){ if(x==p->data){ return p; } p=p->next; } return NULL; } 2.14② 试写一算法在带头结点的单链表结构上实现线性表 操作Length(L)。 实现下列函数: int Length(LinkList L); // Return the length of the linked list // whose head node is pointed by „L‟ 单链表类型定义如下: typedef struct LNode{ ElemType data; struct LNode *next; } LNode, *LinkList; int Length(LinkList L) // Return the length of the linked list // whose head node is pointed by 'L' { int i=0; LinkList p=L; while(p->next){ ++i; p=p->next; } return i; } 2.17② 试写一算法,在无头结点的动态单链表上实现 线性表操作INSERT(L,i,b),并和在带头结点的动态单 链表上实现相同操作的算法进行比较。 实现下列函数: void Insert(LinkList &L, int i, ElemType b); 单链表类型定义如下: typedef struct LNode{ ElemType data; struct LNode *next; } LNode, *LinkList; //思路不是很清晰,很多细节问题,调试了很长时间 //主要考虑问题:1、i为0或负数时 2、i在链表长度内 3、i为链表长度+1时 4、代码精简 void Insert(LinkList &L, int i, ElemType b) { int j,count; LinkList p=L,q=L; if(i<0){exit(OVERFLOW);} for(count=0;p!=NULL;++count){ p=p->next; } if(1==i){ p=(LinkList)malloc(sizeof(LNode)); p->data=b; p->next=L; L=p; } else if (i>1&&i<=count+1){ for(p=L,j=1;j<=i-1&&p;++j){ q=p;//p为第j个元素的指针,q为p的j-1个指针 p=p->next; } p=(LinkList)malloc(sizeof(LNode)); p->data=b; p->next=q->next; q->next=p; } } 2.18② 同2.17题要求。试写一算法, 实现线性表操作DELETE(L,i)。 实现下列函数: void Delete(LinkList &L, int i); 单链表类型定义如下: typedef struct LNode{ ElemType data; struct LNode *next; } LNode, *LinkList; void Delete(LinkList &L, int i) { int j; int count=0; LinkList p=L,q; //1、求链表长度 while(p){ p=p->next; ++count; } //2、查找第i-1号元素 //特殊位置首位、末尾 p=L; if(1==i){ L=p->next; free(p); } //i==0时没问题 else if(i>1&&i<=count) { for(p=L,j=1;j q=p->next; p->next=q->next; free(q); } } 2.20② 同2.19题条件,试写一高效的算法,删除表中所 有值相同的多余元素 (使得操作后的线性表中所有元素的 值均不相同) 同时释放被删结点空间,并分析你的算法的 时间复杂度。 实现下列函数: void Purge(LinkList &L); 单链表类型定义如下: typedef struct LNode{ ElemType data; struct LNode *next; } LNode, *LinkList; void Purge(LinkList &L) { ElemType last=L->next->data; LinkList q=L->next,p=L->next; while(p){ if(last==p->data&&p!=L->next){ q->next=p->next; free(p); p=q; } else {last=p->data;} q=p; p=p->next; } } ◆2.21③ 试写一算法,实现顺序表的就地逆置, 即利用原表的存储空间将线性表(a1,a2,…,an) 逆置为(an,an-1,…,a1)。 实现下列函数: void Inverse(SqList &L); 顺序表类型定义如下: typedef struct { ElemType *elem; int length; int listsize; } SqList; void Inverse(SqList &L) { int i; ElemType *p,temp; p=L.elem; for(i=0;i ◆2.22③ 试写一算法,对单链表实现就地逆置。 实现下列函数: void Inverse(LinkList &L); /* 对带头结点的单链表L实现就地逆置 */ 单链表类型定义如下: typedef struct LNode{ ElemType data; struct LNode *next; } LNode, *LinkList; void Inverse(LinkList &L) /* 对带头结点的单链表L实现就地逆置 */ { LinkList last,cur,q; q=L->next; //保存首元素地址 last=L->next;//上一个指针 cur=L->next; //当前操作的指针 if(cur){ while(cur){//此处没注意,写成了!cur,大意失荆州啊! cur=L->next; L->next=cur->next; cur->next=last; if(cur){last=cur;} } L->next=last; q->next=NULL; } } 2.23③ 设线性表A=(a1,…,am), B=(b1,…,bn),试写 一个按下列规则合并A、B为线性表C的算法,即使得 C=(a1,b1,…,am,bm,bm+1,…,bn) 当m≤n时; 或者 C=(a1,b1,…,an,bn,an+1,…,am) 当m>n时。 线性表A、B和C均以单链表作存储结构,且C表利用A表和 B表中的结点空间构成。注意:单链表的长度值m和n均未 显式存储。 实现下列函数: void Merge(LinkList ha, LinkList hb, LinkList &hc) /* 依题意,合并带头结点的单链表ha和hb为hc */ 单链表类型定义如下: typedef struct LNode{ ElemType data; struct LNode *next; } LNode, *LinkList; void Merge(LinkList ha, LinkList hb, LinkList &hc) /* 依题意,合并带头结点的单链表ha和hb为hc */ { LinkList cur_a,cur_b,cur_c; cur_a=ha->next; cur_b=hb->next; cur_c=ha;//这里要注意给cur_c赋值,不然地址为空 while(cur_a&&cur_b){ cur_c->next=cur_a;//Lc的next指向a; cur_c=cur_c->next;//cur_c指向c->next cur_a=cur_a->next;//cur_a指向a->next cur_c->next=cur_b;//cur_c的next指向b cur_c=cur_c->next;//cur_c指向b cur_b=cur_b->next;//cur_b指向b->next } if(cur_a){ cur_c->next=cur_a; } if(cur_b){ cur_c->next=cur_b; } hc=ha; } ◆2.24④ 假设有两个按元素值递增有序排列的线性表 A和B,均以单链表作存储结构,请编写算法将A表和B表 归并成一个按元素值递减有序(即非递增有序,允许表 中含有值相同的元素)排列的线性表C, 并要求利用原 表(即A表和B表)的结点空间构造C表。 实现下列函数: void Union(LinkList &lc, LinkList la, LinkList lb); /* 依题意,利用la和lb原表的结点空间构造lc表 */ 单链表类型定义如下: typedef struct LNode{ ElemType data; struct LNode *next; } LNode, *LinkList; void Union(LinkList &lc, LinkList &la, LinkList &lb) { LinkList temp,last,q; if(la->next->data<=lb->next->data){ q=la->next;last=la->next; } else { q=lb->next;last=lb->next; } while(la->next&&lb->next){ if(la->next->data<=lb->next->data){ temp=la->next; la->next=temp->next; temp->next=last; last=temp; } else{ temp=lb->next; lb->next=temp->next; temp->next=last; last=temp; } } // while(la->next){ temp=la->next; la->next=temp->next; temp->next=last; last=temp; } while(lb->next){ temp=lb->next; lb->next=temp->next; temp->next=last; last=temp; } q->next=NULL; lc=la; lc->next=temp; } 2.31② 假设某个单向循环链表的长度大于1,且表 中既无头结点也无头指针。已知s为指向链表中某个 结点的指针,试编写算法在链表中删除指针s所指结 点的前驱结点。 实现下列函数: ElemType DeleteNode(LinkList s); /* 删除指针s所指结点的前驱结点,并返回被删结点的元素值 */ 单链表类型定义如下: typedef struct LNode{ ElemType data; struct LNode *next; } LNode, *LinkList; ElemType DeleteNode(LinkList s) /* 删除指针s所指结点的前驱结点,并返回被删结点的元素值 */ { ElemType e; LinkList p,temp=s; while(temp->next->next!=s){ temp=temp->next; } e=temp->next->data; p=temp->next; temp->next=s; free(p); return e; } 2.32② 已知有一个单向循环链表,其每个结点中 含三个域:prev、data和next,其中data为数据域, next为指向后继结点的指针域,prev也为指针域, 但它的值为空(NULL),试编写算法将此单向循环链 表改为双向循环链表,即使prev成为指向前驱结点 的指针域。 实现下列函数: void PerfectBiLink(BiLinkList &CL); 双向循环链表类型定义如下: typedef struct BiNode { ElemType data; int freq; // 2.38题用 struct BiNode *prev, *next; } BiNode, *BiLinkList; void PerfectBiLink(BiLinkList &CL) { BiLinkList p; p=CL; p->next->prev=p; p=p->next; while(p!=CL){ p->next->prev=p; p=p->next; } } ◆2.33③ 已知由一个线性链表表示的线性表中含有 三类字符的数据元素(如:字母字符、数字字符和其 它字符),试编写算法将该线性链表分割为三个循环 链表,其中每个循环链表表示的线性表中均只含一类 字符。 实现下列函数: void Split(LinkList &lc, LinkList &ld, LinkList &lo, LinkList ll); 单链表类型定义如下: typedef struct LNode{ ElemType data; struct LNode *next; } LNode, *LinkList; void Split(LinkList &lc, LinkList &ld, LinkList &lo, LinkList ll) { LinkList p,cur_c,cur_d,cur_o; p=ll->next; cur_c=lc; cur_d=ld; cur_o=lo; while(p){ if(p->data>='A'&&p->data<='z'){ cur_c->next=p; cur_c=cur_c->next; } else if(p->data>='0'&&p->data<='9'){ cur_d->next=p; cur_d=cur_d->next; } else{ cur_o->next=p; cur_o=cur_o->next; } p=p->next; } cur_c->next=lc; cur_d->next=ld; cur_o->next=lo; } 2.37④ 设以带头结点的双向循环链表表示的线性 表L=(a1,a2,…,an)。试写一时间复杂度为O(n)的 算法,将L改造为L=(a1,a3,…,an,…,a4,a2)。 实现下列函数: void ReverseEven(BiLinkList &L); 双向循环链表类型定义如下: typedef struct BiNode { ElemType data; int freq; // 2.38题用 struct BiNode *prev, *next; } BiNode, *BiLinkList; void ReverseEven(BiLinkList &L) { BiLinkList last,p,temp; int count=0; //用count计结点个数 p=L->next; //p指向第一个元素 while(p!=L->prev){//求链表长度-1 ++count; p=p->next; } last=p;//获得最后一个元素的地址 if(count>=2){ p=p->prev; while(p!=L->next){//当p指向的不是第一个元素时 if(0==count%2){//判断是否序号为偶数的结点 temp=p; p=p->prev; temp->prev->next=temp->next; temp->next->prev=temp->prev; last->next=temp; temp->prev=last; last=temp; } else{//奇号结点则继续往前 p=p->prev; } --count; } last->next=L;//构建循环 L->prev=last;//构建循环 } } ◆2.39③ 试对稀疏多项式Pn(x)采用存储量同多项式项 数m成正比的顺序存储结构,编写求Pn(x0)的算法(x0为 给定值),并分析你的算法的时间复杂度。 实现下列函数: float Evaluate(SqPoly pn, float x); /* pn.data[i].coef 存放ai, */ /* pn.data[i].exp存放ei (i=1,2,…,m) */ /* 本算法计算并返回多项式的值。不判别溢出。 */ /* 入口时要求0≤e1 typedef struct { int coef; int exp; } PolyTerm; typedef struct { PolyTerm *data; int length; } SqPoly; float Evaluate(SqPoly pn, float x) /* pn.data[i].coef 存放ai, */ /* pn.data[i].exp存放ei (i=1,2,...,m) */ /* 本算法计算并返回多项式的值。不判别溢出。 */ /* 入口时要求0≤e1 total+=temp*(pn.data[i].coef); ++i; } return total; } ◆2.41② 试以循环链表作稀疏多项式的存储结构, 编写求其导函数的算法,要求利用原多项式中的结 点空间存放其导函数(多项式),同时释放所有无 用(被删)结点。 实现下列函数: void Difference(LinkedPoly &pa); /* 稀疏多项式 pa 以循环链表作存储结构, */ /* 将此链表修改成它的导函数,并释放无用结点 */ 链式多项式的类型定义: typedef struct PolyNode { int coef; int exp; struct PolyNode *next; } PolyNode, *PolyLink; // 多项式元素(项)结点类型 typedef PolyLink LinkedPoly; // 链式多项式 void Difference(LinkedPoly &pa) /* 稀疏多项式 pa 以循环链表作存储结构, */ /* 将此链表修改成它的导函数,并释放无用结点 */ { LinkedPoly cur=pa->next,last=pa->next,tail=pa->next; if(pa->next){//此处改为cur时遇到空表会出错,不知道为什么 if(0==last->exp){cur=cur->next;last->coef=0;} while(cur!=pa){ last->coef=cur->coef*(cur->exp); last->exp=cur->exp-1; tail=last; last=last->next; cur=cur->next; } if(cur=last->next){free(last);tail->next=pa;} } } 数据结构习题集 第3章答案 ◆3.17③ 试写一个算法,识别依次读入的一个以@ 为结束符的字符序列是否为形如‟序列1&序列2′模式 的字符序列。其中序列1和序列2中都不含字符‟&', 且序列2是序列1的逆序列。例如,‟a+b&b+a‟是属该 模式的字符序列,而‟1+3&3-1′则不是。 实现下列函数: Status match(char *str); /* 若str是属该模式的字符序列,*/ /* 则返回TRUE,否则返回FALSE */ Stack是一个已实现的栈。 可使用的相关类型和函数: typedef char SElemType; // 栈Stack的元素类型 Status InitStack(Stack &s); Status Push(Stack &s, SElemType e); Status Pop(Stack &s, SElemType &e); Status StackEmpty(Stack s); Status GetTop(Stack s, SElemType &e); Status match(char *str) /* 若str是属该模式的字符序列,*/ /* 则返回TRUE,否则返回FALSE */ { //文档没有说明字符串是以@结尾的 //也没有说栈的类型是SqStack,用Stack时编译出错 SqStack s; SElemType c; Status flag=1; InitStack(s); char *cur=str; while('&'!=*cur){ Push(s,*cur); ++cur; } //入栈 ++cur; if(!GetTop(s,c)&&*cur!='@'){flag=0;}//判断栈空 while(*cur!='@' ){ Pop(s,c); if(c!=*cur){flag=0;break;} ++cur; }//依次出栈匹配 if(GetTop(s,c)){flag=0;}//再次判断是否非空 return flag; } 3.18② 试写一个判别表达式中开、闭括号是否配对出现的算法。 实现下列函数: Status MatchCheck(SqList exp); /* 顺序表exp表示表达式; */ /* 若exp中的括号配对,则返回TRUE,否则返回FALSE */ /* 注:本函数不使用栈 */ 顺序表类型定义如下: typedef struct { ElemType *elem; int length; int listsize; } SqList; // 顺序表 Status MatchCheck(SqList exp) /* 顺序表exp表示表达式; */ /* 若exp中的括号配对,则返回TRUE,否则返回FALSE */ /* 注:本函数不使用栈 */ /*****************************/ // 此题top指针和cur指针要很仔细地运用,还有判错条件也要小心 { ElemType *cur,*top,*base; base=exp.elem;//模拟栈底 top=cur=base+1;//模拟栈顶(top)和当前元素(cur) if(')'==*cur){ return FALSE; } //判断第一个字符是否为右括号 if(0==exp.length){ return TRUE; }//判断是否为空顺序表 while(cur<=base+exp.length-1){//依次遍历 if('('==*cur){//当元素为左括号时 if(top!=cur){ *top=*cur; *cur='0'; } ++top; }//top始终指向第二个元素 //////////////////////////// else if(')'==*cur){ if(top==base){ return FALSE; } if('('==*(top-1)){ *(--top)='0'; *cur='0'; } } //////////////////////////// ++cur; } if('0'==*base){return TRUE;}//此处应为base,而不是top return FALSE; } ◆3.19④ 假设一个算术表达式中可以包含三种括号:圆括号”(” 和 “)”,方括号”[\"和\"]“和花括号”{“和”}”,且这三种括号可按任意的 次序嵌套使用(如:…[…{…}…[…]…]…[…]…(…)…)。编写判别给定表达 式中所含括号是否正确配对出现的算法(已知表达式已存入数据元素 为字符的顺序表中)。 实现下列函数: Status MatchCheck(SqList exp); /* 顺序表exp表示表达式; */ /* 若exp中的括号配对,则返回TRUE,否则返回FALSE */ 顺序表类型定义如下: typedef struct { ElemType *elem; int length; int listsize; } SqList; // 顺序表 Stack是一个已实现的栈。 可使用的相关类型和函数: typedef char SElemType; // 栈Stack的元素类型 Status InitStack(Stack &s); Status Push(Stack &s, SElemType e); Status Pop(Stack &s, SElemType &e); Status StackEmpty(Stack s); Status GetTop(Stack s, SElemType &e); Status MatchCheck(SqList exp) /* 顺序表exp表示表达式; */ /* 若exp中的括号配对,则返回TRUE,否则返回FALSE */ { ElemType *cur=exp.elem; SElemType temp; SqStack s; InitStack(s); if(0==exp.length){return 1;} while(cur<=exp.elem+exp.length-1){ if('['==*cur||'('==*cur||'{'==*cur){ Push(s,*cur); } else{ GetTop(s,temp); if(StackEmpty(s)){//粗心,栈空时返回的是1而不是0 return 0; } else if(']'==*cur&&'['==temp){ Pop(s,temp); } else if(')'==*cur&&'('==temp){ Pop(s,temp); } else if('}'==*cur&&'{'==temp){ Pop(s,temp); } } ++cur; } if(StackEmpty(s))return 1;//粗心,栈空时返回的是1而不是0 return 0; } 3.20③ 假设以二维数组g(1..m,1..n)表示一个图像 区域,g[i,j]表示该区域中点(i,j)所具颜色,其值 为从0到k的整数。编写算法置换点(i0,j0)所在区域 的颜色。约定和(i0,j0)同色的上、下、左、右的邻 接点为同色区域的点。 实现下列函数: void ChangeColor(GTYPE g, int m, int n, char c, int i0, int j0); /* 在g[1..m][1..n]中,将元素g[i0][j0] */ /* 所在的同色区域的颜色置换为颜色c */ 表示图像区域的类型定义如下: typedef char GTYPE[m+1][n+1]; Stack是一个已实现的栈。 可使用的相关类型和函数: typedef int SElemType; // 栈Stack的元素类型 Status StackInit(Stack &s, int initsize); Status Push(Stack &s, SElemType e); Status Pop(Stack &s, SElemType &e); Status StackEmpty(Stack s); Status GetTop(Stack s, SElemType &e); void ChangeColor(GTYPE g, int m, int n, char c, int i0, int j0) /* 在g[1..m][1..n]中,将元素g[i0][j0] */ /* 所在的同色区域的颜色置换为颜色c */ /* 说明:di=1,2,3,4分别为东南西北四个方向,表示的是下一位置在当前位置的哪 个方向! 因为数组的下标的性质,只要知道di就能够退回到上一个位置, 而如果第一个元素四周都没有同色元素之后(栈空),结束程序 */ { SqStack S; InitStack(S); int x,y,di; char color; if(i0<=0||i0>m||j0<=0||j0>n){ exit(OVERFLOW); } x=i0; y=j0; color=g[x][y]; do{ if(x>0&&y>0&&x<=m&&y<=n&&color==g[x][y]){ di=1;//设置方向为东 g[x][y]=c; Push(S,di); y=y+1;//当前位置切换为东边的元素 } else{ Pop(S,di); switch(di){//当前位置非同色或不合法,设置当前位置为上一位置 (回退) case 1:--y;break; case 2:--x;break; case 3:++y;break; case 4:++x;break; } ++di; if(di<=4){//若di>4,相当于只回退 switch(di){//切换当前位置到下一位置 case 1:++y;break;//东临 case 2:++x;break;//南 case 3:--y;break;//西 case 4:--x;break;//北 } Push(S,di); } } }while(!StackEmpty(S)); } ◆3.21③ 假设表达式由单字母变量和双目四则运 算算符构成。试写一个算法,将一个通常书写形式 且书写正确的表达式转换为逆波兰式。 实现下列函数: char *RPExpression(char *e); /* 返回表达式e的逆波兰式 */ Stack是一个已实现的栈。 可使用的相关类型和函数: typedef char SElemType; // 栈Stack的元素类型 Status InitStack(Stack &s); Status Push(Stack &s, SElemType e); Status Pop(Stack &s, SElemType &e); Status StackEmpty(Stack s); SElemType Top(Stack s); char *RPExpression(char *e) /* 返回表达式e的逆波兰式 */ //由于个人水平,折腾了很就才通过 //主要思路如下: //1 建立优先级表,符号表,栈中元素对应符号 //2 依此读取字符,判断是运算符还是数字,如果数字直接入后缀表达式栈, //如果是运算符,则判断与栈顶元素优先级关系,进行响应操作 /* 容易犯错的地方 1 优先级关系不正确 2 当*p优先级低于运算符栈顶时,出栈,但忘了继续比较 3 忘了字符串长度应该为length+1,因为最后'\\0' 变量说明 OPTR 运算符栈 rpe 后缀表达式栈 opera 数组为运算符表 list 数组为优先级表 pre_optr 记录运算符栈元素的代表数字 */ { int i=0,j=0,op1,op2,pre=2,count=0; char *p=e,*head,temp,s[100]; Stack OPTR,rpe; int pre_optr[10]; char opera[7]={'+','-','*','/','(',')','#'}; int list[7][7]={{1,1,-1,-1,-1,1,1} ,{1,1,-1,-1,-1,1,1} ,{1,1,1,1,-1,1,1} ,{1,1,1,1,-1,1,1} ,{-1,-1,-1,-1,-1,0,-2} ,{1,1,1,1,-2,1,1} ,{-1,-1,-1,-1,-1,-2,0}}; InitStack(OPTR); InitStack(rpe); while(*p){ //计算出转换后表达式的长度 if('('!=*p&&')'!=*p){ ++count; } ++p; } p=e; Push(OPTR,'#'); pre_optr[j]=6; while(*p){//依此读入字符,进行相应处理 for(i=0;i<7;++i){ if(opera[i]==*p){ break; } } op2=i; if(7==op2){//判断是否为数字 Push(rpe,*p); } else{ op1=pre_optr[j]; pre=list[op1][op2]; if(-2==pre){ return ERROR; } else if(1==pre){//优先级大于*p if(')'!=*p){ while(1==list[op1][op2]){ Pop(OPTR,temp); --j; Push(rpe,temp); op1=pre_optr[j]; } pre_optr[++j]=op2;//记录栈顶符号 Push(OPTR,*p); } else{//如果为右括号 while(Top(OPTR)!='('){ Pop(OPTR,temp); Push(rpe,temp); --j; } Pop(OPTR,temp); --j; } } else if(0==pre){//等于 Pop(OPTR,temp); } else if(-1==pre){//小于 Push(OPTR,*p); pre_optr[++j]=op2;//记录栈顶符号 } } ++p; }//运行到串尾; while(Top(OPTR)!='#'){ Pop(OPTR,temp); Push(rpe,temp); }//符号栈中所有元素出栈----转换完成 while(!StackEmpty(rpe)){//栈元素逆转---- Pop(rpe,temp); Push(OPTR,temp); } p=head=(char *)malloc(count+1); while('#'!=Top(OPTR)){//将栈元素写入字符串 Pop(OPTR,temp); *p=temp; ++p; } *p='\\0'; return head; } 3.24③ 试编写如下定义的递归函数的递归算法: g(m,n) = 0 当m=0,n>=0 g(m,n) = g(m-1,2n)+n 当m>0,n>=0 并根据算法画出求g(5,2)时栈的变化过程。 实现下列函数: int G(int m, int n) /* if m<0 or n<0 then return -1. */ { if(m<0||n<0){ return -1; } if(0==m){ return 0; } else { return G(m-1,2*n)+n; //刚开始竟然很白痴地写成G(m-1,2n) - -|| } } 3.25④ 试写出求递归函数F(n)的递归算法, 并消除递归: F(n) = n+1 当n=0 F(n) = nF(n/2) 当n>0 实现下列函数: int F(int n) /* if n<0 then return -1. */ { if(n<0){ return -1; } if(0==n){ return 1; } else{ return n*F(n/2); } } ◆3.28② 假设以带头结点的循环链表表示队列,并且 只设一个指针指向队尾元素结点(注意不设头指针), 试编写相应的队列初始化、入队列和出队列的算法。 实现下列函数: Status InitCLQueue(CLQueue &rear); Status EnCLQueue(CLQueue &rear, ElemType x); Status DeCLQueue(CLQueue &rear, ElemType &x); 带头结点循环链队列CLQueue的类型为以下LinkList类型: typedef struct LNode{ ElemType data; struct LNode *next; } LNode, *LinkList; typedef LinkList CLQueue; Status InitCLQueue(CLQueue &rear) { rear=(CLQueue)malloc(sizeof(LNode)); if(!rear){ return FALSE; } rear->next=rear; return TRUE; } Status EnCLQueue(CLQueue &rear, ElemType x) { CLQueue head,p; head=rear->next; p=(CLQueue)malloc(sizeof(LNode)); if(!p){ return FALSE; } p->data=x; p->next=head; rear->next=p; rear=p; return OK; } Status DeCLQueue(CLQueue &rear, ElemType &x) { CLQueue head,p; head=rear->next; if(rear==rear->next){//这里粗心了,忘记考虑队列空的情况 return ERROR; } p=head->next; x=p->data; head->next=p->next; free(p); return OK; } 3.29③ 如果希望循环队列中的元素都能得到利用, 则需设置一个标志域tag,并以tag的值为0或1来区 分,尾指针和头指针值相同时的队列状态是”空”还 是”满”。试编写与此结构相应的入队列和出队列的 算法,并从时间和空间角度讨论设标志和不设标志 这两种方法的使用范围(比如,当循环队列容量较 小而队列中每个元素占的空间较多时,那一种方法 较好?)。 实现下列函数: Status EnCQueue(CTagQueue &Q, QElemType x); Status DeCQueue(CTagQueue &Q, QElemType &x); 本题的循环队列CTagQueue的类型定义如下: typedef char QElemType; typedef struct { QElemType elem[MAXQSIZE]; int tag; int front; int rear; } CTagQueue; Status EnCQueue(CTagQueue &Q, QElemType x) { if(Q.tag){ return ERROR; } Q.elem[Q.rear]=x; if(Q.rear==MAXQSIZE-1){ Q.rear=0; } else{ ++Q.rear; } if(Q.rear==Q.front){ Q.tag=1; } return OK; } Status DeCQueue(CTagQueue &Q, QElemType &x) { if(Q.front==Q.rear&&0==Q.tag){ return ERROR; } else{ x=Q.elem[Q.front]; if(Q.front!=MAXQSIZE-1){ ++Q.front; } else{ Q.front=0; } if(Q.front==Q.rear){ Q.tag=0; } } return OK; } ◆3.30② 假设将循环队列定义为:以域变量rear 和length分别指示循环队列中队尾元素的位置和内 含元素的个数。试给出此循环队列的队满条件,并 写出相应的入队列和出队列的算法(在出队列的算 法中要返回队头元素)。 实现下列函数: Status EnCQueue(CLenQueue &Q, QElemType x); Status DeCQueue(CLenQueue &Q, QElemType &x); 本题的循环队列CLenQueue的类型定义如下: typedef char QElemType; typedef struct { QElemType elem[MAXQSIZE]; int length; int rear; } CLenQueue; Status EnCQueue(CLenQueue &Q, QElemType x) { if(MAXQSIZE==Q.length){ return ERROR; } if(MAXQSIZE-1!=Q.rear){ ++Q.rear; Q.elem[Q.rear]=x; } else{ Q.rear=0; Q.elem[Q.rear]=x; } ++Q.length; return OK; } Status DeCQueue(CLenQueue &Q, QElemType &x) { if(!Q.length){ return ERROR; } if(Q.rear+1>=Q.length){ x=Q.elem[Q.rear+1-Q.length]; } else{ x=Q.elem[MAXQSIZE-Q.length+Q.rear+1]; } --Q.length; return OK; } ◆3.31③ 假设称正读和反读都相同的字符序列为 “回文”,例如,‟abba‟和‟abcba‟是回文,‟abcde‟ 和‟ababab‟则不是回文。试写一个算法判别读入的 一个以‟@'为结束符的字符序列是否是”回文”。 实现下列函数: Status Palindrome(char *word); /* 利用栈和队列判定字符序列word是否是回文 */ 可使用栈Stack和队列Queue及其下列操作: Status InitStack(Stack &S); Status Push(Stack &S, ElemType x); Status Pop(Stack &S, ElemType &x); Status StackEmpty(Stack S); Status InitQueue(Queue &Q); Status EnQueue(Queue &Q, ElemType x); Status DeQueue(Queue &Q, ElemType &x); Status QueueEmpty(Queue Q); Status Palindrome(char *word) /* 利用栈和队列判定字符序列word是否是回文 */ { Stack S; char temp; InitStack(S); char *p=word,*q=word; while(*p!='@'){ Push(S,*p); ++p; } while(!StackEmpty(S)){ Pop(S,temp); if(temp!=*q){ break; } ++q; } if(StackEmpty(S)){ return TRUE; } return FALSE; } 数据结构习题集 第4章答案 4.10③ 编写对串求逆的递推算法。 要求实现以下函数: void Reverse(StringType &s); /* Reverse s by iteration. */ StringType是串的一个抽象数据类型,它包含以下6种基本操作: void InitStr(StringType &s); // 初始化s为空串。 void StrAssign(StringType &t, StringType s); // 将s的值赋给t。s的实际参数是串变量。 int StrCompare(StringType s, StringType t); // 比较s和t。若s>t,返回值>0;若s=t,返回值=0;若s StringType SubString(StringType s, int start, int len); // 当1<=start<=StrLength(s)且0<=len<=StrLength(s)- start+1时, // 返回s中第start个字符起长度为len的子串,否则返回空串。 // 注意,不要使用 ” s = ” 的形式为 StringType 类型的变量赋值 , // 而要使用 StrAssign 函数!!! void Reverse(StringType &s) /* Reverse s by iteration. */ { StringType temp; int i=StrLength(s); InitStr(temp); //初始化空串 //经测试,StrAssign(temp,'')错误~~原因未知 while(i){ Concat(temp,SubString(s,i,1)); --i; //经测试,while(i--)就回出错~ } StrAssign(s,temp); } 4.12③ 编写一个实现串的置换操作Replace(&S,T,V)的算法。 要求实现以下函数: void Replace(StringType &S, StringType T, StringType V); /* 以串 v 置换串 s 中出现的所有和串 t 相同的非空串 */ StringType是串的一个抽象数据类型,它包含以下6种基本操作: void InitStr(StringType &s); // 初始化s为空串。 void StrAssign(StringType &t, StringType s); // 将s的值赋给t。s的实际参数是串变量。 int StrCompare(StringType s, StringType t); // 比较s和t。若s>t,返回值>0;若s=t,返回值=0;若s StringType SubString(StringType s, int start, int len); // 当1<=start<=StrLength(s)且0<=len<=StrLength(s)- start+1时, // 返回s中第start个字符起长度为len的子串,否则返回空串。 // 注意,不要使用 ” s = ” 的形式为 StringType 类型的变量赋值 , // 而要使用 StrAssign 函数!!! void Replace(StringType &S, StringType T, StringType V) /* 以串 v 置换串 s 中出现的所有和串 t 相同的非空串 */ { int i=1,S_Len,T_Len,V_Len; StringType r; S_Len=StrLength(S); T_Len=StrLength(T); V_Len=StrLength(V); InitStr(r); while(i<=S_Len-T_Len+1){ StrAssign(r,SubString(S,i,T_Len)); if(0==StrCompare(r,T)){ InitStr(r); Concat(r,SubString(S,1,i-1)); Concat(r,V); Concat(r,SubString(S,i+T_Len,S_Len-T_Len-i+1)); StrAssign(S,r); i+=V_Len; S_Len=StrLength(S);//注意要更新S的长度! } else{ ++i; } } } 4.13③ 编写算法,从串s中删除所有和串t相同的子串。 要求实现以下函数: void DelSubString(StringType &scrStr, StringType subStr); /* Remove all substring matching „subStr‟ from „scrStr‟. */ StringType是串的一个抽象数据类型,它包含以下6种基本操作: void InitStr(StringType &s); // 初始化s为空串。 void StrAssign(StringType &t, StringType s); // 将s的值赋给t。s的实际参数是串变量。 int StrCompare(StringType s, StringType t); // 比较s和t。若s>t,返回值>0;若s=t,返回值=0;若s StringType SubString(StringType s, int start, int len); // 当1<=start<=StrLength(s)且0<=len<=StrLength(s)- start+1时, // 返回s中第start个字符起长度为len的子串,否则返回空串。 // 注意,不要使用 ” s = ” 的形式为 StringType 类型的变量赋值 , // 而要使用 StrAssign 函数!!! void DelSubString(StringType &scrStr, StringType subStr) /* Remove all substring matching 'subStr' from 'scrStr'. */ { int S_Len,T_Len,i=1; StringType temp; InitStr(temp); S_Len=StrLength(scrStr); T_Len=StrLength(subStr); while(i<=S_Len-T_Len+1){ StrAssign(temp,SubString(scrStr,i,T_Len)); if(0==StrCompare(temp,subStr)){ InitStr(temp); Concat(temp,SubString(scrStr,1,i-1)); Concat(temp,SubString(scrStr,T_Len+i,S_Len-T_Len-i+1)); StrAssign(scrStr,temp); S_Len=StrLength(scrStr); } else{ ++i; //注意这里删除substr后i不变!! } } } 4.17③ 编写算法,实现串的基本操作Replace(&S,T,V)。 要求采用教科书4.2.1节中所定义的定长顺序存储表示, 但不允许调用串的基本操作。 要求实现以下函数: Status Replace(SString& s, SString t, SString v); /* 用串v替换串s中所有和串t匹配的子串。 */ /* 若有与t匹配的子串被替换,则返回TRUE;*/ /* 否则返回FALSE */ 定长顺序串SString的类型定义: typedef unsigned char SString[MAXSTRLEN+1]; /* s[0] is the string‟s length */ Status Replace(SString& s, SString t, SString v) /* 用串v替换串s中所有和串t匹配的子串。 */ /* 若有与t匹配的子串被替换,则返回TRUE;*/ /* 否则返回FALSE */ /*这道题要注意的是顺序串元素的移动*/ { //没通过,强烈怀疑测试数据有问题!!! int flag=0,i,j,k,pos,step; step=t[0]-v[0];//得到两个串的长度差 for(i=1;i<=s[0]-t[0]+1;++i){//依次匹配串 for(pos=i,j=1;j<=t[0];++pos,++j){ if(s[pos]!=t[j]){//此处若写成 pos++和j++,那么下面t[0] } //如果不匹配,则退出循环 } if(t[0] for(j=1,k=i;j<=v[0];++k,++j){ s[k]=v[j]; } } else if(step<0){//串t长度小于模式串的情况 for(k=s[0];k>=i;--k){ s[k-step]=s[k]; } for(j=1,k=i;j<=v[0];++k,++j){ s[k]=v[j]; } } else {//t的长度大于模式串的情况 for(k=pos;k<=s[0];++k){ //此处因为抄了前面的代码,所以没有注意到细节,导致 结果错误,已改正 s[k-step]=s[k]; } for(j=1,k=i;j<=v[0];++k,++j){ s[k]=v[j]; } } flag=1;//记录成功置换 i+=v[0]-1;//i向后移动 s[0]+=-step;//step为正时s[0]减小,step为负时,s[0]增加,故 } } if(flag){ return TRUE; } return FALSE; } 4.20③ 编写算法,从串s中删除所有和串t相同的子串。 要求实现以下函数: Status DelSub(SString &s, SString t); /* 从串s中删除所有和串t匹配的子串。 */ /* 若有与t匹配的子串被删除,则返回TRUE;*/ /* 否则返回FALSE */ 定长顺序串SString的类型定义: typedef unsigned char SString[MAXSTRLEN+1]; /* s[0] is the string‟s length */ Status DelSub(SString &s, SString t) /* 从串s中删除所有和串t匹配的子串。 */ /* 若有与t匹配的子串被删除,则返回TRUE;*/ /* 否则返回FALSE */ { int i,j,pos,flag=0; for(i=1;i<=s[0]-t[0]+1;++i){ for(j=1,pos=i;j<=t[0];++j,++pos){ //模式串匹配 if(s[pos]!=t[j]){ break; } } if(j>t[0]){//删除操作--移动串元素 for(;pos<=s[0];++pos){ s[pos-t[0]]=s[pos]; } s[0]-=t[0]; flag=1; //标记成功删除 --i; //关键点!!容易出错的地方,删除了元素之后, //i保持不变,因循环会加1,故 } } if(flag){ return TRUE; } else{ return FALSE; } } 4.24③ 采用教科书4.2.2节中所定义的堆分配存储 表示。试写一算法,在串的堆存储结构上实现串基 本操作Concat(&T, s1, s2)。 要求实现以下函数: Status Concat(HString &S, HString S1, HString S2) /* 用S返回由S1和S2联接而成的新串 */ 堆串HString的类型定义: typedef struct { char *ch; // 若是非空串,则按串长分配存储区,否则ch为NULL int length; // 串长度 } HString; //通过了忘记保存.... //并不难,不解释 4.30⑤ 假设以定长顺序存储结构表示串,试设计 一个算法,求串s中出现的第一个最长重复子串及 其位置,并分析你的算法的时间复杂度。 要求实现以下函数: void CommonStr(SString s, SString &sub, int &loc); /* 求串s中出现的第一个最长重复子串sub及其位置loc */ 定长顺序串SString的类型定义: typedef unsigned char SString[MAXSTRLEN+1]; /* s[0] is the string‟s length */ //目前对此题没有好的解法,占位 数据结构习题集 第5章答案 5.18⑤ 试设计一个算法,将数组A中的元素 A[0..n-1]循环右移k位,并要求只用一个元素 大小的附加存储,元素移动或交换次数为O(n)。 要求实现以下函数: void Rotate(Array1D &a, int n, int k); 一维数组类型Array1D的定义: typedef ElemType Array1D[MAXLEN]; void Rotate(Array1D &a, int n, int k) /* a[n] contains the elements, */ /* rotate them right circlely by k sits */ { ElemType *p=a,temp; int i,j; if(0!=k%n){//k不是n的倍数时 for(i=1;i<=k;++i){ temp=a[n-1]; for(j=n-2;j>=0;--j){ a[j+1]=a[j]; } a[0]=temp; } } } 5.21④ 假设稀疏矩阵A和B均以三元组表作为存储结构。 试写出矩阵相加的算法,另设三元组表C存放结果矩阵。 要求实现以下函数: Status AddTSM(TSMatrix A,TSMatrix B,TSMatrix &C); /* 三元组表示的稀疏矩阵加法: C=A+B */ 稀疏矩阵的三元组顺序表类型TSMatrix的定义: #define MAXSIZE 20 // 非零元个数的最大值 typedef struct { int i,j; // 行下标,列下标 ElemType e; // 非零元素值 }Triple; typedef struct { Triple data[MAXSIZE+1]; // 非零元三元组表,data[0]未用 int mu,nu,tu; // 矩阵的行数、列数和非零元个数 }TSMatrix; Status AddTSM(TSMatrix A,TSMatrix B,TSMatrix &C) /* 三元组表示的稀疏矩阵加法: C=A+B */ { int ai,bi,ci,aj,bj,cj,apos,bpos,cpos; apos=bpos=cpos=1; if(A.mu!=B.mu||A.nu!=B.nu){ return ERROR; } C.mu=A.mu; C.nu=A.nu; while(apos<=A.tu&&bpos<=B.tu){ ai=A.data[apos].i; bi=B.data[bpos].i; if(ai>bi){ ci=bi; while(ci==B.data[bpos].i){ C.data[cpos].i=ci; C.data[cpos].j=B.data[bpos].j; C.data[cpos].e=B.data[bpos].e; ++bpos; ++cpos; } } else if(ai C.data[cpos].j=A.data[apos].j; C.data[cpos].e=A.data[apos].e; ++apos; ++cpos; } } else{ ci=ai; aj=A.data[apos].j; bj=B.data[bpos].j; if(aj>bj){ C.data[cpos].i=ci; C.data[cpos].j=bj; C.data[cpos].e=B.data[bpos].e; ++cpos; ++bpos; } else if(aj C.data[cpos].e=A.data[apos].e; ++cpos; ++apos; } else{ cj=ai; C.data[cpos].e=A.data[apos].e+B.data[bpos].e; if(0!=C.data[cpos].e){ C.data[cpos].i=ci; C.data[cpos].j=aj; ++cpos; } ++apos; ++bpos; } } }//A稀疏矩阵完或者B稀疏矩阵完。 while(apos<=A.tu){//如果A矩阵中仍有元素 C.data[cpos].i=A.data[apos].i; C.data[cpos].j=A.data[apos].j; C.data[cpos].e=A.data[apos].e; ++cpos; ++apos; } while(bpos<=B.tu){//如果B矩阵中仍有元素 C.data[cpos].i=B.data[bpos].i; C.data[cpos].j=B.data[bpos].j; C.data[cpos].e=B.data[bpos].e; ++cpos; ++bpos; } C.tu=--cpos; return OK; } 5.23② 三元组表的一种变型是,从三元组表中去掉 行下标域得到二元组表,另设一个行起始向量,其每 个分量是二元组表的一个下标值,指示该行中第一个 非零元素在二元组表中的起始位置。试编写一个算法, 由矩阵元素的下标值i,j求矩阵元素。试讨论这种方 法和三元组表相比有什么优缺点。 要求实现以下函数: Status GetElem(T2SMatrix M, int i, int j, ElemType &e); /* 求二元组矩阵的元素A[i][j]的值e */ 稀疏矩阵的二元组顺序表+行起始向量的类型T2SMatrix的定义: typedef struct{ int j; ElemType e; }TwoTuples; typedef struct{ TwoTuples data[MAXSIZE]; int cpot[MAXROW]; // 这个向量存储每一行在二元组中的起始位置 int mu,nu,tu; } T2SMatrix; // 二元组矩阵类型 Status GetElem(T2SMatrix M, int i, int j, ElemType &e) /* 求二元组矩阵的元素A[i][j]的值e */ { //竟然忘了这个是稀疏矩阵,e如果不是非零元素就是零元素 //还要判断i j的合法性!! int cur,last; cur=M.cpot[i]; last=M.cpot[i+1]; e=0; if(i>M.mu||j>M.nu||i<=0||j<=0){ return ERROR; } while(cur } ++cur; } return OK; } 5.26③ 试编写一个以三元组形式输出用十字链表 表示的稀疏矩阵中非零元素及其下标的算法。 要求实现以下函数: void OutCSM(CrossList M, void(*Out3)(int, int, int)); /* 用函数Out3,依次以三元组格式输出十字链表表示的矩阵 */ 稀疏矩阵的十字链表存储表示: typedef struct OLNode { int i,j; // 该非零元的行和列下标 ElemType e; // 非零元素值 OLNode *right,*down; // 该非零元所在行表和列表的后继链域 }OLNode, *OLink; typedef struct { OLink *rhead,*chead; // 行和列链表头指针向量基址 int mu,nu,tu; // 稀疏矩阵的行数、列数和非零元个数 }CrossList; void OutCSM(CrossList M, void(*Out3)(int, int, int)) /* 用函数Out3,依次以三元组格式输出十字链表表示的矩阵 */ { int i=1,row,col,e; OLink p,q; for(i=1;i<=M.mu;++i){ p=M.rhead[i]; while(p){ Out3(p->i,p->j,p->e); p=p->right; } } } 5.30③ 试按表头、表尾的分析方法重写求广义表 的深度的递归算法。 要求实现以下函数: int GListDepth(GList ls); /* Return the depth of list */ 广义表类型GList的定义: typedef enum {ATOM,LIST} ElemTag; typedef struct GLNode{ ElemTag tag; union { char atom; struct { GLNode *hp, *tp; } ptr; }un; } *GList; int GListDepth(GList ls) /* Return the depth of list */ { int max=0,len=0; GList p; if(!ls){ return 1; } if(ls->tag==ATOM){ return 0; } for(max=0,p=ls;p;p=p->un.ptr.tp){ len=GListDepth(p->un.ptr.hp); if(max 5.32④ 试编写判别两个广义表是否相等的递归算法。 要求实现以下函数: Status Equal(GList A, GList B); /* 判断广义表A和B是否相等,是则返回TRUE,否则返回FALSE */ 广义表类型GList的定义: typedef enum {ATOM,LIST} ElemTag; typedef struct GLNode{ ElemTag tag; union { char atom; struct { GLNode *hp, *tp; } ptr; }un; } *GList; Status Equal(GList A, GList B) /* 判断广义表A和B是否相等,是则返回TRUE,否则返回FALSE */ { //基本思想:分三种情况1、若果都为原子节点,则判断是否相等 2、如果都为广义表,则递归返回两个广义表比较结果 //3、其它情况直接返回FALSE; if(ATOM==A->tag&&ATOM==B->tag){//情况1 if(A->un.atom==B->un.atom){ return TRUE; } else{ return FALSE; } } else if(LIST==A->tag&&LIST==B->tag){//情况2 return Equal(A->un.ptr.hp,B->un.ptr.hp)&&Equal(A->un.ptr.tp,B->un.ptr.tp); } else{//情况3 return FALSE; } } 5.33④ 试编写递归算法,输出广义表中所有原子项 及其所在层次。 要求实现以下函数: void OutAtom(GList A, int layer, void(*Out2)(char, int)); /* 递归地用函数Out2输出广义表的原子及其所在层次,layer表示当前层次 */ 广义表类型GList的定义: typedef enum {ATOM,LIST} ElemTag; typedef struct GLNode{ ElemTag tag; union { char atom; struct { GLNode *hp, *tp; } ptr; }un; } *GList; void OutAtom(GList A, int layer, void(*Out2)(char, int)) /* 递归地用函数Out2输出广义表的原子及其所在层次,layer表示当前层次 */ { if(A){ GList p; if(ATOM==A->tag){ Out2(A->un.atom,layer); } else{ p=A->un.ptr.hp; OutAtom(p,layer+1,Out2); p=A->un.ptr.tp; OutAtom(p,layer,Out2);//表尾所在层是当前层,所以此处不能为layer+1 } } } 数据结构习题集 第6章答案 6.33③ 假定用两个一维数组L[1..n]和R[1..n]作为 有n个结点的二叉树的存储结构, L[i]和R[i]分别指 示结点i的左孩子和右孩子,0表示空。试写一个算法 判别结点u是否为结点v的子孙。 要求实现以下函数: Status Dencendant(Array1D L,Array1D R,int n,int u,int v); /* If node „u‟ is the dencendant of node „v‟, */ /* then return „TRUE‟ else return „FALSE‟. */ /* L[i] is the left child of the i_th node, */ /* R[i] is the right child of the i_th node */ /* in the Binary Tree which has n nodes. */ 一维数组类型Array1D的定义: typedef int Array1D[MAXSIZE]; Status Dencendant(Array1D L,Array1D R,int n,int u,int v) /* If node 'u' is the dencendant of node 'v', */ /* then return 'TRUE' else return 'FALSE'. */ /* L[i] is the left child of the i_th node, */ /* R[i] is the right child of the i_th node */ /* in the Binary Tree which has n nodes. */ { int flag=0; if(!v){ return FALSE; } else{ if(L[v]==u){ return TRUE; } else{ flag+=Dencendant(L,R,n,u,L[v]); } if(R[v]==u){ return TRUE; } else{ flag+=Dencendant(L,R,n,u,R[v]); } if(flag){ return TRUE; } return FALSE; } } 6.34③ 假定用两个一维数组L[1..n]和R[1..n]作为 有n个结点的二叉树的存储结构, L[i]和R[i]分别指 示结点i的左孩子和右孩子,0表示空。试写一个算法, 先由L和R建立一维数组T[1..n],使T中第i(i=1,2,…, n)个分量指示结点i的双亲,然后判别结点u是否为结 点v的子孙。 要求实现以下函数: Status Dencend(Array1D L, Array1D R, int n, int u, int v, Array1D T); /******************************************************************/ 一维数组类型Array1D的定义: typedef int Array1D[MAXSIZE]; Status Dencend(Array1D L, Array1D R, int n, int u, int v, Array1D T) /******************************************************************/ { int i,val; for(i=1;i<=n;++i){//初始化数组T T[i]=0; } for(i=1;i<=n;++i){//建立数组T T[L[i]]=i; T[R[i]]=i; } val=T[u]; while(val!=0){ if(val==v){ return TRUE; } val=T[val]; } return FALSE; } 6.36③ 若已知两棵二叉树B1和B2皆为空,或者皆 不空且B1的左、右子树和B2的左、右子树分别相似, 则称二叉树B1和B2相似。试编写算法,判别给定两 棵二叉树是否相似。 要求实现下列函数: Status Similar(BiTree t1, BiTree t2); /* 判断两棵二叉树是否相似的递归算法 */ 二叉链表类型定义: typedef struct BiTNode { TElemType data; BiTNode *lchild, *rchild; } BiTNode, *BiTree; Status Similar(BiTree t1, BiTree t2) /* 判断两棵二叉树是否相似的递归算法 */ { if(!t1&&!t2){//如果两棵树同为空 return TRUE; } else if(t1&&t2){//如果两棵树同为非空,则返回各个子树的比较结果 return Similar(t1->lchild,t2->lchild)&&Similar(t1->rchild,t2->rchild); } else{//当两棵树存在不相似的时候时,即一棵为空,一棵非空 return FALSE; } } 6.37③ 试直接利用栈的基本操作写出先序遍历的非递归 形式的算法(提示:不必按3.3.2节介绍的从递归到非递归 的方法而直接写出非递归算法)。 要求实现下列函数: void PreOrder(BiTree bt, void (*visit)(TElemType)); /* 使用栈,非递归先序遍历二叉树bt, */ /* 对每个结点的元素域data调用函数visit */ 二叉链表类型定义: typedef struct BiTNode { TElemType data; BiTNode *lchild,*rchild; } BiTNode, *BiTree; 可用栈类型Stack的相关定义: typedef BiTree SElemType; // 栈的元素类型 Status InitStack(Stack &S); Status StackEmpty(Stack S); Status Push(Stack &S, SElemType e); Status Pop(Stack &S, SElemType &e); Status GetTop(Stack S, SElemType &e); void PreOrder(BiTree bt, void (*visit)(TElemType)) /* 使用栈,非递归先序遍历二叉树bt, */ /* 对每个结点的元素域data调用函数visit */ { //基本思路:根据工作栈原理,模拟递归的效果~ if(bt){//判断树空 SElemType p=bt; Stack S; InitStack(S); while(!StackEmpty(S)||p){ while(p){//先序访问根节点、遍历左节点 visit(p->data); Push(S,p); p=p->lchild; } if(!StackEmpty(S)){//遍历右节点,不小心写成while,错了几次~~ Pop(S,p); p=p->rchild; } } } } 6.38④ 同6.37题条件,写出后序遍历的非递归算法 (提示:为分辨后序遍历时两次进栈的不同返回点, 需在指针进栈时同时将一个标志进栈)。 要求实现下列函数: void PostOrder(BiTree bt, void (*visit)(TElemType)); /* 使用栈,非递归后序遍历二叉树bt, */ /* 对每个结点的元素域data调用函数visit */ 二叉链表类型定义: typedef struct BiTNode { TElemType data; BiTNode *lchild,*rchild; } BiTNode, *BiTree; 可用栈类型Stack的相关定义: typedef struct { BiTNode *ptr; // 二叉树结点的指针类型 int tag; // 0..1 } SElemType; // 栈的元素类型 Status InitStack(Stack &S); Status StackEmpty(Stack S); Status Push(Stack &S, SElemType e); Status Pop(Stack &S, SElemType &e); Status GetTop(Stack S, SElemType &e); void PostOrder(BiTree bt, void (*visit)(TElemType)) /* 使用栈,非递归后序遍历二叉树bt, */ /* 对每个结点的元素域data调用函数visit */ { Stack S; InitStack(S); SElemType e; BiTree p=bt; int tag=0; if(bt){ e.tag=0; while(!StackEmpty(S)||p==bt){ while(p&&!tag){ e.ptr=p; if(p->lchild){//如果存在左子树 p=p->lchild; e.tag=0; } else{//否则为右子树 p=p->rchild; e.tag=1; } Push(S,e); }//while GetTop(S,e); if(!StackEmpty(S)&&e.tag){ Pop(S,e); //叶子结点出栈 p=e.ptr; visit(p->data);//输出该结点 } if(!StackEmpty(S)){ Pop(S,e); //得到上一层结点 p=e.ptr; if(e.tag){//右子树已经入栈 visit(p->data); p=NULL; } else{//右子树没入过栈 if(p->rchild){ p=p->rchild; tag=0; e.tag=1; Push(S,e); } else {//没有右子树 visit(p->data); p=NULL; } } } else{//栈空则,p为NULL p=NULL; } }//while }//if } 6.41③ 编写递归算法,在二叉树中求位于先序序列中 第k个位置的结点的值。 要求实现下列函数: TElemType PreOrder(BiTree bt, int k); /* bt is the root node of a binary linked list, */ /* Preorder travel it and find the node whose */ /* position number is k, and return its value. */ /* if can‟t found it, then return „#‟. */ 二叉链表类型定义: typedef struct BiTNode { TElemType data; BiTNode *lchild, *rchild; } BiTNode, *BiTree; TElemType Get(BiTree bt,int &count,TElemType &e){ if(bt){ if(1==count){ e=bt->data; return 0; } else{ if(bt->lchild){ --count; Get(bt->lchild,count,e); } if(bt->rchild){ --count; Get(bt->rchild,count,e); } } } } //没想到可以自己添加函数~~方便很多 TElemType PreOrder(BiTree bt, int k) /* bt is the root node of a binary linked list, */ /* Preorder travel it and find the node whose */ /* position number is k, and return its value. */ /* if can't found it, then return '#'. */ { TElemType e; e='#'; Get(bt,k,e); return e; } 6.42③ 编写递归算法,计算二叉树中叶子结点的数目。 要求实现下列函数: void Leaves(BiTree bt, int &x); /* Count the leaf node of the BiTree */ /* whose root node is bt to x. */ 二叉链表类型定义: typedef struct BiTNode { TElemType data; BiTNode *lchild, *rchild; } BiTNode, *BiTree; void Leaves(BiTree bt, int &x) /* Count the leaf node of the BiTree */ /* whose root node is bt to x. */ //题目并没有说x初始化为0,害人不浅啊~~ { int l1,l2; if(bt){ if(!bt->lchild&&!bt->rchild){ ++x; } else{ Leaves(bt->lchild,x); Leaves(bt->rchild,x); } } } 6.43③ 编写递归算法,将二叉树中所有结点的 左、右子树相互交换。 要求实现下列函数: void Exchange(BiTree &bt); /* Exchange the left and right leaves of */ /* bitree whose root node is bt */ 二叉链表类型定义: typedef struct BiTNode { TElemType data; BiTNode *lchild, *rchild; } BiTNode, *BiTree; void Exchange(BiTree &bt) /* Exchange the left and right leaves of */ /* bitree whose root node is bt */ { BiTree temp; if(bt){ Exchange(bt->lchild); Exchange(bt->rchild); temp=bt->lchild; bt->lchild=bt->rchild; bt->rchild=temp; } } 6.44④ 编写递归算法:求二叉树中以元素值 为x的结点为根的子树的深度。 要求实现下列函数: int Depthx(BiTree T, TElemType x); /* 求二叉树中以值为x的结点为根的子树深度 */ 二叉链表类型定义: typedef struct BiTNode { TElemType data; BiTNode *lchild, *rchild; } BiTNode, *BiTree; int Depth(BiTree T){ int l1,l2; if(!T){ return 0; } else{ l1=Depth(T->lchild)+1; l2=Depth(T->rchild)+1; return (l1>l2)?l1:l2; } } int Findx(BiTree T,BiTree &p,TElemType x){ if(T){ if(T->data==x){ p=T; return 0; } else{ Findx(T->lchild,p,x); Findx(T->rchild,p,x); } } } int Depthx(BiTree T, TElemType x) /* 求二叉树中以值为x的结点为根的子树深度 */ { BiTree p=NULL; Findx(T,p,x); return Depth(p); } 6.46③ 编写复制一棵二叉树的非递归算法。 要求实现下列函数: void CopyBiTree(BiTree T, BiTree &TT); /* 基于层次遍历的非递归复制二叉链表 */ 二叉链表类型定义: typedef char TElemType; // 设二叉树的元素为char类型 typedef struct BiTNode { TElemType data; BiTNode *lchild, *rchild; } BiTNode, *BiTree; 可用队列类型Queue的相关定义: typedef BiTree QElemType; // 设队列元素为二叉树的指针类型 Status InitQueue(Queue &Q); Status EnQueue(Queue &Q, QElemType e); Status DeQueue(Queue &Q, QElemType &e); Status GetHead(Queue Q, QElemType &e); Status QueueEmpty(Queue Q); void CopyBiTree(BiTree T, BiTree &TT) /* 基于层次遍历的非递归复制二叉链表 */ //基本思想:用两个队列来同步操作! { BiTree p,p2; Queue Q,Q2; if(!T){ TT=NULL; return; } TT=(BiTree)malloc(sizeof(BiTNode)); InitQueue(Q); InitQueue(Q2); EnQueue(Q,T); EnQueue(Q2,TT); while(!QueueEmpty(Q)){ DeQueue(Q,p); DeQueue(Q2,p2); p2->data=p->data; if(p->lchild){ EnQueue(Q,p->lchild); p2->lchild=(BiTree)malloc(sizeof(BiTNode)); if(!p2->lchild){ exit(OVERFLOW); } EnQueue(Q2,p2->lchild); } else{ p2->lchild=NULL; } if(p->rchild){ EnQueue(Q,p->rchild); p2->rchild=(BiTree)malloc(sizeof(BiTNode)); if(!p2->rchild){ exit(OVERFLOW); } EnQueue(Q2,p2->rchild); } else{ p2->rchild=NULL; } } } 6.47④ 编写按层次顺序(同一层自左至右)遍历二叉树的算法。 要求实现下列函数: void LevelOrder(BiTree bt, char *ss); /* travel BiTree bt by level, Return result by ss. */ 二叉链表类型定义: typedef char TElemType; // 设二叉树的元素为char类型 typedef struct BiTNode { TElemType data; BiTNode *lchild, *rchild; } BiTNode, *BiTree; 可用队列类型Queue的相关定义: typedef BiTree QElemType; // 设队列元素为二叉树的指针类型 Status InitQueue(Queue &Q); Status EnQueue(Queue &Q, QElemType e); Status DeQueue(Queue &Q, QElemType &e); Status GetHead(Queue Q, QElemType &e); Status QueueEmpty(Queue Q); 提示:可将遍历元素的值(字符)依次置入ss,并最后以‟\\0′结尾。 也可以用下列字符串函数产生ss: int sprintf(char *buffer, char *format [, argument, ...]); char *strcat(char *dest, char *src); void LevelOrder(BiTree bt, char *ss) /* travel BiTree bt by level, Return result by ss. */ { int i=0; Queue Q; BiTree p; InitQueue(Q); if(bt){ EnQueue(Q,bt); while(!QueueEmpty(Q)){ DeQueue(Q,p); ss[i++]=p->data; if(p->lchild){ EnQueue(Q,p->lchild); } if(p->rchild){ EnQueue(Q,p->rchild); } } ss[i]='\\0'; } } 6.49④ 编写算法判别给定二叉树是否为完全二叉树。 要求实现下列函数: Status CompleteBiTree(BiTree bt); /* judge if the binary tree whose root is bt */ /* is a complete tree. */ 二叉链表类型定义: typedef struct BiTNode { TElemType data; BiTNode *lchild, *rchild; } BiTNode, *BiTree; 可用队列类型Queue的相关定义: typedef BiTree QElemType; // 设队列元素为二叉树的指针类型 Status InitQueue(Queue &Q); Status EnQueue(Queue &Q, QElemType e); Status DeQueue(Queue &Q, QElemType &e); Status GetHead(Queue Q, QElemType &e); Status QueueEmpty(Queue Q); Status CompleteBiTree(BiTree bt) /* judge if the binary tree whose root is bt */ /* is a complete tree. */ /*基本思路 使用一个栈记录按层次遍历结果,当该结点非NULL时,左右子树入栈 因此,如果该树为完全二叉树时栈内容为XXXX##(X表示非空),##之间不可能有非空结点 如果非完全二叉树则内容可能为XXX#XX##也就是在NULL结点间仍有非空结点 只要非空结点与空结点分布情况即可求解 */ { int flag=0,top=0; BiTree stack[100]; Queue Q; BiTree p; InitQueue(Q); if(bt){ EnQueue(Q,bt); while(!QueueEmpty(Q)){ DeQueue(Q,p); if(p){ EnQueue(Q,p->lchild); EnQueue(Q,p->rchild); stack[top++]=p->lchild; stack[top++]=p->rchild; } }//while while(top){ if(flag){ if(stack[--top]==NULL){//在非NULL结点前仍有NULL结点 return FALSE; } } else{ if(stack[--top]!=NULL){//遇到第一个非NULL结点 flag=1; } } } }//if return TRUE; } 6.65④ 已知一棵二叉树的前序序列和中序序列分别 存于两个一维数组中,试编写算法建立该二叉树的二 叉链表。 要求实现以下函数: void BuildBiTree(BiTree &bt, int ps, char *pre, int is, char *ino, int n); /* 当前要建立的子树bt的元素总数为n,*/ /* 元素在前序序列pre的起始位置为ps,*/ /* 元素在中序序列ino的起始位置为is */ 二叉链表类型定义: typedef char TElemType; typedef struct BiTNode { TElemType data; BiTNode *lchild, *rchild; } BiTNode, *BiTree; void BuildBiTree(BiTree &bt, int ps, char *pre, int is, char *ino, int n) /* 当前要建立的子树bt的元素总数为n,*/ /* 元素在前序序列pre的起始位置为ps,*/ /* 元素在中序序列ino的起始位置为is */ { //估计此题比较繁琐,待更新 } 数据结构习题集 第7章答案 7.22③ 试基于图的深度优先搜索策略写一算法, 判别以邻接表方式存储的有向图中是否存在由顶 点vi到顶点vj的路径(i≠j)。 注意:算法中涉及 的图的基本操作必须在此存储结构上实现。 实现下列函数: Status DfsReachable(ALGraph g, int i, int j); /* Judge if it exists a path from vertex „i‟ to */ /* vertex „j‟ in digraph „g‟. */ /* Array „visited[]„ has been initialed to „false‟.*/ 图的邻接表以及相关类型和辅助变量定义如下: Status visited[MAX_VERTEX_NUM]; typedef char VertexType; typedef struct ArcNode { int adjvex; struct ArcNode *nextarc; } ArcNode; typedef struct VNode { VertexType data; ArcNode *firstarc; } VNode, AdjList[MAX_VERTEX_NUM]; typedef struct { AdjList vertices; int vexnum, arcnum; } ALGraph; //这道题思路很简单,就是简单的深度优先搜索,只不过不用搜索整个图 //只要遍历完含有顶点i的连通子图,然后判断顶点j是否被访问过就可以知道他们 //是否存在路径 int DFS(ALGraph g,int i){ ArcNode *w; for(w = g.vertices[i].firstarc; w > 0 ;w = w->nextarc){ if(visited[w->adjvex] == FALSE){ visited[w->adjvex] = 1; DFS(g,w->adjvex); } } return TRUE; } Status DfsReachable(ALGraph g, int i, int j) /* Judge if it exists a path from vertex 'i' to */ /* vertex 'j' in digraph 'g'. */ /* Array 'visited[]' has been initialed to 'false'.*/ { int n; DFS(g,i); if(visited[j] != FALSE){ return TRUE; } else{ return FALSE; } } 7.23③ 同7.22题要求。试基于图的广度优先搜索策略写一算法。 实现下列函数: Status BfsReachable(ALGraph g, int i, int j); /* Determine whether it exists path from vertex i to */ /* vertex j in digraph g with Breadth_First Search. */ /* Array „visited‟ has been initialed to „false‟. */ 图的邻接表以及相关类型和辅助变量定义如下: Status visited[MAX_VERTEX_NUM]; typedef char VertexType; typedef struct ArcNode { int adjvex; struct ArcNode *nextarc; } ArcNode; typedef struct VNode { VertexType data; ArcNode *firstarc; } VNode, AdjList[MAX_VERTEX_NUM]; typedef struct { AdjList vertices; int vexnum, arcnum; } ALGraph; Status InitQueue(Queue &q); Status EnQueue(Queue &q, int e); Status DeQueue(Queue &q, int &e); Status QueueEmpty(Queue q); Status GetFront(Queue q, int &e); //此题与22题差别不大,同样是使用BFS遍历连通子图再判断 //注意判断结点不存在的情况 Status BfsReachable(ALGraph g, int i, int j) /* Determine whether it exists path from vertex i to */ /* vertex j in digraph g with Breadth_First Search. */ /* Array 'visited' has been initialed to 'false'. */ { ArcNode *p; Queue q; int e,n; InitQueue(q); if(!i&&!j){ //无奈之举,似乎测试数据有问题 //询问A-G有无路径时,i和j都为0 //这种判断方法不严谨,请勿模仿 return FALSE; } EnQueue(q,i); while(!QueueEmpty(q)){//BSF基本用法 DeQueue(q,e); visited[e] = TRUE; p = g.vertices[e].firstarc; while(p){ if(visited[p->adjvex] == FALSE){ EnQueue(q,p->adjvex); } p = p->nextarc; } } if(visited[j] != FALSE){//顶点j已被访问 return TRUE; } else{ return FALSE; } } 7.24③ 试利用栈的基本操作编写,按深度优先搜索策略 遍历一个强连通图的非递归形式的算法。算法中不规定具 体的存储结构,而将图Graph看成是一种抽象的数据类型。 实现下列函数: void Traverse(Graph dig, VertexType v0, void(*visit)(VertexType)); /* Travel the digraph „dig‟ with Depth_First Search. */ 图以及相关类型、函数和辅助变量定义如下: Status visited[MAX_VERTEX_NUM]; int LocateVex(Graph g, VertexType v); VertexType GetVex(Graph g, int i); int FirstAdjVex(Graph g, int v); int NextAdjVex(Graph g, int v, int w); void visit(char v); Status InitStack(SStack &s); Status Push(SStack &s, SElemType x); Status Pop(SStack &s, SElemType &x); Status StackEmpty(SStack s); Status GetTop(SStack s, SElemType &e); 这道题测试数据似乎有问题 在内村里面H明明没有指向结点,而测试例子和答案竟然给出H – A,暂时无法解决! 待更新中… 数据结构习题集 第10章答案 10.23② 试以L.r[k+1]作为监视哨改写教材10.2.1节 中给出的直接插入排序算法。其中,L.r[1..k]为待排 序记录且k } RedType; typedef struct { RedType r[MAXSIZE+1]; // r[0]闲置或用作哨兵单元 int length; } SqList; //-_-!!题目关于LT这个函数什么也没说 void InsertSort(SqList &L) { int i,j; for(i=2;i<=L.length;++i){ if(LT(L.r[i],L.r[i-1])){ L.r[L.length+1]=L.r[i]; L.r[i]=L.r[i-1]; for(j=i-2;LT(L.r[L.length+1],L.r[j]);--j){ L.r[j+1]=L.r[j]; } L.r[j+1]=L.r[L.length+1]; } } } 10.26② 如下所述改写教科书1.4.3节中的起泡排序算法: 将算法中用以起控制作用的布尔变量change改为一个整型变 量,指示每一趟排序中进行交换的最后一个记录的位置,并 以它作为下一趟起泡排序循环终止的控制值。 实现下列函数: void BubbleSort(SqList &L); /* 元素比较和交换必须调用以下比较函数和交换函数:*/ /* Status LT(RedType a, RedType b); 比较:”<\" */ /* Status GT(RedType a, RedType b); 比较:\">” */ /* void Swap(RedType &a, RedType &b); 交换 */ 顺序表的类型SqList定义如下: typedef struct { KeyType key; … } RedType; typedef struct { RedType r[MAXSIZE+1]; // r[0]闲置或用作哨兵单元 int length; } SqList; 比较函数和交换函数: Status LT(RedType a, RedType b); // 比较函数:”<\" Status GT(RedType a, RedType b); // 比较函数:\">” void Swap(RedType &a, RedType &b); // 交换函数 void BubbleSort(SqList &L) /* 元素比较和交换必须调用如下定义的比较函数和交换函数:*/ /* Status LT(RedType a, RedType b); 比较:\"<\" */ /* Status GT(RedType a, RedType b); 比较:\">\" */ /* void Swap(RedType &a, RedType &b); 交换 */ //不知道为什么,compare正常,但swap一直为0 //终于发现原因了,原来这里的Swap是大写的,如果小写的话,可以通过,但是最终swap为 0 { int len=L.length,last=0; int i; while(len>1){ for(i=1;i 10.32⑤ 荷兰国旗问题:设有一个仅由红、白、兰 这三种颜色的条块组成的条块序列。请编写一个时 间复杂度为O(n)的算法,使得这些条块按红、白、 兰的顺序排好,即排成荷兰国旗图案。 实现下列函数: void HFlag(FlagList &f) /* “荷兰国旗”的元素为red,white和blue,*/ /* 分别用字符‟0′,‟1′和‟2′表示 */ “荷兰国旗”的顺序表的类型FlagList定义如下: #define red ‟0′ #define white ‟1′ #define blue ‟2′ typedef char ColorType; typedef struct { ColorType r[MAX_LENGTH+1]; int length; } FlagList; //基本思路:设置low和high来记录两端的位置,按顺序比较i与0和2的关系 //如果为0则存放在线性表左端,如果为2则存放在线性表右端 void HFlag(FlagList &f) { ColorType t; int i=1,low=1,high=f.length; while(f.r[low]=='0'){ //找到第一个不为0的位置 ++low; ++i; } while(f.r[high]=='2'){ //找到倒数第一个不为2的结点 --high; } while(i<=high){ if(f.r[i]=='0'&&low!=i){//如果为0,则与low交换,low!=i的判断极为关键 t=f.r[i]; f.r[i]=f.r[low]; f.r[low]=t; ++low; } else if(f.r[i]=='2'){//如果为2,则与high交换 t=f.r[i]; f.r[i]=f.r[high]; f.r[high]=t; --high; } else{ ++i; } while(f.r[low]=='0'){ //找到第一个不为0的位置 ++low; } while(f.r[high]=='2'){ //找到倒数第一个不为2的结点 --high; } } } 10.34③ 已知(k1,k2,…,kp)是堆,则可以写一个时 间复杂度为O(log(n))的算法将(k1,k2,…,kp,kp+1) 调整为堆。试编写”从p=1起,逐个插入建堆”的算法, 并讨论由此方法建堆的时间复杂度。 实现下列函数: void CreateHeap(HeapType &h, char *s); 堆(顺序表)的类型HeapType定义如下: typedef char KeyType; typedef struct { KeyType key; … … } RedType; typedef struct { RedType r[MAXSIZE+1]; int length; } SqList, HeapType; /* 基本思路: 题目要求用逐个插入建堆的算法进行建堆,刚看题目莫名奇妙, 把书上调整大顶堆的算法抄上去,没想到这天杀的题目也提示下这个是小顶堆... 仔细看清题目之后,发现这道题目很简单。 假设当前堆已经是小顶堆,当有新的叶子时, 只需要跟它的双亲结点的key值比较, 如果比双亲的key小则交换 一直交换到跟结点。 */ //堆调整函数 void HeapAdjust(HeapType &h,int s,int m){ int j; KeyType temp; for(j=m;j>s;j/=2){ if(h.r[j].key while(s[i]!='\\0'){//逐个插入 ++h.length; h.r[h.length].key=s[i]; HeapAdjust(h,1,h.length);//调整堆 ++i; } } 10.35③ 假设定义堆为满足如下性质的完全三叉树: (1) 空树为堆; (2) 根结点的值不小于所有子树根的值,且所有子树 均为堆。 编写利用上述定义的堆进行排序的算法,并分析推导 算法的时间复杂度。 实现下列函数: void HeapSort(HeapType &h); 堆(顺序表)的类型HeapType定义如下: typedef char KeyType; typedef struct { KeyType key; … … } RedType; typedef struct { RedType r[MAXSIZE+1]; int length; } SqList, HeapType; 比较函数和交换函数: Status LT(RedType a, RedType b) { return a.key 解题思路: 近视、眼花,以为题目说的跟书上的一样,又是直接抄上去,结果老是不对 研究后发现,题目说的是完全三叉树.... 随便列举一棵完全三叉树,仔细观察可以发现, 若双亲的序号为i,则左、中、右子树为3i-1,3i,3i+1; 模仿完全二叉树算法即可轻松得出算法 主要区别在于参数的变化还有三个子树的比较,特别是j rc.key=h.r[s].key; for(j=s*3-1;j<=m;j=3*j-1){ if(j h.r[s]=h.r[j]; s=j; } h.r[s]=rc; } void HeapSort(HeapType &h) /* 元素比较和交换必须调用以下比较函数和交换函数:*/ /* Status LT(RedType a, RedType b); 比较:\"<\" */ /* Status GT(RedType a, RedType b); 比较:\">\" */ /* void Swap(RedType &a, RedType &b); 交换 */ { int i; if(h.length){ for(i=(h.length+1)/3;i>0;--i){ HeapAdjust(h,i,h.length); } for(i=h.length;i>1;--i){ Swap(h.r[1],h.r[i]); HeapAdjust(h,1,i-1); } } } 10.42④ 序列的”中值记录”指的是:如果将此序列排序 后,它是第n/2个记录。试写一个求中值记录的算法。 实现下列函数: KeyType MidElement(SqList &L); 顺序表的类型SqList定义如下: typedef struct { KeyType key; … } RedType; typedef struct { RedType r[MAXSIZE+1]; // r[0]闲置或用作哨兵单元 int length; } SqList; //此题神奇之处在于没有告诉你找不到时返回'#'; //效率很低的解法:用另外一个线性表储存本来的元素 //然后再用效率很低的选择排序 //最后之间比较 //估计存在一种边排序边计算的方法,有空再研究~ KeyType MidElement(SqList &L) { int i,j; SqList M; RedType t; if(!L.length){ return '#'; } for(i=1;i<=L.length;++i){ M.r[i]=L.r[i]; } for(i=1;i<=L.length;++i){ for(j=1;j<=L.length;++j){ if(L.r[i].key>L.r[j].key){ t=L.r[i]; L.r[i]=L.r[j]; L.r[j]=t; } } } for(i=1;i<=L.length;++i){ if(M.r[i].key==L.r[L.length/2+1].key){ return M.r[i].key; } } return '#'; } 10.43③ 已知记录序列a[1..n] 中的关键字各不相同, 可按如下所述实现计数排序:另设数组c[1..n],对每 个记录a[i], 统计序列中关键字比它小的记录个数存 于c[i], 则c[i]=0的记录必为关键字最小的记录,然 后依c[i]值的大小对a中记录进行重新排列,试编写算 法实现上述排序方法。 实现下列函数: void CountSort(SqList &L); /* 采用顺序表存储结构,L.r存储序列a,L.length为n */ /* 在函数内自行定义计数数组c */ 顺序表的类型SqList定义如下: typedef struct { KeyType key; … } RedType; typedef struct { RedType r[MAXSIZE+1]; // r[0]闲置或用作哨兵单元 int length; } SqList; void CountSort(SqList &L) /* 采用顺序表存储结构,L.r存储序列a,L.length为n */ /* 在函数内自行定义计数数组c */ { RedType temp[100]; int c[30]; int i,j; for(i=1;i<=L.length;++i){//初始化计数数组 c[i]=0; temp[i]=L.r[i]; } for(i=1;i<=L.length;++i){//统计数据 for(j=1;j<=L.length;++j){ if(L.r[j].key if(c[j]==i){//找到排序后第i+1个元素,位置为j L.r[i+1]=temp[j]; } } } } 因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- zrrp.cn 版权所有 赣ICP备2024042808号-1
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务