阅读以下函数说明和C程序,将C程序中(1)~(6)空缺处的语句补充完整。【说明】喜迎2008年北京奥运会!以下【C程序】能将一个给定汉字(例如,奥运会的“会”字)的点阵逆时针旋转90°,并输出旋转前后的点阵数据及字形。图1-15是汉字“会”字的16×16点阵字形,用数字0表示空白位置,用数字1表示非空白位置,“会”字的第1行即可表示成如下的{0,1}序列:0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0如果把它看做一个字的16个位,“会”字的第1行可以用十六进制数0100来表示。同理,“会”

题目

阅读以下函数说明和C程序,将C程序中(1)~(6)空缺处的语句补充完整。

【说明】

喜迎2008年北京奥运会!以下【C程序】能将一个给定汉字(例如,奥运会的“会”字)的点阵逆时针旋转90°,并输出旋转前后的点阵数据及字形。

图1-15是汉字“会”字的16×16点阵字形,用数字0表示空白位置,用数字1表示非空白位置,“会”字的第1行即可表示成如下的{0,1}序列:

0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0

如果把它看做一个字的16个位,“会”字的第1行可以用十六进制数0100来表示。同理,“会”字的第2行可以用十六进制数0240表示,第3行可以用十六进制数0420表示……依此类推,用16个双字节整型数即可存放一个汉字点阵字形。“会”字的点阵数据及字形如图1-15的左半部分所示。

将一个汉字逆时针旋转90°,就是把该汉字点阵的最右列作为旋转后新点阵的第1行,次最右列作为旋转后新点阵的第2行……依此类推来形成一个旋转后的点阵字形。图1-15的右半部分就是将“会”字逆时针旋转90°后的点阵数据和字形(提示:读者可将书本顺时针旋转90°,以查看旋转90°后的点阵字形)。

在【C程序】中,数组old存放着“会”字的16个双字节整型点阵数据。函数turnleft能将该点阵数据逆时针旋转90°,旋转后的点阵数据存放在数组new中。函数display能将旋转前后的点阵数据加以编辑,用字符“.”表示值为0的位,用字符“x”表示值为1的位,从而将旋转前后的点阵按行输出其十六进制的数据和字形,如图1-15所示。

【C程序】

include <stdio.h>

define EMPTY '.'

define NONEMPTY 'x'

define LEFT 0

define RIGHT 1

main ()

{ static unsigned old[16]=

{ 0x0100,0x0240,0x0420,0x0810,0x1004,0x23c2,

0x4001,0x8ff8,0x0100,0x0200,0x0400,0x0800,

0xl000,0x2004,0x7ffe,0x0001

};

unsigned new[16];

turnleft (old, new);

display (old,new);

}

turnleft (old,new)

unsigned old[],new[];

{ int row, k;

for (row=0;row<16;row++)

for ((1);k<16;k++)

new[row]|=((old[k]>>(2))&1) <<(3);

}

display (old, new)

unsigned *old,*new;

{ char out[2] [17],letter[2];

int row, col;

letter[O] = EMPTY;

letter[1] = NONEMPTY;

out[LEFT] [16]=out[RIGHT] [16]=(4);

for (row = 0;row<16;row++,old++,new++)

{ for (col = 0;co1<16;++col)

{ out[LEFT] [col] = letter[ ((5)) &1];

out[RIGHT] [col] = letter[ ((6)) &1];

}

printf("\n %4x %s",*old,&out[LEFT] [0]);

printf("%4x %s",*new,&out[RIGHT] [0]);

}

}


