不管怎样,生活还是要继续向前走去。
有的时候伤害和失败不见得是一件坏事,它会让你变得更好,孤单和失落亦是如此。
每件事到最后一定会变成一件好事,只要你能够走到最后。
附录习题参考答案习题1参考答案1.1.选择题(1). A. (2). A. (3). A. (4). B.C. (5). A. (6). A. (7). C. (8). A. (9). B. (10.) A.1.2.填空题(1). 数据关系(2). 逻辑结构物理结构(3). 线性数据结构树型结构图结构(4). 顺序存储链式存储索引存储散列表(Hash)存储(5). 变量的取值范围操作的类别(6). 数据元素间的逻辑关系数据元素存储方式或者数据元素的物理关系(7). 关系网状结构树结构(8). 空间复杂度和时间复杂度(9). 空间时间(10). Ο(n)1.3 名词解释如下:数据:数据是信息的载体是计算机程序加工和处理的对象包括数值数据和非数值数据数据项:数据项指不可分割的、具有独立意义的最小数据单位数据项有时也称为字段或域数据元素:数据元素是数据的基本单位在计算机程序中通常作为一个整体进行考虑和处理一个数据元素可由若干个数据项组成数据逻辑结构:数据的逻辑结构就是指数据元素间的关系数据存储结构:数据的物理结构表示数据元素的存储方式或者数据元素的物理关系数据类型:是指变量的取值范围和所能够进行的操作的总和算法:是对特定问题求解步骤的一种描述是指令的有限序列1.4 语句的时间复杂度为:(1) Ο(n2)(2) Ο(n2)(3) Ο(n2)(4) Ο(n-1)(5) Ο(n3) 1.5 参考程序:main(){int XYZ;scanf("%d %d%d"&X&YZ);if (X>=Y)if(X>=Z)if (Y>=Z) { printf("%d %d%d"XYZ);}else{ printf("%d %d%d"XZY);}else{ printf("%d %d%d"ZXY);}else if(Z>=X)if (Y>=Z) { printf("%d %d%d"YZX);}else{ printf("%d%d%d"ZYX);}else{ printf("%d%d%d"YXZ);}}1.6 参考程序:main(){int in;float xa[]p;printf("\nn=");scanf("%f"&n);printf("\nx=");scanf("%f"&x);for(i=0;i<=n;i++)scanf("%f "&a[i]);p=a[0];for(i=1;i<=n;i++){ p=p+a[i]*x;x=x*x;}printf("%f"p)'}习题2参考答案2.1选择题(1). C. (2). B. (3). B. (4). B. 5. D. 6. B. 7. B. 8. A. 9. A. 10. D.2.2.填空题(1). 有限序列(2). 顺序存储和链式存储(3). O(n) O(n)(4). n-i+1 n-i(5). 链式(6). 数据指针(7). 前驱后继(8). Ο(1) Ο(n)(9). s->next=p->next; p->next=s ;(10). s->next2.3. 解题思路:将顺序表A中的元素输入数组a若数组a中元素个数为n将下标为012...(n-1)/2的元素依次与下标为nn-1...(n-1)/2的元素交换输出数组a的元素参考程序如下:main(){int in;float ta[];printf("\nn=");scanf("%f"&n);for(i=0;i<=n-1;i++)scanf("%f "&a[i]);for(i=0;i<=(n-1)/2;i++){ t=a[i]; a[i] =a[n-1-i]; a[n-1-i]=t;} for(i=0;i<=n-1;i++)printf("%f"a[i]);}2.4 算法与程序:main(){int in;float ta[];printf("\nn=");scanf("%f"&n);for(i=0;i<n;i++)scanf("%f "&a[i]);for(i=1;i<n;i++)if(a[i]>a[0]{ t=a[i]; a[i] =a[0]; a[0]=t;} printf("%f"a[0]);for(i=2;i<n;i++)if(a[i]>a[1]{ t=a[i]; a[i] =a[1]; a[1]=t;} printf("%f"a[0]);}2.5 算法与程序:main(){int ijkn;float xta[];printf("\nx=");scanf("%f"&x);printf("\nn=");scanf("%f"&n);for(i=0;i<n;i++)scanf("%f "&a[i]); // 输入线性表中的元素for (i=0; i<n; i++) { // 对线性表中的元素递增排序 k=i;for (j=i+1; j<n; j++) if (a[j]<a[k]) k=j;if (k<>j) {t=a[i];a[i]=a[k];a[k]=t;}}for(i=0;i<n;i++) // 在线性表中找到合适的位置if(a[i]>x) break;for(k=n-1;k>=i;i--) // 移动线性表中元素然后插入元素xa[k+1]=a[k];a[i]=x;for(i=0;i<=n;i++) // 依次输出线性表中的元素printf("%f"a[i]);}2.6 算法思路:依次扫描A和B的元素比较A、B当前的元素的值将较小值的元素赋给C如此直到一个线性表扫描完毕最后将未扫描完顺序表中的余下部分赋给C即可C的容量要能够容纳A、B两个线性表相加的长度有序表的合并算法:void merge (SeqList ASeqList BSeqList *C){ int ijk;i=0;j=0;k=0;while ( i<=st && j<=st )if (A.data[i]<=B.data[j])C->data[k++]=A.data[i++];elseC->data[k++]=B.data[j++];while (i<=st )C->data[k++]= A.data[i++];while (j<=st )C->data[k++]=B.data[j++];C->last=k-1;}2.7 算法思路:依次将A中的元素和B的元素比较将值相等的元素赋给C如此直到线性表扫描完毕线性表C就是所求递增有序线性表算法:void merge (SeqList ASeqList BSeqList *C){ int ijk;i=0;j=0;k=0;while ( i<=st)while(j<=st )if (A.data[i]=B.data[j])C->data[k++]=A.data[i++];C->last=k-1;}习题3参考答案3.1.选择题(1). D (2). C (3). D (4). C (5). B (6). C (7). C (8). C (9). B (10).AB (11). D (12). B (13). D (14). C (15). C (16). D(17). D (18). C (19). C (20). C 3.2.填空题(1) FILOFIFO(2) -13 4 X * + 2 Y * 3 / -(3) stack.topstack.s[stack.top]=x(4) p>llink->rlink=p->rlinkp->rlink->llink=p->rlink(5) (R-F+M)%M(6) top1+1=top2(7) F==R(8) front==rear(9) front==(rear+1)%n(10) N-13.3 答:一般线性表使用数组来表示的线性表一般有插入、删除、读取等对于任意元素的操作而栈只是一种特殊的线性表栈只能在线性表的一端插入(称为入栈push)或者读取栈顶元素或者称为"弹出、出栈"(pop)3.4 答:相同点:栈和队列都是特殊的线性表只在端点处进行插入删除操作不同点:栈只在一端(栈顶)进行插入删除操作;队列在一端(top)删除一端(rear)插入3.5 答:可能序列有14种:ABCD; ACBD; ACDB; ABDC; ADCB; BACD; BADC; BCAD; BCDA; BDCA; CBAD; CBDA; CDBA; DCBA3.6 答:不能得到435612最先出栈的是4则按321的方式出不可能得到1在2前的序列可以得到135426按如下方式进行push(1)pop()push(2)push(3)pop()push(4)push(5)pop()pop()pop()push(6)pop()3.7 答:stack3.8 非递归:int vonvert (int noint a[]) //将十进制数转换为2进制存放在a[] 并返回位数{int r;SeStack s*p;P=&s;Init_stack(p);while(no){push(pno%2);no/=10;}r=0;while(!empty_stack(p)){pop(pa+r);r++;}return r;}递归算法:void convert(int no){if(no/2>0){Convert(no/2);Printf("%d"no%2);}elseprintf("%d"no);}3.9 参考程序:void view(SeStack s){SeStack *p; //假设栈元素为字符型char c;p=&s;while(!empty_stack(p)){c=pop(p);printf("%c"c);}printf("\n");}3.10 答:char3.11 参考程序:void out(linkqueue q){int e;while(q.rear !=q.front ){dequeue(qe);print(e); //打印}}习题4参考答案4.1 选择题:(1). A (2). D (3). C (4). C (5). B (6). B (7). D (8). A (9). B (10). D 4.2 填空题:(1)串长相等且对应位置字符相等(2)不含任何元素的串(3)所含字符均是空格所含空格数(4) 10(5) "hello boy"(6) 13(7) 1066(8)模式匹配(9)串中所含不同字符的个数(10) 364.3 StrLength (s)=14StrLength (t)=4SubStr( s87)=" STUDENT"SubStr(t21)="O"StrIndex(s"A")=3StrIndex (st)=0StrRep(s"STUDENT"q)=" I AM A WORKER"4.4 StrRep(s"Y""+");StrRep(s"+*""*Y");4.5 空串:不含任何字符;空格串:所含字符都是空格串变量和串常量:串常量在程序的执行过程中只能引用不能改变;串变量的值在程序执行过程中是可以改变和重新赋值的主串与子串:子串是主串的一个子集串变量的名字与串变量的值:串变量的名字表示串值的标识符4.6int EQUAl(ST){char *p*q;p=&S;q=&T;while(*p&&*q){if(*p!=*q)return *p-*q;p++;q++;}return *p-*q;}4.7(1)6*8*6=288(2)1000+47*6=1282(3)1000+(8+4)*8=1096(4)1000+(6*7+4)*8=13684.8习题5参考答案5.1 选择(1)C(2)B(3)C(4)B(5)C(6)D(7)C(8)C(9)B(10)C (11)B(12)C(13)C(14)C(15)C(16)B5.2 填空(1)1(2)1036;1040(3)2i(4) 1 ; n ; n-1 ; 2(5)2k-1;2k-1(6)ACDBGJKIHFE(7)p!=NULL(8)Huffman树(9)其第一个孩子; 下一个兄弟(10)先序遍历;中序遍历5.3叶子结点:C、F、G、L、I、M、K;非终端结点:A、B、D、E、J;各结点的度:结点: A B C D E F G L I J K M度: 4 3 0 1 2 0 0 0 0 1 0 0树深:45.4无序树形态如下:二叉树形态如下:5.5二叉链表如下:三叉链表如下:5.6先序遍历序列:ABDEHICFJG中序遍历序列:DBHEIAFJCG后序遍历序列:DHIEBJFGCA5.7(1) 先序序列和中序序列相同:空树或缺左子树的单支树;(2) 后序序列和中序序列相同:空树或缺右子树的单支树;(3) 先序序列和后序序列相同:空树或只有根结点的二叉树5.8这棵二叉树为:5.9先根遍历序列:ABFGLCDIEJMK后根遍历序列:FGLBCIDMJKEA层次遍历序列:ABCDEFGLIJKM5.10证明:设树中结点总数为n叶子结点数为n0则n=n0 + n1 + ...... + nm (1)再设树中分支数目为B则B=n1 + 2n2 + 3n3 + ...... + m nm (2)因为除根结点外每个结点均对应一个进入它的分支所以有n= B + 1 (3)将(1)和(2)代入(3)得n0 + n1 + ...... + nm = n1 + 2n2 + 3n3 + ...... + m nm + 1 从而可得叶子结点数为:n0 = n2 + 2n3 + ...... + (m-1)nm + 15.11由5.10结论得n0 = (k-1)nk + 1又由 n=n0 + nk得nk= n-n0代入上式得n0 = (k-1)(n-n0)+ 1叶子结点数为:n0 = n (k-1) / k5.12int NodeCount(BiTree T){ //计算结点总数if(T)if (T-> lchild==NULL )&&( T --> rchild==NULL )return 1;elsereturn NodeCount(T-> lchild ) +Node ( T --> rchild )+1; elsereturn 0;5.13void ExchangeLR(Bitree bt){/* 将bt所指二叉树中所有结点的左、右子树相互交换 */ if (bt && (bt->lchild || bt->rchild)) {bt->lchild<->bt->rchild;Exchange-lr(bt->lchild);Exchange-lr(bt->rchild);}}/* ExchangeLR */5.14int IsFullBitree(Bitree T){/* 是则返回1否则返回0*/Init_Queue(Q); /* 初始化队列*/flag=0;In_Queue(QT); /* 根指针入队列按层次遍历*/while(!Empty_Queue (Q)){Out_Queue(Qp);if(!p) flag=1; /* 若本次出队列的是空指针时则修改flag值为1若以后出队列的指针存在非空则可断定不是完全二叉树 */else if (flag) return 0; /*断定不是完全二叉树 */ else{In_Queue(Qp->lchild);In_Queue(Qp->rchild); /* 不管孩子是否为空都入队列*/}}/* while */return 1; /* 只有从某个孩子指针开始之后所有孩子指针都为空才可断定为完全二叉树*/}/* IsFullBitree */5.15转换的二叉树为:5.16对应的森林分别为:5.17typedef char elemtype;typedef struct{ elemtype data;int parent;} NodeType;(1) 求树中结点双亲的算法:int Parent(NodeType t[ ]elemtype x){/* x不存在时返回-2否则返回x双亲的下标(根的双亲为-1 */for(i=0;i<MAXNODE;i++)if(x==t[i].data) return t[i].parent; return -2;}/*Parent*/(2) 求树中结点孩子的算法:void Children(NodeType t[ ]elemtype x){for(i=0;i<MAXNODE;i++){if(x==t[i].data)break;/*找到x退出循环*/}/*for*/if(i>=MAXNODE) printf("x不存在\n"); else {flag=0;for(j=0;j<MAXNODE;j++)if(i==t[j].parent){ printf("x的孩子:%c\n"t[j].data);flag=1;}if(flag==0) printf("x无孩子\n");}}/*Children*/5.18typedef char elemtype;typedef struct ChildNode{ int childcode;struct ChildNode *nextchild;}typedef struct{ elemtype data;struct ChildNode *firstchild;} NodeType;(1) 求树中结点双亲的算法:int ParentCL(NodeType t[ ]elemtype x){/* x不存在时返回-2否则返回x双亲的下标 */for(i=0;i<MAXNODE;i++)if(x==t[i].data) {loc=i;/*记下x的下标*/break;}if(i>=MAXNODE) return -2; /* x不存在 *//*搜索x的双亲*/for(i=0;i<MAXNODE;i++)for(p=t[i].firstchild;p!=NULL;p=p->nextchild) if(loc==p->childcode)return i; /*返回x结点的双亲下标*/}/* ParentL */(2) 求树中结点孩子的算法:void ChildrenCL(NodeType t[ ]elemtype x){for(i=0;i<MAXNODE;i++)if(x==t[i].data) /*依次打印x的孩子*/{flag=0; /* x存在 */for(p=t[i].firstchild;p;p=p->nextchild){ printf("x的孩子:%c\n"t[p-> childcode].data);flag=1;}if(flag==0) printf("x无孩子\n");return;}/*if*/printf("x不存在\n");return;}/* ChildrenL */5.19typedef char elemtype;typedef struct TreeNode{ elemtype data;struct TreeNode *firstchild; struct TreeNode *nextsibling; } NodeType;void ChildrenCSL(NodeType *telemtype x){ /* 层次遍历方法 */Init_Queue(Q); /* 初始化队列 */In_Queue(Qt);count=0;while(!Empty_Queue (Q)){Out_Queue(Qp);if(p->data==x){ /*输出x的孩子*/p=p->firstchild;if(!p) printf("无孩子\n");else{ printf("x的第%i个孩子:%c\n"++countp->data);/*输出第一个孩子*/p=p->nextsibling; /*沿右分支*/while(p){printf("x的第%i个孩子:%c\n"++countp->data);p=p-> nextsibling;}}return;}if(p-> firstchild) In_Queue(Qp-> firstchild);if(p-> nextsibling) In_Queue(Qp-> nextsibling);}}/* ChildrenCSL */5.20(1) 哈夫曼树为:(2) 在上述哈夫曼树的每个左分支上标以1右分支上标以0并设这7个字母分别为A、B、C、D、E、F和H如下图所示:则它们的哈夫曼树为分别为:A:1100B:1101C:10D:011E:00F:010H:111习题6参考答案6.1 选择题(1)C (2)A (3)B(4)C(5)B______条边(6)B(7)A(8)A(9)B(10)A(11)A(12)A(13)B(14)A(15)B(16)A(17)C 6.2 填空(1) 4(2) 1对多 ; 多对多(3) n-1 ; n(4) 0_(5)有向图(6) 1(7)一半(8)一半(9)___第i个链表中边表结点数___(10)___第i个链表中边表结点数___(11)深度优先遍历;广度优先遍历(12)O(n2)(13)___无回路6.3(1)邻接矩阵:(2)邻接链表:(3)每个顶点的度:顶点度V1 3V2 3V3 2V4 3V5 36.4(1)邻接链表:(2)逆邻接链表:(3)顶点入度出度V1 3 0V2 2 2V3 1 2V4 1 3V5 2 1V6 2 36.5(1)深度优先查找遍历序列:V1 V2 V3 V4 V5; V1 V3 V5 V4 V2; V1 V4 V3 V5 V2 (1)广度优先查找遍历序列:V1 V2 V3 V4 V5; V1 V3 V2 V4 V5; V1 V4 V3 V2 V56.6有两个连通分量:6.7顶点(1)(2)(3)(4)(5)Low Close Cost VexLow CloseCost VexLow CloseCost VexLow CloseCost VexLow CloseCost VexV10 00 00 00 00 0V21 00 00 00 00 0V31 01 00 00 00 0V43 02 12 10 10 1V5∞ 05 13 22 30 3U{v1} {v1v2} {v1v2v3} {v1 v2 v3 v4} {v1 v2 v3 v4 v5} T {} { (v1 v2) } {(v1 v2) (v1 v3) } {(v1 v2) (v1 v3) (v2 v4) } {(v1 v2)(v1v3)(v2v4)(v4v5) }最小生成树的示意图如下:6.8拓扑排序结果: V3--> V1 --> V4 --> V5 --> V2 --> V66.9(1)建立无向图邻接矩阵算法:提示:参见算法6.1因为无向图的邻接矩阵是对称的所以有for (k=0; k<G ->e; k++) /*输入e条边建立无向图邻接矩阵*/{ scanf("\n%d%d"&i&j);G ->edges[i][j]= G ->edges[j][i]=1;}(2)建立无向网邻接矩阵算法:提示:参见算法6.1初始化邻接矩阵:#define INFINITY 32768 /* 表示极大值*/for(i=0;i<G->n;i++)for(j=0;j<G->n;j++) G->edges[i][j]= INFINITY;输入边的信息:不仅要输入边邻接的两个顶点序号还要输入边上的权值for (k=0; k<G ->e; k++) /*输入e条边建立无向网邻接矩阵*/{ scanf("\n%d%d%d"&i&j&cost); /*设权值为int型*/G ->edges[i][j]= G ->edges[j][i]=cost;/*对称矩阵*/}(3)建立有向图邻接矩阵算法:提示:参见算法6.16.10(1)建立无向图邻接链表算法:typedef VertexType char;int Create_NgAdjList(ALGraph *G){ /* 输入无向图的顶点数、边数、顶点信息和边的信息建立邻接表 */scanf("%d"&n); if(n<0) return -1; /* 顶点数不能为负 */G->n=n;scanf("%d"&e); if(e<0) return =1; /*边数不能为负 */G->e=e;for(m=0;m< G->n ;m++)G-> adjlist [m].firstedge=NULL; /*置每个单链表为空表*/for(m=0;m< G->n;m++)G->adjlist[m].vertex=getchar(); /*输入各顶点的符号*/for(m=1;m<= G->e; m++){scanf("\n%d%d"&i&j); /* 输入一对邻接顶点序号*/if((i<0 || j<0) return -1;p=(EdgeNode*)malloc(sizeof(EdgeNode));/*在第i+1个链表中插入一个边表结点*/ p->adjvex=j;p->next= G-> adjlist [i].firstedge;G-> adjlist [i].firstedge=p;p=(EdgeNode*)malloc(sizeof(EdgeNode));/*在第j+1个链表中插入一个边表结点*/ p->adjvex=i;p->next= G-> adjlist [j].firstedge;G-> adjlist [j].firstedge=p;} /* for*/return 0; /*成功*/}//Create_NgAdjList(2)建立有向图逆邻接链表算法:typedef VertexType char;int Create_AdjList(ALGraph *G){ /* 输入有向图的顶点数、边数、顶点信息和边的信息建立逆邻接链表 */scanf("%d"&n); if(n<0) return -1; /* 顶点数不能为负 */G->n=n;scanf("%d"&e); if(e<0) return =1; /*弧数不能为负 */G->e=e;for(m=0;m< G->n; m++)G-> adjlist [m].firstedge=NULL; /*置每个单链表为空表*/for(m=0;m< G->n;m++)G->adjlist[m].vertex=getchar(); /*输入各顶点的符号*/for(m=1;m<= G->e ; m++){scanf("\n%d%d"&t&h); /* 输入弧尾和弧头序号*/if((t<0 || h<0) return -1;p=(EdgeNode*)malloc(sizeof(EdgeNode));/*在第h+1个链表中插入一个边表结点*/ p->adjvex=t;p->next= G-> adjlist [h].firstedge;G-> adjlist [h].firstedge=p;} /* for*/return 0; /*成功*/}//Create_AdjList6.11void Create_AdjM(ALGraph *G1MGraph *G2){ /*通过无向图的邻接链表G1生成无向图的邻接矩阵G2*/G2->n=G1->n; G2->e=G1->e;for(i=0;i<G2->n;i++) /* 置G2每个元素为0 */for(j=0;j<G2->n;j++) G2->edges[i][j]= 0;for(m=0;m< G1->n;m++)G2->vexs[m]=G1->adjlist[m].vertex; /*复制顶点信息*/num=(G1->n/2==0?G1->n/2:G1->n/2+1); /*只要搜索前n/2个单链表即可*/for(m=0;m< num;m++){ p=G1->adjlist[m].firstedge;while(p){ /* 无向图的存储具有对称性*/G2->edges[m][ p->adjvex ]= G2->edges[p->adjvex ] [m] =1;p==p->next;}}/* for */}/*Create_AdjM */6.12void Create_AdjL(ALGraph *G1MGraph *G2){ /*通过无向图的邻接矩阵G1生成无向图的邻接链表G2*/G2->n=G1->n; G2->e=G1->e;for(i=0;i<G1->n;i++) /* 建立每个单链表 */{ G2->vexs[i]=G1->adjlist[i].vertex;G2->adjlist[i].firstedge=NULL;for(j=i; j<G1->n; j++) /*对称矩阵只要搜索主对角以上的元素即可*/{ if(G1->edges[i][j]== 1){ p=(EdgeNode*)malloc(sizeof(EdgeNode));/*在第i+1个链表中插入一个边表结点*/p->adjvex=j;p->next= G-> adjlist [i].firstedge;G-> adjlist [i].firstedge=p;p=(EdgeNode*)malloc(sizeof(EdgeNode));/*在第j+1个链表中插入一个边表结点*/p->adjvex=i;p->next= G-> adjlist [j].firstedge;G-> adjlist [j].firstedge=p;}/*if*/}/* for*/}/* for*/}/* Create_AdjL */6.13(1) 邻接矩阵中1的个数的一半;(2) 若位于[i-1j-1]或[j-1i-1]位置的元素值等于1则有边相连否则没有(3) 顶点i的度等于第i-1行中或第i-1列中1的个数6.14(1) 邻接链表中边表结点的个数的一半;(2) 若第i-1(或j-1)个单链表中存在adjvex域值等于j-1(或i-1)的边表结点则有边相连否则没有(3) 顶点i的度等于第i-1个单链表中边表结点的个数6.15提示:参见算法6.2 和6.3习题 7参考答案7.1 选择题(1)C (2)C (3) C (4)B (5) A (6)A (7) D (8)B (9)D (10) B(11)B (12)A (13)C (14)C (15)A (16)D (17)C (18)BC (19)B (20)A7.2 填空题(1) O(n)O(log2n)(2) 12485log2(n+1)-1(3)小于大于(4)增序序列(5)m-1(6) 70; 342055(7) n/m(8)开放地址法链地址法(9)产生冲突的可能性就越大产生冲突的可能性就越小(10)关键码直接(11)②①⑦(12) 1616821(13)直接定址法数字分析法平方取中法折叠法除留余数法随机数法(14)开放地址法再哈希法链地址法建立一个公共溢出区(15)装满程度(16)索引快(17)哈希函数装填因子(18)一个结点(19)中序(20)等于7.3 一棵二叉排序树(又称二叉查找树)或者是一棵空树或者是一棵同时满足下列条件的二叉树:(1)若它的左子树不空则左子树上所有结点的键值均小于它根结点键值(2)若它的右子树不空则右子树上所有结点的键值均大于它根结点键值(3)它的左、右子树也分别为二叉排序树7.4 对地址单元d=H(K)如发生冲突以d为中心在左右两边交替进行探测按照二次探测法键值K的散列地址序列为:do=H(K)d1=(d0+12)mod md2=(d0-12)mod md3=(d0+22)mod md4=(d0-12)mod m......7.5 衡量算法的标准有很多时间复杂度只是其中之一尽管有些算法时间性能很好但是其他方面可能就存在着不足比如散列查找的时间性能很优越但是需要关注如何合理地构造散列函数问题而且总存在着冲突等现象为了解决冲突还得采用其他方法二分查找也是有代价的因为事先必须对整个查找区间进行排序而排序也是费时的所以常应用于频繁查找的场合对于顺序查找尽管效率不高但却比较简单常用于查找范围较小或偶而进行查找的情况7.6此法要求设立多个散列函数Hii=1...k当给定值K与闭散列表中的某个键值是相对于某个散列函数Hi的同义词因而发生冲突时继续计算该给定值K在下一个散列函数Hi+1下的散列地址直到不再产生冲突为止7.7散列表由两个一维数组组成一个称为基本表另一个称为溢出表插入首先在基本表上进行;假如发生冲突则将同义词存人溢出表7.8 结点个数为n时高度最小的树的高度为1有两层它有n-1个叶结点1个分支结点;高度最大的树的高度为n-l有n层它有1个叶结点n-1个分支结点7.9 设顺序查找以h为表头指针的有序链表若查找成功则返回结点指针p查找失败则返回null值pointer sqesrearch(pointer hint xpointerp){p=null;while(h)if(x>h->key)h=h->link;else{if(x==h->key)p=h;return(p);}}虽然链表中的结点是按从小到大的顺序排列的但是其存储结构为单链表查找结点时只能从头指针开始逐步进行搜索故不能用折半(二分)查找7.10 分析:对二叉排序树来讲其中根遍历序列为一个递增有序序列因此对给定的二叉树进行中根遍历如果始终能保证前一个值比后一个值小则说明该二叉树是二叉排序树int bsbtr (bitreptr T) /*predt记录当前结点前趋值初值为-∞*/{ if (T==NULL) return(1);else{b1=bsbtr(T->lchild);/*判断左子树*/if (!b1|| (predt>=T->data)) return(0);*当前结点和前趋比较*/ predt=T->data;/*修改当前结点的前趋值*/return(bsbtr(T->rchild));/*判断右子树并返回最终结果*/}}7.11 (1)使用线性探查再散列法来构造散列表如表下所示散列表───────────────────────────────地址 0 1 2 3 4 5 6 7 8 9 10───────────────────────────────数据 33 1 13 12 34 38 27 22───────────────────────────────(2)使用链地址法来构造散列表如下图(3)装填因子a=8/11使用线性探查再散列法查找成功所需的平均查找次数为Snl=0.5(1+1/(1-a))=0.5*(1+1/(1-8/11))=7/3使用线性探查再散列法查找不成功所需的平均查找次数为:Unl=0.5(1+1/(1-a)2)=0.5*(1+1/(1-8/11)2)=65/9 使用链地址法查找成功所需的平均查找次数为:Snc=l+a/2=1+8/22=15/11使用链地址法查找不成功所需的平均查找次数为: 'Unl=a+e-a=8/1l+e-8/117.12 分析:在等查区间的上、下界处设两个指针由此计算出中间元素的序号当中间元素大于给定值X时接下来到其低端区间去查找;当中间元素小于给定值X时接下来到其高端区间去查找;当中间元素等于给定值X时表示查找成功输出其序号Int binlist(sqtable Aint stkeytype X) /*t、s分别为查找区间的上、下界*/{ if(s<t) return(0);/*查找失败*/else{ mid=(S+t)/2;switCh(mid){case x<A.item[midJ.key: return(binlist(Asmid-lX));/*在低端区间上递归*/case x==A.item[mid].key: return(mid);/+查找成功*/ case x>A.item[mid].key: return(amid+ltX));/*在高端区间上递归*/}}}7.13int sqsearch0 (sqtable Akeytype X) /*数组有元素n个*/{ i=l;A.item[n+1].key=X;/t设置哨兵*/while (A.item[n+1].key!=X) i++;return (i% (n/1));/*找不到返回0找到返回其下标*/}查找成功平均查找长度为:(1+2+3+...+n)/n:(1+n)/2查找不成功平均查找长度为:n+17.14散列函数:H(key)=100+(key个位数+key十位数) mod l0;形成的散列表:100 101 102 103 104 105 106 107 108 10998 75 63 46 49 79 61 53 17查找成功时的平均长度为:(1+2+1+1+5+1+1+5+5+3)/10=2.5次由于长度为10的哈希表已满因此在插人第11个记录时所需作的比较次数的期望值为10查找不成功时的平均长度为10习题 8参考答案8.1 选择题(1)B (2)A (3)D (4)C (5)B (6)A (7)B (8)C (9)A (10)C(11)D (12)C (13) C (14)D (15)C (16)B (17) D (18)C (19)B (20)D8.2填空题(1)快速归并(2) O(log2n)O(nlog2n)(3)归并(4)向上根结点(5) 1918163022(6)(7)4913275076386597(8)88(9)插入选择(每次选择最大的)(10)快速归并(11)O(1)O(nlog2n)(12)稳定(13)3(14)(15205040)(15)O(log2n)(16)O(n2)(17)冒泡排序快速排序(18)完全二叉树n/2(19)稳定不稳定(20)2(204015)8.3. 假定给定含有n个记录的文件(r1f2...rn)其相应的关键字为(k1k2...kn)则排序就是确定文件的一个序列rrr2...rn使得k1'≤k2'≤...≤kn'从而使得文件中n个记录按其对应关键字有序排列如果整个排序过程在内存中进行则排序叫内部排序假设在待排序的文件中存在两个或两个以上的记录具有相同的关键字若采用某种排序方法后使得这些具有相同关键字的记录在排序前后相对次序依然保持不变则认为该排序方法是稳定的否则就认为排序方法是不稳定的8.4.稳定的有:直接插入排序、二分法插入排序、起泡排序、归并排序和直接选择排序8.5.初始记录序列按关键字有序或基本有序时比较次数为最多8.6.设5个元素分别用abcde表示取a与b、c与d进行比较若a>bc>d(也可能是a<bc<d此时情况类似)显然此时进行了两次比较取b与d再比较若b>d则a>b>d若b<d则有c>d>b此时已进行了3次比较要使排序比较最多7次可把另外两个元素按折半检索排序插入到上面所得的有序序列中此时共需要4次比较从而可得算法共只需7次比较8.7.题目中所说的几种排序方法中其排序速度都很快但快速排序、归并排序、基数排序和Shell排序都是在排序结束后才能确定数据元素的全部序列而排序过程中无法知道部分连续位置上的最终元素而堆排序则是每次输出一个堆顶元素(即最大或最少值的元素)然后对堆进行再调整保证堆顶元素总是当前剩下元素的最大或最小的从而可知欲在一个大量数据的文件中如含有15000个元素的记录文件中选取前10个最大的元素可采用堆排序进行8.8.二分法排序8.9.void insertsort(seqlist r)  ;{ //对顺序表中记录R[0一N-1)按递增序进行插入排序&NBSP;int ij;  ;for(i=n-2;i>=0; i--) //在有序区中依次插入r[n-2]..r[0]  ;if(r[i].key>r[i+1].key) //若不是这样则r[i]原位不动 ;{  ;r[n]=r[i];j=i+l;//r[n]是哨兵 ;do{ //从左向右在有序区中查找插入位置 ;r[j-1]= r[j];//将关键字小于r[i].key的记录向右移 ;j++;  ;}whle(r[j].key r[j-1]=r[n];//将引i)插入到正确位置上 ;}//endif ;}//insertsort.  ;8.10.建立初始堆:[937 694 863 265 438 751 742129075 3011]&NBSP;&NBSP;第一次排序重建堆:[863 694 751 765 438 301 742 129 075]9378.11.在排序过程中每次比较会有两种情况出现若整个排序过程至少需作t次比较则显然会有2^t个情况由于n个结点总共有n!种不同的排列因而必须有n!种不同的比较路径于是: 2t≥n!即t≥log2n!因为log2nl=nlog2n-n/ln2+log2n/2+O(1)故有log2n!≈nlog2n从而t≧nlog2n得证8.12.依据堆定义可知:序列(1)、(2)、(4)是堆(3)不是堆从而可对其调整使之为如下的大根堆(1009580604095821020)8.13.第一趟:[265 301] [129 751] [863 937] [694 742] [076 438]&NBSP; &NBSP;第二趟:[129 265 301 751] [694 742 863 937] [076 438]&NBSP;&NBSP;第三趟:[129 265 301 694 742 751 863 937] [076 438]&NBSP;&NBSP;第四趟:[076 129 265 301 438 694 742 751 863 937]&NBSP;8.14.(1)归并排序:(1829) (2547) (1258) (1051)(18252947) (10125158)(1012182529475158)(2)快速排序:(1018251229585147)(1018251229475158)(1012182529475158)(3)堆排序:初始堆(大顶堆):(58 47512918122510)第一次调整:(51 472529181210)(58)第二次调整:(47 2925101812)(5158)第三次调整:(29 18251012)(475158)第四次调整:(25 181210)(29475158)第五次调整:(18 1012)(2529475158)第六次调整:(12 10) (182529475158)第七次调整:(1012182529475158)8.15.(1)直接插入排序序号 1 2 3 4 5 6 7 8 9 10 11 12 关键字 83 40 63 13 84 35 96 57 39 79 61 151=2 40 83 [63 13 84 35 96 57 39 79 61 15] 1=3 40 63 83 [13 84 35 96 57 39 79 61 15] 1=4 13 40 63 83 [84 3 5 96 57 39 79 61 15] I=5 13 40 63 83 84 [35 96 57 39 79 61 15] I=6 13 35 40 63 83 84 [96 57 39 79 61 15] 1=7 13 35 40 63 83 84 96 [57 39 79 61 15] 1=8 13 35 40 57 63 83 84 96 [ 39 79 61 15] 1=9 13 35 39 40 57 63 83 84 96 [79 61 15] I=10 13 35 39 40 57 63 79 83 84 96 [61 15] I=11 13 35 39 40 57 61 63 79 83 84 96 [15] 1=12 13 15 35 39 40 57 61 63 79 83 84 96 (2)直接选择排序序号 1 2 3 4 5 6 7 8 9 10 11 12 关键字 83 40 63 13 84 35 96 57 39 79 61 15i=1 13 [ 40 63 83 84 35 96 57 39 79 61 15] i=2 13 15 [63 83 84 35 96 57 39 79 61 40] i=3 13 15 35 [83 84 63 96 57 39 79 61 40] i=4 13 15 35 39 [84 63 96 57 83 79 61 40] i=5 13 15 35 39 40 [63 96 57 83 79 61 84] i=6 13 15 35 39 40 57 [96 63 83 79 61 84] i=7 13 15 35 39 40 57 61 [63 83 79 96 84] i=8 13 15 35 39 40 57 61 63 [83 79 96 84] i=9 13 15 35 39 40 57 61 63 79 183 96 84] i=10 13 15 35 39 40 57 61 63 79 83 [96 84] i=11 13 15 35 39 40 57 61 63 79 83 84 [96] (3)快速排序关键字 83 40 63 13 84 35 96 57 39 79 61 15 第一趟排序后 [15 40 63 13 61 35 79 57 39] 83 [96 84] 第二趟排序后 [13] 15 [63 40 61 35 79 57 39] 83 84 [96]第三趟排序后 13 15 [39 40 61 35 57] 63 [79] 83 84 96 第四趟排序后 13 15 [35] 39 [61 40 57] 63 79 83 84 96 第五趟排序后 13 15 35 39 [57 40] 61 63 79 83 84 96 第六趟排序后 13 15 35 39 40 [57] 61 63 79 83 84 96 第七趟排序后 13 15 35 39 40 57 61 63 79 83 84 96 (4)堆排序关键字 83 40 63 13 84 35 96 57 39 79 61 15排序成功的序列 96 84 83 79 63 61 57 40 39 35 15 13(5)归并排序关键字 83 40 63 13 84 35 96 57 39 79 61 15 第一趟排序后 [40 83] [13 63] [3584] [57 96] [39 79] [15 61]第二趟排序后 [13 40 63 83] [35 57 84 96] [15 39 61 79] 第三趟排序后 [13 35 40 57 63 83 84 96]] [15 39 61 79] 第四趟排序后 13 15 35 39 40 57 61 63 79 83 84 96。