对
错
第1题:
试题四
阅读下列函数说明和C函数,将应填入 (n) 处的字句写在答题纸的对应栏内。
[函数说明]
函数DeleteNode(Bitree *r,int e)的功能是:在树根结点指针为r的二叉查找(排序)树上删除键值为e的结点,若删除成功,则函数返回0,否则函数返回-1。二叉查找树结点的类型定义为:
typedef struct Tnode{
int data;
struct Tnode *Lchild,*Rchild;
}*Bitree;
在二叉查找树上删除一个结点时,要考虑三种情况:
1若待删除的结点p是叶子结点,则直接删除该结点;
2若待删除的结点p只有一个子结点,则将这个子结点与待删除结点的父结点直接连接,然后删除结点p;
3若待删除的结点p有两个子结点,则在其左子树上,用中序遍历寻找关键值最大的结点s,用结点s的值代替结点p的值,然后删除结点s,结点s必属于上述1、2情况之一。
[函数代码]
int DeleteNode(Bitree *r,int e) {
Bitreep = *r, pp, s, c;
while( (1) ) { /*从树根结点出发查找键值为e的结点*/
pp = p;
if ( e< p->data) p = p -> Lchild;
else p = p->Rchild;
}
if(!p) return –1; /* 查找失败 */
if(p->Lchild && p->Rchild) { /* 处理情况3 */
s = (2);pp = p;
while ( (3) ) { pp = s; s = s-> Rchild; }
p->data = s ->data; p = s;
}
/*处理情况1、2*/
if( (4) ) c = p -> Lchild;
elsec = p -> Rchild;
if(p == *r) *r = c;
elseif ( (5) ) pp -> Lchild = c;
elsepp->Rchild = c;
free(p);
return 0;
}
试题分析:
本程序的功能是删除二叉查找树的一个结点。首先,我们来了解一下什么是二叉查找树。
二叉查找树,又称二叉排序树(BinarySort Tree)。一棵二叉查找树,或者是一棵空树,或者满足以下递归条件:
①查找树的左、右子树各是一棵查找树。
②若查找树的左子树非空,则其左子树上的各结点值均小于根结点的值。
③若查找树的右子树非空,则其右子树上的各结点值均大于根结点的值。
例如下图就是一棵二叉查找树。
了解二叉查找树的概念以后,我们再来看题目会有事半功倍的效果。题目中对怎样删除结点有着比较详细的说明。
第一种情况就是删除叶子结节,叶子结节可以直接删除,这一点很好理解,因为叶子结节删除后并不会打乱查找树的顺序。也就是说把上图中的“20”结点删除,剩下的还是一棵查找树。
第二种情况是删除只有一个子结点的结点,只需把其子结点代替父结点即可,也就是说若要删除图中的“56”结点,只需把“51”移至“56”位置即可,若“51”下有子树,子树结构不变。
第三种情况要复杂一点,要用到二叉查找树的一些性质,就是结点右子树的所有结点都大于根结节,左子树所有结点都小于根结点。所以,当删除了有左右子树的结点时,要在左子树找最大的结节,来替换被删结点。也就是说若要删除图中的”89”结点,要把“56”搬到“89”的位置。再用第二种情况规则,把“51”调整到原来56的位置。
现在我们已经了解了算法流程,可以开始具体的分析程序了。
第一句是变量的声明,以及赋初值,p指向二叉查找树的根。接下来是一个循环,从注释部分可以知道,此循环的功能是查找键值为e的结点。循环内有判断条件当e < p->data 时,进入左子树查找,否则到右子树中查找。很明显没有关于找到结点的处理代码,也就是说,循环内部只处理了没找到结点的情况,所以循环条件应是当找到键值为e的结点时退出循环,同时应注意一个隐含的限制条件,就是当p=NULL时,表示已经查找完毕,也不用进入循环了。所以(1)应填 p && p->data != e。
接下来的if 程序段是处理第 ③种情况的,由循环中的“s = s-> Rchild;”可以看出,s用于在要删结点的左子树中查找键值最大的结点。所以s的初值应是:要删除结点的左子结点。所以,(2)应填:p->Lchild。
结合前面提到的对第③条规则的描述以及二叉查找树的规则,我们可知,要找的结点s应是左子树最右的结点,即右子结点为NULL的结节。所以(3)应填S->Rchild。
再下来就是对①、②的处理了,这里并没有把①、②处理分开进行,而是合在一起进行处理,这里引入了一个中间变量c,用c来存储用于替换p的结点。
我们现在来分析一下,怎样的条件可以使这两种情况合在一起,因为当要删除的结点为叶子结点时,p->Lchild与p->Rchild都为NULL,当要删除的结点有一个子结点时,如果有左子结点,则p->Rchild为Null;如果有右子结点,则p->Lchild为NULL。所以当p->Lchild不为NULL时,说明是第二种情况,p结点含左子结点,所以c=p->Lchild,当p->Lchild为NULL时,说明有两种可能:第一,p->Rchild也为NULL,则p是叶子结点。第二,p->Rchild不为NULL,则p是有右子结点的结点。但这两种情况都可以用:c = p->Rchild,因为当p是叶子结点的时候用NULL代替p的位置即可。所以第(4)空,应填 p->Lchild。在程序中很多地方都出现了变量pp,其实只要仔细看一下前面的程序就知道,pp一直指向的是p结点的前一个结点,即p的父结点,所以(5)的作用是,判断p是其父结点的左子结点,还是右子结点,也就是说(5)应填 pp->Lchild == p。
参考答案:(每空3分)
(1)p && p->data != e 或者 p!=NULL && p->data != e
(2)p->Lchild
(3)s->Rchild
(4)p->Lchild
(5)pp->Lchild == p 或者 p == pp->Lchild
第2题:
阅读下列函数说明和C函数,将应填入(n)处。
【函数3说明】
函数DeleteNode(Bitree * r,int e)的功能是:在树根结点指针为r的二叉查找(排序)树上删除键值为e的结点,若删除成功,则函数返回0,否则函数返回-1。二叉查找树结点的类型定义为:
typedef struct Tnode{
int data; /*结点的键值*/
struct Tnode * Lchild,*Rchild; /*指向左、右子树的指针*/
} * Bitree;
在二叉查找树上删除一个结点时,要考虑三种情况:
①若待删除的结点p是叶子结点,则直接删除该结点;
②若待删除的结点p只有一个子结点,则将这个子结点与待删除结点的父结点直接连接,然后删除结点P;
③若待删除的结点p有两个子结点,则在其左子树上,用中序遍历寻找关键值最大的结点s,用结点s的值代替结点p的值,然后删除结点s,结点s必属于上述①、②情况之一。
【函数3】
int DeleteNode(Bitree * r,int e){
Bitree p=*r,pp,s,c;
while((1)){ /*从树根结点出发查找键值为e的结点*/
pp=p;
if(e<p->data)p=p->Lchild;
else p=p->Rchild;
{
if(!p)return-1; /*查找失败*/
if(p->Lchild &&p->Rchild){/*处理情况③*/
s=(2); pp=p;
while((3)){pp=s;s=s->Rchild;}
p->data=s->data;p=s;
}
/*处理情况①、②*/
if((4))c=p->Lchild;
else c=p->Rchild;
if(p==*r)*r=c;
else if((5))pp->Lchild=c;
else pp->Rchild=c;
free(p);
return 0;
}
第3题:
阅读下列C函数和函数说明,将应填入(n)处的字句写在对应栏内。
【说明】
函数DeleteNode (Bitree *r, int e)的功能是:在树根结点指针为r的二叉查找(排序)树上删除键值为e的结点,若删除成功,则函数返回0,否则函数返回-1。二叉查找树结点的类型定义为:
typedef struct Tnode{
int data; /*结点的键值*/
struct Tnode *Lchild, *Rchild; /*指向左、右子树的指针*/
}*Bitree:
在二叉查找树上删除一个结点时,要考虑3种情况:
①若待删除的结点p是叶子结点,则直接删除该结点;
②若待删除的结点p只有一个子结点,则将这个子结点与待删除结点的父结点直接连接,然后删除结点p;
③若待删除的结点p有两个子结点,则在其左子树上,用中序遍历寻找关键值最大的结点s,用结点s的值代替结点p的值,然后删除结点s,结点s必属于上述①、②情况之一。
【函数】
int DeleteNode (Bitree *r,int e) {
Bitree p=*r,pp,s,c;
while ( (1) ){ /*从树根结点出发查找键值为e的结点*/
pp=p;
if(e<p->data) p=p->Lchild;
else p=p->Rchild;
}
if(!P) return-1; /*查找失败*/
if(p->Lchild && p->Rchild) {/*处理情况③*/
s=(2);pp=p
while (3) {pp=s;s=s->Rchild;}
p->data=s->data; p=s;
}
/*处理情况①、②*/
if ( (4) ) c=p->Lchild;
else c=p->Rchild;
if(p==*r) *r=c;
else if ( (5) ) pp->Lchild=c;
else pp->Rchild=c;
free (p);
return 0;
}
第4题:
第5题:
产品在被购买之后,就进入买后阶段。购买者对购买活动的满意感(s)是产品期望(E)和该产品可觉察性能(P)的函数,即S=f(E P)。以下关于E和P关系描述正确的是( )。
A.若E=P时,消费者满意
B.若E>P 时,消费者不满意
C.若E
D.E和P之间的差距越大,消费者的不满意感也就越强
第6题:
购买者对其购买活动的满意感(S)是其产品期望(E)和该产品可能觉察性能(P)的函数,即S=f(E,P)。若E>P,则()。
A、消费者会满意
B、消费者不满意
C、消费者会非常满意
D、消费者无所谓
第7题:
设有如下函数定义。若在主函数中用语句cout<<f("good")调用上述函数,则输出结果为(48)。 int f(char *s){ char *p=s; while(*p! ='\0')p++; return(p-s); }
A.3
B.4
C.5
D.6
第8题:
阅读下列函数说明和C函数,将应填入(n)处的字句写在对应栏内。
【说明】
函数DeleteNode(Bitree*r,inte)的功能是:在树根节点指针为r的二叉查找(排序)树上删除键值为e的节点,若删除成功,则函数返回0,否则函数返回-1。二叉查找树节点的类型定义为:
typedef struct Tnode{
int data;/*节点的键值*/
struct Tnode *Lchild,*Rchiid;/*指向左、右子树的指针*/
}*Bitree;
在二叉查找树上删除一个节点时,要考虑3种情况。
①若待删除的节点p是叶子节点,则直接删除该节点。
②若待删除的节点p只有一个子节点,则将这个子节点与待删除节点的父节点直接连接,然后删除节点。
③若待删除的节点p有两个子节点,则在其左子树上,用中序遍历寻找关键值最大的节点 s,用节点s的值代替节点p的值,然后删除节点s,节点s必属于上述①、②情况之一。
【函数5-5】
int DeleteNode(Bitree *r,int e){
Bitree p=*r,pp,s,c;
while( (1) {/*从树根节点出发查找键值为e的节点*/
pp=p;
if(e<p->data)p=p->Lchild;
else p=p->Rehild;
}
if(!p)retrn -1;/*查找失败*/
if(p->Lchild && p->Rchild){/*处理情况③*/
s=(2); pp=p;
while( (3)){pp=s;s=s->Rchild;}
p->data=s->data;p=s;
}
/* 处理情况①、②*/
if((4))c=p->Lchild;
else c=p->Rchild;
if(p== *r)*r=c;
else if((5))pp->Lchild=c;
else pp->Rchild=c;
free(p);
return 0;
}
第9题:
第10题: