201705程序员下午真题

第 1 题

阅读下列说明和流程图,填补流程图中的空缺,将解答填入答题纸的对应栏内。 
【说明】 
设有二维整数数组(矩阵)A[1:m,1:n],其每行元素从左到右是递增的,每列元素从上到下是递增的。以下流程图旨在该矩阵中需找与给定整数X相等的数。如果找不到则输出“false”;只要找到一个(可能有多个)就输出“True”以及该元素的下标i和j(注意数组元素的下标从1开始)。
例如,在如下矩阵中查找整数8,则输出为:True,4,1
      2    4    6     9
      4    5    9    10
      6    7   10   12
      8    9   11   13
流程图中采用的算法如下:从矩阵的右上角元素开始,按照一定的路线逐个取元素与给定整数X进行比较(必要时向左走一步或向下走一步取下一个元素),直到找到相等的数或超出矩阵范围(找不到)。

【流程图】


【问题】该算法的时间复杂数是() 
供选择答案:A.O(1)  B.O(m+n)  C.O(m*n)   D,O(m²+n²) **答案与解析** - 试题难度:较难 - 知识点:流程图>流程图 - 试题答案:(1)n
(2)j-1→j
(3)i+1→i
(4)j
(5)B
- 试题解析:读题,可以看出元素查找的过程为从右上角开始,往左或者往下进行查找。因此,初始值i=1,j=n。
如果查找值小于右上角值,则往左移动一列再进行比较。所以,第二空填j-1→j
接下来是判断什么时候跳出循环。此时,终止循环的条件是:j=0,也就是其从最右端移到了最左端。
再看X<A[i,j]不成立时,执行流程的右支。此时,也就是说这一行的A[i,j]小于查找值,因此需往下移动一行。所以第三空填i+1→i
首先要理解这个算法的逻辑:当遇到一个数比要查找的数大时,那么是向其左侧移动一列;当遇到一个数比要查找的数小时,那么是向下移动一行。假设需要查找的位于左下角,那么进行比较的次数最多是(m+n)次(行列数之和)。
Ai,j-1        Ai,j           Ai,j+1
Ai+1,j-1    Ai+1,j        Ai+1,j+1

详细的查找过程如下:假设首先右上角元素比要查找的数大时,左侧移动一列,如果还小,再向左移动,假设移动了j列,遇到了一个数Ai,j比X要小,那么说明这个数对应行左边的数都比这个数要小,所以这一行就不需要比较了。就往下移动一行,移动到Ai+1,j,对于这个数该行右边的数是不需要再次进行比较的(这是因为前面有Ai,j+1是大于查找的值的,而Ai+1,j+1> Ai,j+1,所以其右侧的值都不用再比较了)。然后如果Ai+1,j仍然小于要查找的值,那么同样,这个数对应行左边的数都比这个数要小,所以这一行就不需要比较了。因此就要向下移动一行,如果还小,继续向下移动一行,如果大于再往左侧移动一列,依次比较,直到查找成功。所以比较的次数最多是行列数之和。 ### 第 2 题    阅读下列说明和C函数,填补函数中的空缺,将解答填入答案纸的对应栏目内。
【说明】
      函数isLegal(char*ipaddr)的功能是判断以点分十进制数表示的IPV4地址是否合法。参数ipadddr 给出表示IPV4地址的字符串的首地址,串中仅含数字字符和“.”。若IPV4地址合法则返回1,否则返回0。判定为合法的条件是:每个十进制数的值位于整数区间[0,255],两个相邻的树之间用“.”分隔,共4个数、3个“.”。例如,192.168.0.15、1.0.0.1是合法的,192.168.1.256、1.1..1是不合法的。

【函数】
int isLegal (char*ipaddr)
{
    int flag;
    int curVal;                    //curVal 表示分析出的一个十进制数
    int decNum=0,dotNum=0;       //decNum 用于记录十进制数的个数
                            //dotNum 用户记录点的个数
    char*p=( 1  );
 
    for(;*p;p++) {
       curVal=0;flag=0
       while (isdigit(*p)){        //判断是否为数字字符
           curVal=( 2  )+*p-’0’;
           ( 3  )
           flag=1;
        }
        if(curVal>255){
           return 0;
        }
        if (flag){    
       (  4   )
       }
        if(*p=’.’){
              dotNum++;
        } 
    }
    if ((  5)  ){
        return 1;
    }
    return 0;
}

答案与解析

  • 试题难度:较难
  • 知识点:C程序设计>C程序设计
  • 试题答案:
    (1)ipaddr
    (2)curval*10
    (3)p++
    (4)decNum++
    (5)decNum==4 && dotNum==3
  • 试题解析:此题判断IPV4地址是否合法,主要是判断其每个十进制数的大小和总个数以及“.”个数来进行判别。
    首先用isdigital函数判断是否为十进制数,是则保留值。指针移到地址的下一个字符。
    每找到一个十进制数都需要和前一次找到的值进行组合,即前一次的结果要乘以10。
    每找完一个完整数字和“.”都需要记录,所以要有decNum++和dotNum++。
    最后,如果IP地址正确,则返回1。即:decNum=4和dotNum=3时成立。

第 3 题

阅读下列说明和C函数,填补C函数中的空缺,将解答填入答案纸的对应栏目内。
【说明】
字符串是程序中常见的一种处理对象,在字符串中进行子串的定位、插入和删除是常见的运算。
设存储字符串时不设置结束标志,而是另行说明串的长度,因此串类型定义如下:
typedef struct ﹛
     Char *str;      //字符串存储空间的起始地址
     int length;     //字符串长
     int capacity;    //存储空间的容量
﹜SString;

【函数1说明】
     函数indexStr(S,T,pos)的功能是:在S 所表示的字符串中,从下标pos开始查找T所表示字符串首次出现的位置。方法是:第一趟从S中下标为pos、T中下标为0的字符开始,从左往右逐个对于来比较S和T的字符,直到遇到不同的字符或者到达T的末尾。若到达T的末尾,则本趟匹配的起始下标pos为T出现的位置,结束查找;若遇到了不同的字符,则本趟匹配失效。下一趟从S中下标pos+1处的字符开始,重复以上过程。若在S中找到T,则返回其首次出现的位置,否则返回-1。
   例如,若S中的字符串为”students ents”,T中的字符串为”ent",pos=0,则T在S中首次出现的位置为4。
【C函数1】
   int index Str(SString S ,SString T,int pos)
  {
     int i,j;
     if(S.length<1||T.length<1||S.length<pos+T.length-1)
         return-1;
     for(i=pos,j=0;i<S.length &&j<T.length;){
          if (S.str[i]==T.str[j]){
             i++;j++;
          }
          else{
               i=(  1   );j=0
          }
      }
     if (   2   )return i -T.length;
         return -1;
}
【函数2说明】

函数 eraseStr(S,T}的功能是删除字符串S中所有与T相同的子串,其处理过程为:首先从字符串 S 的第一个字符(下标为0)开始查找子串T,若找到〈得到子串在S中的起始位置),则将串 S 中子串T之后的所有字符向前移动,将子串T覆盖,从而将其删除,然后重新开始查找下一个子串T,若找到就用后面的字符序列进行覆盖,重复上述过程,直到将S中所有的子串T删除。
例如,若字符串 S为 “12ab345abab678”、T为“ab”。第一次找到“ab”时(位置为2),将“345abab678”前移,S 中的串改为“12345abab678” ,第二次找到“ab”时(位置为 5);将“ab678”前移,S中的串改为“12345ab678”,第三次找到“ab”时(位置为5);将“678”前移 ,S中的串改为“12345678 ”。

【C函数2】
Void eraseStr(SString*S,SStringT)

    int i;
    int pos;
 
    if (S->length<1||T.length<1||S->length<T.length)
       return;
    
    pos=0;
    for(;;)﹛
        //调用indexStr在S所表示串的pos开始查找T的位置
        pos=indexStr(  3   );
        if(pos=-1)                         //S所表示串中不存在子串T
          return;
        for(i=pos+T.length;i<S->length;i++)   //通过覆盖来删除子串T
             S->str[(  4  )]=S->str[i];
        S->length=(   5   );                       //更新S所表示串的长度
     ﹜
  ﹜