相似考题
更多“ 阅读以下函数说明和C程序,将C程序中(1)~(6)空缺处的语句补充完整。【说明】喜迎2008年北京奥运会!以下【C程序】能将一个给定汉字(例如,奥运会的“会”字)的点阵逆时针旋转90°,并输出旋转前后的点阵数据及”相关问题
  • 第1题:

    阅读以下应用程序说明和C程序,将C程序段中(1)~(7)空缺处的语句填写完整。

    [说明]

    以下[C程序]完成从指定数据文件中读入职工的工号和他完成产品个数的数据信息,对同一职工多次完成的产品个数进行累计,最后按表5-22所示的格式输出职工完成产品数量的名次(ORDER)。该名次是按每位职工完成的产品数量(QUANTITY)排序,之后同一名次的职工人数(COUNT)和他们的职工号(NUMBER,同一名次的职工号以从小到大的顺序输出)。

    以下[C程序]采用链表结构存储有关信息,链表中的每个表元对应一位职工。在数据输入同时,形成一个有序链表(按完成的产品数量和工号排序)。当一个职工有新的数据输入,在累计他的完成数量时会改变原来链表的有序性,为此应对链表进行删除、查找和插入等处理。

    [C程序]


    正确答案:这是一道要求读者掌握有序链表的特点及其如何在有序链表上实现插入、删除、查找的操作的程序分析题。本题的解答思路如下。 仔细阅读[C程序]可知该程序代码采用链表结构存储有关信息链表中的每个结点对应一位职工。在数据输入时形成一个有序链表(按完成的产品数量和工号排序)。当一个职工有新的数据输入在累计该职工的完成数量时会改变原来链表的有序性因此需要对链表中的结点重新进行排序。而对程序的排序操作可以看成是一组查找、删除、插入操作的组合操作这组操作又和链表的特点密切相关。 链表是用一组任意的存储空间来依次存放线性表中的数据元素及其元素之间关系的存储结构。由于链表的存储空间是在程序运行的过程中动态分配的需要一个个分配一个存储空间因此无须事先估计存储空间大小也不会出现存储空间的浪费并能够使存储器中的碎片充分地得到利用但是存储空间的地址不一定连续。 用链表表示一个数据结构时为了表示数据元素之间的逻辑关系每个数据元素的存储空间都包括数据域和指针域两个部分。数据域用来存放数据元素本身的值指针域用来存放和该数据元素存在某种逻辑关系的其他元素的地址(或对应数组的下标)从而通过指针域中的指针指示数据元素之间的逻辑关系。 在链表结构中进行插入和删除运算不需要移动数据元素只需修改数据元素的指针域的地址就可以建立元素之间新的逻辑关系。由于这种结构失去了随机存取的特性只能依照链接顺序访问存取效率不高因此不适合进行查找运算。 本试题函数proc()完成的功能是从给定的数据文件中输入职工的工号(即fscanf (fp "%d"&n) ;)和该职工完成的产品数量信息(即fscanf(fp "%d" &m); )从而形成一个按照产品数量和工号排序的职工有序链表。例如输入一个工号为n的职工的全部信息后就利用指针v从链表的首结点开始顺序搜索满足条件(即工号等于n)的结点这个过程依赖for循环语句(即for(v=base v!=NULL&&v->no!=n; u=v v=v->next); )的实现。当循环条件v!=NULL且v->no!=n为真时说明指针v指向的当前结点存在但却不是满足条件的结点所以指针v通过语句u=v v=v->next实现向后移动继而指向下一个结点然后再重复上述的判断、移动过程直到找到满足条件的结点或确定链表中根本不存在这样的结点为止。由于这两种结果不能同时发生所以for循环后的if-else条件语句先要对上述查找过程可能产生的两种结果做出选择然后再决定继续执行的操作。又由于 if条件为真的情况下要执行的复合语句中包含累计产品数量的语句(即v->q+m; )所以可判断出程序首先是对链表中存在的刚输入职工的工号的情况进行处理因此(1)空缺处所填写的内容是“v!=NULL&&v->no==n”或其他等价形式。 根据上述链表中存在刚输入职工工号的情况则需要重新对该工号职工进行产品数量的累计从而改变原来链表的有序性为此应该对链表中的结点重新进行排序。那么该程序的排序操作可以看成是一组删除、查找、插入操作的组合操作。 首先将链表中满足条件(即工号为n)的结点v删除。删除分为两种情况:①当删除的结点是链表的首结点即v与base同指向一个结点时需改变链表的头指针让它指向首结点的直接后继结点因此(2)空缺处所填写的内容是“v==base”或其他等价形式;②当删除的结点是链表中的其他结点时需改变链表中要删除结点的直接前驱结点的后继指针。 其次在有序链表中为上述被删除的结点v寻找合适的插入位置。插入位置是根据待插入的结点(即上述被删除的结点)中产品累计数量的多少以及工号的大小与链表中现存结点进行比较确定的。根据它们的比较结果插入位置可以有以下3种情况(令指针p指向链表中正在与待插入结点进行比较的结点而指针u用来指向其直接前驱结点)。 ①指针p所指向结点的q值(即产品累计数量)小于待插入结点v的q值(即产品累计数量)于是将结点v插入到p所指向的结点之前。 ②指针p所指向结点的q值与待插入结点v的q值相等但前者的no值(即工号)大于后者的no值于是将结点v插入到p所指向的结点之前。 ③指针p所指向结点的q值比待插入结点v的q值都大于是一直向后寻找直到p==NULL为止这时指针u指向链表中的最后一个结点因而将结点v插入到链表的尾部即成为结点U的直接后继。 由以上分析可知(3)空缺处所填写的内容是“p->qv->q‖p->q==v->q&&p->no>n->no”或其他等价形式。由于以上分析中前两种情况都属于在指针p所指向结点之前插入结点v因此要考虑一个关键的插入位置以及是否在首结点之前插入即(4)空缺处所填写的内容是“p==base”或其他等价形式(5)空缺处所填写的内容是“v->next=p”或其他等价形式。 函数output()完成的功能是按照指定的格式输出。(6)空缺处所在的for循环实现了相同q值的结点个数的统计这些结点按照工号从小到大的顺序形成一个有序链表段。为了使表达式正确计算(6)空缺处需要填入“v!=NULL&&v->q==u->q”或其他等价形式。 由于(7)空缺处所在的for循环实现了有相同产品个数的职工工号的顺序输出因此(7)空缺处所填写的内容是“count--!=0(或u!=v)”或其他等价形式。
    这是一道要求读者掌握有序链表的特点及其如何在有序链表上实现插入、删除、查找的操作的程序分析题。本题的解答思路如下。 仔细阅读[C程序]可知,该程序代码采用链表结构存储有关信息,链表中的每个结点对应一位职工。在数据输入时,形成一个有序链表(按完成的产品数量和工号排序)。当一个职工有新的数据输入,在累计该职工的完成数量时会改变原来链表的有序性,因此需要对链表中的结点重新进行排序。而对程序的排序操作可以看成是一组查找、删除、插入操作的组合操作,这组操作又和链表的特点密切相关。 链表是用一组任意的存储空间来依次存放线性表中的数据元素及其元素之间关系的存储结构。由于链表的存储空间是在程序运行的过程中动态分配的,需要一个个分配一个存储空间,因此无须事先估计存储空间大小,也不会出现存储空间的浪费,并能够使存储器中的碎片充分地得到利用,但是存储空间的地址不一定连续。 用链表表示一个数据结构时,为了表示数据元素之间的逻辑关系,每个数据元素的存储空间都包括数据域和指针域两个部分。数据域用来存放数据元素本身的值,指针域用来存放和该数据元素存在某种逻辑关系的其他元素的地址(或对应数组的下标),从而通过指针域中的指针指示数据元素之间的逻辑关系。 在链表结构中进行插入和删除运算不需要移动数据元素,只需修改数据元素的指针域的地址就可以建立元素之间新的逻辑关系。由于这种结构失去了随机存取的特性,只能依照链接顺序访问,存取效率不高,因此不适合进行查找运算。 本试题函数proc()完成的功能是从给定的数据文件中输入职工的工号(即fscanf (fp, "%d",&n) ;)和该职工完成的产品数量信息(即fscanf(fp, "%d", &m); ),从而形成一个按照产品数量和工号排序的职工有序链表。例如输入一个工号为n的职工的全部信息后,就利用指针v从链表的首结点开始顺序搜索满足条件(即工号等于n)的结点,这个过程依赖for循环语句(即for(v=base v!=NULL&&v->no!=n; u=v, v=v->next); )的实现。当循环条件v!=NULL且v->no!=n为真时,说明指针v指向的当前结点存在但却不是满足条件的结点,所以指针v通过语句u=v, v=v->next实现向后移动,继而指向下一个结点,然后再重复上述的判断、移动过程,直到找到满足条件的结点或确定链表中根本不存在这样的结点为止。由于这两种结果不能同时发生,所以for循环后的if-else条件语句,先要对上述查找过程可能产生的两种结果做出选择,然后再决定继续执行的操作。又由于 if条件为真的情况下,要执行的复合语句中包含累计产品数量的语句(即v->q+m; ),所以可判断出程序首先是对链表中存在的刚输入职工的工号的情况进行处理,因此(1)空缺处所填写的内容是“v!=NULL&&v->no==n”或其他等价形式。 根据上述链表中存在刚输入职工工号的情况,则需要重新对该工号职工进行产品数量的累计,从而改变原来链表的有序性,为此应该对链表中的结点重新进行排序。那么,该程序的排序操作可以看成是一组删除、查找、插入操作的组合操作。 首先,将链表中满足条件(即工号为n)的结点v删除。删除分为两种情况:①当删除的结点是链表的首结点,即v与base同指向一个结点时,需改变链表的头指针,让它指向首结点的直接后继结点,因此(2)空缺处所填写的内容是“v==base”或其他等价形式;②当删除的结点是链表中的其他结点时,需改变链表中要删除结点的直接前驱结点的后继指针。 其次,在有序链表中为上述被删除的结点v寻找合适的插入位置。插入位置是根据待插入的结点(即上述被删除的结点)中产品累计数量的多少,以及工号的大小与链表中现存结点进行比较确定的。根据它们的比较结果,插入位置可以有以下3种情况(令指针p指向链表中正在与待插入结点进行比较的结点,而指针u用来指向其直接前驱结点)。 ①指针p所指向结点的q值(即产品累计数量)小于待插入结点v的q值(即产品累计数量),于是将结点v插入到p所指向的结点之前。 ②指针p所指向结点的q值与待插入结点v的q值相等,但前者的no值(即工号)大于后者的no值,于是将结点v插入到p所指向的结点之前。 ③指针p所指向结点的q值比待插入结点v的q值都大,于是一直向后寻找,直到p==NULL为止,这时指针u指向链表中的最后一个结点,因而将结点v插入到链表的尾部,即成为结点U的直接后继。 由以上分析可知,(3)空缺处所填写的内容是“p->qv->q‖p->q==v->q&&p->no>n->no”或其他等价形式。由于以上分析中前两种情况都属于在指针p所指向结点之前插入结点v,因此要考虑一个关键的插入位置,以及是否在首结点之前插入,即(4)空缺处所填写的内容是“p==base”或其他等价形式,(5)空缺处所填写的内容是“v->next=p”或其他等价形式。 函数output()完成的功能是按照指定的格式输出。(6)空缺处所在的for循环实现了相同q值的结点个数的统计,这些结点按照工号从小到大的顺序形成一个有序链表段。为了使表达式正确计算,(6)空缺处需要填入“v!=NULL&&v->q==u->q”或其他等价形式。 由于(7)空缺处所在的for循环实现了有相同产品个数的职工工号的顺序输出,因此(7)空缺处所填写的内容是“count--!=0(或u!=v)”或其他等价形式。

  • 第2题:

    请认真阅读以下函数说明、图及C程序,将程序段中(1)~(7)空缺处的语句填写完整。

    [说明]

    一般的树结构常采用孩子—兄弟表示法表示,即用二叉链表做树的存储结构,链表中节点的两个链域分别指向该节点的第一个孩子节点和下一个兄弟节点。例如,如图1-15(a)所示树的孩子—兄弟表示如图1-15(b)所示。

    函数LevelTraverse()的功能是对给定树进行层序遍历。例如,对如图1-15所示的树进行层序遍历时,节点的访问次序为D B A E F P C。

    对树进行层序遍历时使用了队列结构,实现队列基本操作的函数原型如表1-11所示。

    Bool、Status类型定义如下:

    树的二叉链表节点定义如下:

    [C函数程序]


    正确答案:这是一道要求读者掌握树结构的存储及遍历运算的程序分析题。本试题的解答思路如下。 队列可以保证访问节点时按照层次和自左至右的顺序。借助队列结构对树进行层序遍历时每个节点都进出队列一次节点出队列时进行访问。其过程是首先令树根节点入队若是森林(树根之间互为兄弟)接着则令其余树的根节点入队然后在队列非空的情况下队头节点出队访问该节点同时令其孩子节点入队。以此类推直到队列为空。 在试题所给出的[C函数程序]中代码“InitQueue(&tempQ); (1) ;”完成初始化队列并令根节点入队列的功能因此(1)空缺处所填写的内容是“EnQueue(&tempQ root)”。 采用二叉树存储树结构时其右分支表示兄弟关系因此队头节点出队时应沿右分支将队头节点的所有孩子依次加入队列。(2)空缺处所在的while循环完成处理第一棵树的兄弟节点的功能因此(2)空缺处所填写的内容是“brotherptr=brotherptr->nextbrother”。至此就完成了第一层节点的处理。 (3)空缺处用于判断队列是否为空即应填入“!IsEmpty(tempQ)”或其他等价形式。 使用队列或栈结构存储元素以实现某种运算的基本特点是当队列非空时应令队头元素出队列。因此(4)空缺处所填写的内容是“DeQueue(&tempQ&ptr)”。 若一个节点不存在孩子则其firstchild指针域为空也无须令其孩子节点入队列。因此(5)空缺处所填写的内容是“!ptr->firstchild”或其他等价形式。反之若一个节点有孩子则应首先令其第一个孩子节点入队列然后通过右分支链使其他孩子节点入队列。因此(6)空缺处所填写的内容是“EnQueue(&tempQptr->firstchild)”(7)空缺处所填写的内容是“brotherptr=brotherptr->nextbrother”。
    这是一道要求读者掌握树结构的存储及遍历运算的程序分析题。本试题的解答思路如下。 队列可以保证访问节点时按照层次和自左至右的顺序。借助队列结构对树进行层序遍历时,每个节点都进出队列一次,节点出队列时进行访问。其过程是,首先令树根节点入队,若是森林(树根之间互为兄弟),接着则令其余树的根节点入队,然后在队列非空的情况下,队头节点出队,访问该节点同时令其孩子节点入队。以此类推,直到队列为空。 在试题所给出的[C函数程序]中,代码“InitQueue(&tempQ); (1) ;”完成初始化队列并令根节点入队列的功能,因此(1)空缺处所填写的内容是“EnQueue(&tempQ, root)”。 采用二叉树存储树结构时,其右分支表示兄弟关系,因此队头节点出队时,应沿右分支将队头节点的所有孩子依次加入队列。(2)空缺处所在的while循环完成处理第一棵树的兄弟节点的功能,因此,(2)空缺处所填写的内容是“brotherptr=brotherptr->nextbrother”。至此,就完成了第一层节点的处理。 (3)空缺处用于判断队列是否为空,即应填入“!IsEmpty(tempQ)”或其他等价形式。 使用队列或栈结构存储元素以实现某种运算的基本特点是,当队列非空时,应令队头元素出队列。因此(4)空缺处所填写的内容是“DeQueue(&tempQ,&ptr)”。 若一个节点不存在孩子,则其firstchild指针域为空,也无须令其孩子节点入队列。因此,(5)空缺处所填写的内容是“!ptr->firstchild”或其他等价形式。反之,若一个节点有孩子,则应首先令其第一个孩子节点入队列,然后通过右分支链使其他孩子节点入队列。因此,(6)空缺处所填写的内容是“EnQueue(&tempQ,ptr->firstchild)”,(7)空缺处所填写的内容是“brotherptr=brotherptr->nextbrother”。

  • 第3题:

    阅读以下说明和C++代码。

    [说明]

    已知类SubClass的getSum方法返回其父类成员与类SubClass成员j的和,类 SuperClass中的getSum为纯虚拟函数。程序中的第23行有错误,请修改该错误并给出修改后的完整结果,然后完善程序中的空缺,分析程序运行到第15行且尚未执行第15行的语句时成员变量j的值,最后给出程序运行后的输出结果。

    [C++代码]


    正确答案:(1)this->j (2)SuperClass∷ 错误更正结果:SuperClass*s=new SubClass(-3); 变量i的值:0 运行结果:-32
    (1)this->j (2)SuperClass∷ 错误更正结果:SuperClass*s=new SubClass(-3); 变量i的值:0 运行结果:-3,2 解析:本题考查的是面向对象程序设计语言C++。
    考查的主要知识点为C++程序设计语言中类成员变量的初始化、父类成员方法的调用、对象的构造等。第一空要求用用参数j的值更新数据成员,由于成员变量名也为i因此需要明确地指出需要更新的变量j为类中的成员变量,可以在前面加上一个明确的前缀this来表示,因此(1)处应填写this->j:(2)处要求调用父类的成员方法getValue(),为了和子类中的getValue()相区别,需要加上域前缀,因此(2)处应该填写SuperClass∷,表明该函数属于类SuperClass;在程序的第23行,由于SuperClass s表明已经定义了一个对象,因此,后面不应该使用new再次分配一个对象,但是后面的程序代码将s作为一个对象指针使用,因此需要将s定义为一个指针,因此更改后结果应为:SuperClass*s= new SubClass(-3);当程序运行到第15行但是还没有执行15行的语句时,成员变量i的值应为构造函数初始化列表中指定的j的初始化值,本题目为0:最后程序的输出为-3和 2,-3为子类中成员变量j的值,而2表示父类中i的值和子类中i的值的和。

  • 第4题:

    试题二(共15分)

    阅读以下说明和C程序代码,将解答写在答题纸的对应栏内。

    【说明】

    下面是一个待修改的C程序,其应该完成的功能是:对于输入的一个整数num,计算其位数k,然后将其各位数字按逆序转换为字符串保存并输出。若num为负整数,则输出字符串应有前缀“-”。例如,将该程序修改正确后,运行时若输入“14251”,则输出“15241”;若输入“-6319870”,则输出“-0789136”。

    下面给出的C程序代码中有五处错误,请指出错误代码所在的行号并给出修改正确后的完整代码行。

    【C程序代码】


    正确答案:

    以上解答不分次序

  • 第5题:

    阅读以下函数说明和C代码,将C程序中(1)~(5)空缺处的语句填写完整。

    [说明]

    函数int Toplogical(LinkedWDigraphG)的功能是对图G中的顶点进行拓扑排序,并返回关键路径的长度。其中,图G表示一个具有n个顶点的AOE-网,图中顶点从1~n依次编号,图G的存储结构采用邻接表表示,其数据类型定义如下。

    例如,某AOE-网如图6-22所示,其邻接表存储结构如图6-23所示。

    [函数]


    正确答案:是一道要求读者掌握数据结构中拓扑排序和求关键路径问题的算法分析及设计题。本题的解答思路如下。 AOE网(Activity On Edge network边表示活动的网)是一个带权的有向无环图其中顶点表示事件弧表示活动权表示活动持续的时间。通常AOE网可以用来估算工程的完成时间。 在AOE网中入度为0的顶点为源点出度为0的顶点为汇点。由于有些活动可以并行地执行因此从源点到汇点的路径中长度最长的路径称为关键路径(路径长度即指路径上各种活动持续时间之和)。表示事件的顶点存在最早、最晚发生时间。若以顶点V1表示源点、顶点Vn表示汇点则汇点的最早发生时间和最晚发生时间是一致的并且等于关键路径的长度。 设顶点Vj的最早发生时间用ve(j)表示则ve(j)是指从源点V1到Vj的最长路径长度(时间)。这个时间决定了所有从Vj发出的弧所表示的活动能够开工的最早时间。 ve(j)计算方法为 其中T是所有到达顶点j的弧的集合;dut(Ij>)是弧Ij>上的权值;n是网中的顶点数(即汇点的序号)。 显然上式是一个从源点开始的递推公式。Ve(j)的计算必须在Vj的所有前驱顶点的最早发生时间全部求出后才能进行。这样必须对AOE网进行拓扑排序然后按拓扑有序序列逐个求出各顶点事件的最早发生时间。 拓扑排序是将有向无环图中所有顶点排成一个线性序列的过程并且该序列满足:若在有向图中从顶点Vi到Vj有一条路径则在该线性序列中顶点Vi必然在顶点Vj之前。可见拓扑排序序列是由有向图中的所有顶点构成的一个线性序列在这个序列中体现了所有顶点之间的优先关系。 对AOE网进行拓扑排序的步骤如下: ①首先在AOE网中选择一个入度为0(没有前驱)的顶点且输出它。 ②然后从网中删除该顶点并且删除以该顶点为始点的所有引出边。 ③重复上述两个步骤直至网中不存在入度为0的顶点为止。 在拓扑排序过程中有可能同时存在多个入度为0的顶点函数中用顺序栈Stack[]暂存入度为0且没有进入拓扑序列的顶点。 本试题所给出的算法首先申请了3块连续的地址空间分别用来存放关键路径长度、网中各顶点的入度及入度为0的顶点编号它们的首地址分别存放在指针变量Ve、indegree、Stack中。 算法主体是由3个for循环和3个while循环组成。第1个for循环即for(j=1;j=G.n;j++){ve[j]=0; indegree[j]=O;}主要完成数组初始化的功能。 进行拓扑排序之前应先求出网中每个顶点的入度并存入数组indegree[]中从而将“从网中删除该顶点及其与该顶点有关的所有边”的操作转换为“相关顶点的入度减1”一旦发现某个顶点的入度变为0就将其编号压入堆栈。从而将选择入度为0的顶点转化为从Stack中弹出栈顶元素所代表的顶点。 题目中顶点从1开始编号顶点Vi的编号为i第2个for循环代码主要完成求网中各个顶点的入度的功能。 在有向图中若以V2为尾的弧有V2V4>且权值为30、V2V6>且权值为50则其的邻接表表示形式是:V2→430→650^。 因此扫描顶点V2的邻接表可以将邻接于V2的所有顶点的入度加1即(1)空缺处应填入“indegree[p ->adjvex)++”或其等价形式。 第3个for循环语句主要完成求网中入度为0的顶点并保存其编号的功能。以下代码实现拓扑排序并求解各个顶点时事件的最早发生时间。 由于入度为0的顶点由栈中弹出根据变量w在后续代码中所起的作用——存放网中没有直接前驱的顶点并通过printf语句输出可知(2)空缺处应填入“Stack[top--]”或其等价形式。 然后在网中删除没有直接前驱的顶点和以该顶点为始点的所有引出边并通过内嵌的while循环语句把这些引出边对应的终点的入度减1即将邻接到顶点w的各个顶点(p->adjvex)的入度减1再判断它们是否也是入度为0的顶点。因此(3)空缺处应填入“indegree[p->adjvex]——”或其等价形式。 同时对于顶点p->adjveX而言当删除其所有引入边之后从源点出发到达它的最长路径长度也就计算出来了所以每删除一条到达顶点p->adjvex的引入边都要查看一下最长路径长度是否需要更新。因此(4)空缺处填入“ve[w]+p->weight>ve[p->adjvex]”或其等价形式。 算法程序的最后部分通过return语句返回该图的关键路径长度即汇点的最早发生时间(该AOE网的关键路径长度)。由于AOE网中汇点未必是编号最大的顶点但它必然是从栈中弹出的最后一个顶点因此(5)空缺处填入“ve[w]”或其等价形式。
    是一道要求读者掌握数据结构中拓扑排序和求关键路径问题的算法分析及设计题。本题的解答思路如下。 AOE网(Activity On Edge network,边表示活动的网)是一个带权的有向无环图,其中顶点表示事件,弧表示活动,权表示活动持续的时间。通常,AOE网可以用来估算工程的完成时间。 在AOE网中,入度为0的顶点为源点,出度为0的顶点为汇点。由于有些活动可以并行地执行,因此从源点到汇点的路径中,长度最长的路径称为关键路径(路径长度即指路径上各种活动持续时间之和)。表示事件的顶点存在最早、最晚发生时间。若以顶点V1表示源点、顶点Vn表示汇点,则汇点的最早发生时间和最晚发生时间是一致的,并且等于关键路径的长度。 设顶点Vj的最早发生时间用ve(j)表示,则ve(j)是指从源点V1到Vj的最长路径长度(时间)。这个时间决定了所有从Vj发出的弧所表示的活动能够开工的最早时间。 ve(j)计算方法为 其中,T是所有到达顶点j的弧的集合;dut(I,j>)是弧I,j>上的权值;n是网中的顶点数(即汇点的序号)。 显然,上式是一个从源点开始的递推公式。Ve(j)的计算必须在Vj的所有前驱顶点的最早发生时间全部求出后才能进行。这样必须对AOE网进行拓扑排序,然后按拓扑有序序列逐个求出各顶点事件的最早发生时间。 拓扑排序是将有向无环图中所有顶点排成一个线性序列的过程,并且该序列满足:若在有向图中从顶点Vi到Vj有一条路径,则在该线性序列中,顶点Vi必然在顶点Vj之前。可见,拓扑排序序列是由有向图中的所有顶点构成的一个线性序列,在这个序列中体现了所有顶点之间的优先关系。 对AOE网进行拓扑排序的步骤如下: ①首先在AOE网中选择一个入度为0(没有前驱)的顶点且输出它。 ②然后从网中删除该顶点,并且删除以该顶点为始点的所有引出边。 ③重复上述两个步骤,直至网中不存在入度为0的顶点为止。 在拓扑排序过程中,有可能同时存在多个入度为0的顶点,函数中用顺序栈Stack[]暂存入度为0且没有进入拓扑序列的顶点。 本试题所给出的算法首先申请了3块连续的地址空间,分别用来存放关键路径长度、网中各顶点的入度及入度为0的顶点编号,它们的首地址分别存放在指针变量Ve、indegree、Stack中。 算法主体是由3个for循环和3个while循环组成。第1个for循环,即for(j=1;j=G.n;j++){ve[j]=0; indegree[j]=O;},主要完成数组初始化的功能。 进行拓扑排序之前,应先求出网中每个顶点的入度并存入数组indegree[]中,从而将“从网中删除该顶点及其与该顶点有关的所有边”的操作转换为“相关顶点的入度减1”,一旦发现某个顶点的入度变为0,就将其编号压入堆栈。从而将选择入度为0的顶点转化为从Stack中弹出栈顶元素所代表的顶点。 题目中顶点从1开始编号,顶点Vi的编号为i,第2个for循环代码主要完成求网中各个顶点的入度的功能。 在有向图中,若以V2为尾的弧有V2,V4>且权值为30、V2,V6>且权值为50,则其的邻接表表示形式是:V2→4,30→6,50^。 因此,扫描顶点V2的邻接表可以将邻接于V2的所有顶点的入度加1,即(1)空缺处应填入“indegree[p ->adjvex)++”或其等价形式。 第3个for循环语句主要完成求网中入度为0的顶点并保存其编号的功能。以下代码实现拓扑排序并求解各个顶点时事件的最早发生时间。 由于入度为0的顶点由栈中弹出,根据变量w在后续代码中所起的作用——存放网中没有直接前驱的顶点,并通过printf语句输出,可知(2)空缺处应填入“Stack[top--]”或其等价形式。 然后,在网中删除没有直接前驱的顶点和以该顶点为始点的所有引出边,并通过内嵌的while循环语句把这些引出边对应的终点的入度减1,即将邻接到顶点w的各个顶点(p->adjvex)的入度减1,再判断它们是否也是入度为0的顶点。因此(3)空缺处应填入“indegree[p->adjvex]——”或其等价形式。 同时,对于顶点p->adjveX而言,当删除其所有引入边之后,从源点出发到达它的最长路径长度也就计算出来了,所以每删除一条到达顶点p->adjvex的引入边,都要查看一下最长路径长度是否需要更新。因此,(4)空缺处填入“ve[w]+p->weight>ve[p->adjvex]”或其等价形式。 算法程序的最后部分,通过return语句返回该图的关键路径长度,即汇点的最早发生时间(该AOE网的关键路径长度)。由于AOE网中汇点未必是编号最大的顶点,但它必然是从栈中弹出的最后一个顶点,因此(5)空缺处填入“ve[w]”或其等价形式。