严蔚敏-数据结构集合习题 下载本文

查找成功的平均查找长度是=1*0.25+2*(0.12+0.20)+3*(0.1+0.08+0.20)+4*0.05=2.23 由于在构造次优查找树的过程中,没有考查单个关键字的相应权值,可能出现根的关键字的权值比之相邻的关键字的权值小,这时要作调整:选邻近的权值较大的关键字作次优查找树的根结点。调整后的次优查找树如图73(2)。 74.

75.这里失败结点是不存在的结点,在其双亲结点处查找失败,这时的比较次数为Li-1。

76.

(1) 顺序查找判定树

(2)ASL顺序成功 =(1p1 +2p2+3p3+4p4+5p5)=0.97 ASL折半成功 =(1p3+2(p1+p4)+3(p2+p5)=1.04 ASL折半失败 =(2q0+3q1+3q2+2q3+3q4+3q5)=1.30 ASL顺序失败 =(1q0+2q1+3q2+4q3+5q4+5q5)=1.07 (3)本题中顺序检索好。

77.时间复杂度是判断检索方法的一个重要指标,但不是唯一指标。使用什么检索方法要综合考虑。哈希检索时间O(1),查找速度最快,但需构建哈希函数,进行计算哈希地址,查找时要有解决冲突的方法;二分检索时间O(log2n),需要元素有序且顺序存储,排序操作的时间开销大;顺时检索时间最差为O(n),但对检索表无要求,数据有序无序均可,在数据量较小时使用方便。

五.算法设计题

1. 根据二叉排序树中序遍历所得结点值为增序的性质,在遍历中将当前遍历结点与其前驱

结点值比较,即可得出结论,为此设全局指针变量pre(初值为null)和全局变量flag,初值为true。若非二叉排序树,则置flag为false。 #define true 1 #define false 0

typedef struct node

{datatype data; struct node *llink,*rlink;} *BTree; void JudgeBST(BTree t,int flag)

// 判断二叉树是否是二叉排序树,本算法结束后,在调用程序中由flag得出结论。 { if(t!=null && flag)

{ Judgebst(t->llink,flag);// 中序遍历左子树

if(pre==null)pre=t;// 中序遍历的第一个结点不必判断

else if(pre->datadata)pre=t;//前驱指针指向当前结点 else{flag=flase;} //不是完全二叉树 Judgebst (t->rlink,flag);// 中序遍历右子树 }//JudgeBST算法结束

本题的另一算法是照定义,二叉排序树的左右子树都是二叉排序树,根结点的值大于左子树中所有值而小于右子树中所有值,即根结点大于左子树的最大值而小于右子树的最小值。算法如下:

int JudgeBST(BTree t)

//判断二叉树t是否是二叉排序树,若是,返回true,否则,返回false {if(t==null)return true;

if(Judgebst(t->llink)&& Judgebst(t->rlink))//若左右子树均为二叉排序树

{m=max(t->llink);n=min(t->rlink);//左子树中最大值和右子树中最小值 return (t->data>m && t->data

int max(BTree p)//求二叉树左子树的最大值

{if(p==null) return -maxint;//返回机器最小整数 else{while(p->rlink!=null)p=p->rlink; return p->data;} }

int min(BTree p)//求二叉树右子树的最小值

{if(p==null) return maxint;//返回机器最大整数 else{while(p->llink!=null)p=p->llink; return p->data;} }

2.[题目分析]借助于分块查找思想,在建立数据顺序表的同时,建立一索引表。数据表中按k个集合分块(元素个数不一定相等),索引表中有两个域,一是各集合最后一个元素在数据表中的位置(一维数组中的下标),二是集合的个数(k)。实现数据运算时,根据给定的二元组(i,x),首先在索引表中找到集合i的位置,然后在数据表中查找x。如查到x ,则查找成功,返回x在数据表中的位置,否则查找失败。若要插入,则将数据表中的数据后移,插入x,同时修改索引表。

typedef struct {datatype data;}rectype; typedef struct

{int a[];//a数组容量够大,存储各集合最后一个数据在数据表中的下标 int k; //集合个数 }index;

int SetSearch_Insert(rectype R[],index id,datatype x,int i)

//数据表R,查找第i个集合的元素x,若查找成功,返回其位置,否则将其插入第i个集合

{if(i<1 || i>id.k)printf(“无第%d个集合\\n”,i);exit(0);}

if(i==1)first=0;else first=id.a[i-1]+1; //first指向第i个集合在数据表的首址

last= id.a[i];//last是第i个集合在数据表中的末址

for(j=first;j≤last;j++) if(R[j]==x)return (j);//查找成功 for(j=id.a[id.k];j>id.a[i];j--) //查找失败,将x插入数据表 R[j+1]=R[j];//元素后移

R[j+1]=x; //将x插入到原第i个集合最后一个元素之后。

for(j=i;j≤k;j++)id.a[j]++;//修改索引表中各集合最后一个元素的下标 }结束SetSearch_Insert

由于各集合元素个数不等,各块长度不等且块间无序,索引表中用数组表示,数组中元素值是各集合最后一个元素在数据表中的下标。按本算法插入(2,11.2)和(1,5.3),数据表前后状态如下: 插0 入10.前 2 插10.入2 后 1 1.7 1.7 2 4.8 4.8 3 16.2 16.2 4 1.7 5.3 5 8.4 1.7 6 0.5 8.4 7 4.8 0.5 8 9 10 11 12 13 14 2.7 4.2 5.1 3.6 3.9 2.7 5.1 3.9 4.2 3.6 11.2 4.8 插入前,索引表中a数组的内容是3,6,12,插入后修改为4,8,14。 3.(1)非递归建立二叉排序树,在二叉排序树上插入的结点都是叶子结点。 void Creat_BST(BiTree bst,datatype K[],int n)

// 以存储在数组K中的n个关键字,建立一棵初始为空的二叉排序树。 {for(i=1;i≤n;i++)

{p=bst;f=null;//在调用Creat_BST时,bst=null while(p!=null)

if(p->dataRLINK; } // f是p的双亲 else if(p->data>K[i]){ f=p;p=p->LLINK;}

s=(BiTree)malloc(sizeof (BiNode));// 申请结点空间 s->data=K[i];s->LLINK=null;s->RLINK=null; if(f==null)bst=s; //根结点 else if(s->datadata)f->LLINK=s;//左子女

else f->RLINK=s;//右子树根结点的值大于等于根结点的值 }//算法结束

(2)[题目分析]本题要求输出遍历二叉排序树的嵌套括号表示。其算法思想是,若二叉排序树非空,则输出根结点,再输出其左右子树。在输出其左右子树前,要输出左括号,在输出其右子树前要输出逗号,在输出其右子树后要输出右括号,在左右子树均空情况下,则不输出括号。

void Print(BiTree t)

//以嵌套括号表示结构打印二叉排序树 {if(t!=null)

{printf(t->data);//打印根结点值

if(t->LLINK || t->LLINK);//左子女和右子女中至少有一个不空 {printf(“(”); //输出左括号

Print(t->LLINK); //输出左子树的嵌套括号表示

if(t->RLINK)printf(“,”);//若右子树不空,输出逗号 Print(t->RLINK); //输出右子树的嵌套括号表示 printf(“)”); //输出右括号 }//if }}//Print

4. void Delete(BSTree t,p)

// 在二叉排序树t中,删除f所指结点的右孩子(由p所指向)的算法

{if(p->lchild==null){f->rchild=p->rchild;free(p);} //p无左子女 else //用p左子树中的最大值代替p结点的值 {q=p->lchild;s=q;

while(q->rchild){s=q;q=q->rchild ;}//查p左子树中序序列最右结点 if(s==p->lchild) //p左子树的根结点无右子女

{p->data=s->data;p->lchild=s->lchild;free(s);} else{p->data=q->data;s->rchild=q->lchild;free(q);} }

}//Delete

5.[题目分析]上题用被删结点左子树中最大值结点代替被删结点,本题用被删结点右子树中最小值(中序遍历第一个)结点代替被删结点。

void Delete(BSTree bst,p,fp)

//在二叉排序树bst上,删除fp所指结点的左子女(由p所指向)的算法。

{if(!p->lchild){fp->lchild=p->rchild;free(p);} //p无左子女

else if(!p->rchild){fp->lchild=p->lchild;free(p);} //p无右子女

else // p有左子女和右子女

{q=p->rchild;s=q;//用p右子树中的最小值代替p结点的值

while(q->lchild){s=q;q=q->lchild ;}//查p右子树中序序列最左结点 if(s==p->rchild) //p右子树的根结点无左子女

{p->data=s->data;p->rchild=s->rchild;free(s);} else{p->data=q->data;s->lchild=q->rchild;free(q);} }//Delete

6.[题目分析] 在二叉排序树上删除结点,首先要查找该结点。查找成功后,若该结点无左子树,则可直接将其右子树的根结点接到其双亲结点上;若该结点有左子树,则将其左子树中按中序遍历的最后一个结点代替该结点,从而不增加树的高度。

void Delete(BSTree bst, keytype X)

//在二叉排序树bst上,删除其关键字为X的结点。 {BSTree f,p=bst;

while (p && p->key!=X) //查找值为X的结点 if (p->key>X) {f=p; p=p->lchild;} else {f=p; p=p->rchild;}

if (p==null) {printf(“无关键字为X的结点\\n”); exit(0);} if {p->lchild==null} //被删结点无左子树

if (f->lchild==p) f->lchild=p->rchild;//将被删结点的右子树接到其双亲上 else f->rchild=p->rchild;

else {q=p; s=p->lchild; //被删结点有左子树