答案与解析

  • 试题难度:较难
  • 知识点:C程序设计>C程序设计
  • 试题答案:
    (1)i-j+1
    (2)j==T.length
    (3)*S,T,pos
    (4)i-T.length
    (5)S ->length -T.length
  • 试题解析:函数1为字符串匹配,算法为:先判断字符串S和T的长度,如果为空则不用循环,另外,如果字符串S的长度<字符串T的长度,那字符串S中也不能含有字符串T,也无需进行匹配。
    那当上述情况都不存在时,即需要进行循环。即从S的第一个字符开始,与T的第一个字符进行比较,如果相等,则S的第二个字符和T的第二字符进行比较,再相等就再往后移动一位进行比较,依次直到字符串T的结尾,也就是说j=T.length(数组的下标从0开始,最后一个是T.length-1,结束循环是j=T.length)。
    当某一个字符与T的字符不相等时,那么字符串S就应从下一个字符开始比较,此时i=i-j+1,(如果前面有匹配成功的话,i的值已经增加了j位,因此需要重新回到之前比较的位置的后一个字符进行比较,再次进行与T的第一个字符进行比较,此时j恢复初始值,j=0。
    函数2为字符串的删除运算。首先,要调用函数 indexStr,需要三个参数,字符串S、字符串T和pos。从函数2的调用Void eraseStr(SStringS,SStringT)可以看到,此处字符串S为指针变量,因此字符串前需使用
    然后删除的字符串的位置为删除初始点的位置到其位置点+字符串T的长度,并将后面的字符串前移。而删除T字符串后,字符串S的总长度变化,需减去字符串T的长度。

第 4 题

阅读以下说明和C 函数,填补函数中的空缺,将解答填入答题纸的对应栏内。
【说明】
简单队列是符合先进先出规则的数据结构,下面用不含有头结点的单向循环链表表示简单队列。
函数EnQueue(Queue Q,KeyType new_elem) 的功能是将元素new_elem加入队尾。
函数DnQueue(Queue
Q,KeyType *elem)的功能使将非空队列的队头元素出队(从队列中删除),并通过参数带回刚出队的元素。
用单向循环链表表示的队列如图 4-1 所示。

图4-1 单向循环链表表示的队列示意图

队列及链表结点等相关类型定义如下:
enum {ERROR, OK};
typedef int KeyType;
 
typedef struct    QNode{
      KeyType   data;
      Struct QNodenext;
}QNode,
LinkQueue;
 
Typedef struct{
      int  size;
      Link:Queue rear;
}Queue;
 
【C函数】
 
int EnQueue(QueueQ,KeyType new_elem)
{   //元素new_elem 入队列
     QNode
p;
     p=(QNode)malloc(sizeof(QNode));
     if(!p)
        return ERROR;
    p->data=new_elem;
    if(Q->rear){
        p->next=Q->rear->next;
        (   1   );
     }
     else
         p->next=p;
     ﹙  2  ﹚;
     Q->size++;
    return OK;
}
 
int  DeQueue(Queue
Q,KeyTypeelem)
{   //出队列
     QNode
p;
     If(0==Q->size)           //是空队列
         Return ERROR;
     p=(  3  );                    //令p指向队头元素结点
     *elem =p->data;
     Q->rear->next=(  4   );         //将队列元素结点从链表中去除
     if((  5  ))                //被删除的队头结点是队列中唯一结点
        Q->rear=NULL;       //变成空队列
     free(p);
     Q->size--;
     return OK;
}

答案与解析

  • 试题难度:较难
  • 知识点:C程序设计>C程序设计
  • 试题答案:
    (1)Q→rear→next=p
    (2)Q→rear=p
    (3)Q→rear→next
    (4)p→next
    (5)Q→rear==p 或 Q→rear→next==p或p→next==p 或 Q→size==1 
  • 试题解析:本题考查C语言指针与链表的知识,为入队列和删除队列问题。
    对于入队列,那么当队列Q不为空时,P的队尾t要指向原Q的队尾指向的元素,即:P->next=Q->rear->next,Q的队尾要指向p,即:Q→rear→next=p。当队列Q为空时,插入p元素,则p的队尾指向p自身,即:p→next=p,且整个队列Q的队尾也是p,即:Q→rear=p。
    对于队列删除元素p,先判断Q是否为空,为空队列则返回 ERROR;
     If(0==q->size)           //是空队列
             Return ERROR;
    另p指向队头元素结点,队头元素结点可用Q→rear→next表示。此时,p转化为头结点,p出列,则需要Q的队尾指向p的下一个元素,因此第4空填:p→next。
    最后,判断被删除的队头结点是否是队列中的唯一结点,可采用:Q→rear==p 或 Q→rear→next==p或p→next==p或 Q→size==1等表示方法。

第 5 题

阅读以下说明和 Java程序,填补代码中的空缺,将解答填入答题纸的对应栏内。
【说明】
以下Java代码实现一个简单客户关系管理系统(CRM)中通过工厂(CustomerFactory )对象来创建客户(Customer)对象的功能。客户分为创建成功的客户(RealCustomer)和空客户 (NullCustomer)。空客户对象是当不满足特定条件时创建或获取的对象。类间关系如图 5-1 所示。

图5-1 类图

abstract class Customer{
    protected String name;
    ( 1 ) boolean isNil();
    ( 2 ) String getName();
}
class RealCustomer ( 3 ) Customer{
    public RealCustomer(String name){ this.name=name; }
    public String getName(){ return name ; }
    public boolean isNil() { return false; }
}

class NullCustomer ( 4 ) Customer{
    public String getName(){ return "Not Available in Customer Database"; }
    public boolean isNil() { return true; }
}
class CustomerFactory {
    public String[] names = {"Rob","Joe","Julie"};
    public Customer getCustomer(String name) {
        for (int i = 0 ; i < names.length ; i++) {
            if (names[i].( 5 ) ){
                  return new RealCustomer(name);
            }
        }
     return ( 6 );
    }
}
public class CRM {
    public void getCustomer(){
         CustomerFactory ( 7 ) ;
         Customer customer1 = cf.getCustomer( "Rob" );
         Customer customer2 = cf.getCustomer( "Bob" );
         Customer customer3 = cf.getCustomer( "Julie" );
         Customer customer4 = cf.getCustomer( "Laura" );
         System.out.println( "Customers" );
         System.out.println( customer1.getName() );
         System.out.println( customer2.getName() );
         System.out.println( customer3.getName() );
         System.out.println( customer4.getName() );
   }
    public static void main (String[] args){
         CRM crm =new CRM();
         crm.getCustomer();
      }
}
/*程序输出为:
Customers
Rob
Not Available in Customer Database
Julie
Not Available in Customer Database
*/

答案与解析

  • 试题难度:较难
  • 知识点:Java程序设计>Java程序设计案例
  • 试题答案:

    1)abstract
    2)abstract
    3)extends
    4)extends
    5)equals(name)
    6)new NullCustomer()
    7)cf=new CustomerFactory();

  • 试题解析:

    本题考查Java程序设计客户关系管理系统。
    1)abstract 定义抽象方法
    2)abstract
    3)extends 继承Customer类
    4)extends
    5)equals(name) 判断名字是否在数组集合内
    6)new NullCustomer() 当不满足条件时创建一个空对象
    7)cf=new CustomerFactory(); 实例化对象cf

第 6 题

阅读下列说明和C++代码,填补代码中的空缺,将解答填入答题纸的对应栏内。
【说明】
     以下C++代码实现一个简单客户关系管理系统(CRM)中通过工厂(Customerfactory)对象来创建客户(Customer)对象的功能。客户分为创建成功的客户(realCustomer)和空客户(NullCustomer)。空客户对象是当不满足特定条件时创建或获取的对象。类间关系如图6-1所示。


图6-1

【C++代码】

include<iostream>

include<string>

using namespace std;
 
class Customer{
protected:
     string name;
public:
   (   1   ) bool isNil()=0;
   (   2   ) string getName()=0;
};
 
class RealCustomer (   3   )
Public:
     realCustomer(string name){this->name=name;﹜
     bool isNil(){ return false;  ﹜  
     string getName(){ return name;  ﹜
};
class NullCustomer (    4   ) {
public:
     bool isNil(){  return true; ﹜
     string getName(){ return "Not Available in Customer Database"; ﹜
};
 
class Customerfactory{
public:
    string names[3]={"rob", "Joe","Julie"};
public:
    CustomergetCustomer(string name){
       for (int i=0;i<3;i++){
           if (names[i].(   5   ) ){
               return new realCustomer(name);
            }
        }
        return (   6   );
    }
};
 
class CRM{
public:
    void getCustomer(){
        Customerfactory
(   7   );
        Customercustomer1=cf->getCustomer("Rob");
        Customer
customer2=cf->getCustomer("Bob");
        Customercustomer3=cf->getCustomer("Julie");
        Customer
customer4=cf->getCustomer("Laura");
 
        cout<<"Customers"<<endl;
        cout<<Customer1->getName()<<endl;  delete customer1;
        cout<<Customer2->getName()<<endl;  delete customer2;
        cout<<Customer3->getName()<<endl;  delete customer3;
        cout<<Customer4->getName()<<endl;  delete customer4;
        delete cf;
     }
};
 int main(){
      CRMcrs=new CRM();
      crs->getCustomer();
      delete crs;
      return 0;
}
 
/
程序输出为:
Customers
rob
Not Available in Customer Database
Julie
Not Available in Customer Database
*/

答案与解析

  • 试题难度:较难
  • 知识点:C++程序设计>C++程序设计
  • 试题答案:

    1)virtual
    2)virtual
    3):public Customer
    4):public Customer
    5)compare(name)==0
    6)new Null Customer()
    7)cf=New CustomerFactory()

  • 试题解析:

    本题考查使用C++代码实现实际问题。
    在C++中,动态绑定是通过虚函数来实现的。此题中用到了虚函数,所以要在成员函数原型前加一个关键字virtual。
    类RealCustomer和类NullCustomer是类Customer的派生类,因此3、4空都填public Customer。
    进行对比数据库中的人名compare(name)==0
    第6空与前面语句是相反的,一个是返回new RealCustomer(name),那么此处应填:new Null Customer()
    第7空,用工厂创建对象,cf=New CustomerFactory();

results matching ""

    No results matching ""