您的位置:首页 > 理论基础 > 计算机网络

阅读大量网络资料总结的常用计算机公司笔试题目(2)

2011-08-03 10:05 417 查看
变量a和b,不用if、?:、switch或其它判断语句,找出最大的一个变量。
答:( ( a + b) + abs( a- b ) ) / 2
 
如何打印出当前源文件的文件名以及源文件的当前行号?
答:
cout << __FILE__ ;
cout<<__LINE__ ;
__FILE__和__LINE__是系统预定义宏,这种宏并不是在某个文件中定义的,而是由编译器定义的。
 
main主函数执行完毕后,是否可能会再执行一段代码,给出说明?
答:可以,可以用_onexit 注册一个函数,它会在main 之后执行。
 
文件中有一组整数,要求排序后输出到另一个文件中。
答:
#include<iostream>
#include<fstream>
using namespace std;
 
void Order(vector<int>&data) //bubblesort
{
    int count= data.size();
    int tag= false ; // 设置是否需要继续冒泡的标志位
    for ( inti = 0 ; i< count ; i++)
    {
       for ( intj = 0 ; j< count - i- 1 ; j++)
       {
           if ( data[j] > data[j+1])
           {
              tag = true ;
              int temp = data[j] ;
              data[j] = data[j+1] ;
              data[j+1] = temp ;
           }
       }
       if ( !tag)
           break ;
    }
}
 
void main( void )
{
    vector<int>data;
    ifstream in("c:\\data.txt");
    if ( !in)
    {
       cout<<"file error!";
       exit(1);
    }
    int temp;
    while (!in.eof())
    {
       in>>temp;
       data.push_back(temp);
    }
    in.close();//关闭输入文件流
    Order(data);
    ofstream out("c:\\result.txt");
    if ( !out)
    {
       cout<<"file error!";
       exit(1);
    }
    for ( i= 0 ; i < data.size() ; i++)
       out<<data[i]<<" ";
    out.close();//关闭输出文件流
}
 
链表题:一个链表的结点结构。
struct Node
{
    int data;
    Node *next;
};
typedef struct Node Node;
 
(1)已知链表的头结点head,写一个函数把这个链表逆序 ( Intel)
Node * ReverseList(Node *head) //链表逆序
{
    if ( head== NULL || head->next == NULL )
       return head;
    Node *p1= head ;
    Node *p2= p1->next;
    Node *p3= p2->next;
    p1->next = NULL ;
    while ( p3!= NULL )
    {
       p2->next = p1 ;
       p1 = p2 ;
       p2 = p3 ;
       p3 = p3->next ;
    }
    p2->next = p1 ;
    head = p2 ;
    return head;
}
(2)已知两个链表head1 和head2 各自有序,请把它们合并成一个链表依然有序。(保留所有结点,即便大小相同)
Node * Merge(Node *head1 , Node *head2)
{
    if ( head1== NULL)
       return head2 ;
    if ( head2== NULL)
       return head1 ;
    Node *head= NULL ;
    Node *p1= NULL;
    Node *p2= NULL;
    if ( head1->data < head2->data )
    {
       head = head1 ;
       p1 = head1->next;
       p2 = head2 ;
    }
    else
    {
       head = head2 ;
       p2 = head2->next;
       p1 = head1 ;
    }
    Node *pcurrent= head ;
    while ( p1!= NULL && p2!= NULL)
    {
       if ( p1->data <= p2->data )
       {
           pcurrent->next = p1 ;
           pcurrent = p1 ;
           p1 = p1->next ;
       }
       else
       {
           pcurrent->next = p2 ;
           pcurrent = p2 ;
           p2 = p2->next ;
       }
    }
    if ( p1!= NULL )
       pcurrent->next = p1 ;
    if ( p2!= NULL )
       pcurrent->next = p2 ;
    return head;
}
(3)已知两个链表head1 和head2 各自有序,请把它们合并成一个链表依然有序,这次要求用递归方法进行。 (Autodesk)
答案:
Node * MergeRecursive(Node *head1 , Node *head2)
{
    if ( head1== NULL )
       return head2 ;
    if ( head2== NULL)
       return head1 ;
    Node *head= NULL ;
    if ( head1->data < head2->data )
    {
       head = head1 ;
       head->next = MergeRecursive(head1->next,head2);
    }
    else
    {
       head = head2 ;
       head->next = MergeRecursive(head1,head2->next);
    }
    return head;
}
 
写一个函数找出一个整数数组中,第二大的数 (microsoft)
答:
const int MINNUMBER= -32767 ;
int find_sec_max( int data[] , int count)
{
    int maxnumber= data[0] ;
    int sec_max= MINNUMBER ;
    for ( inti = 1 ; i< count ; i++)
    {
       if ( data[i] > maxnumber)
       {
           sec_max = maxnumber;
           maxnumber = data[i] ;
       }
       else
       {
           if ( data[i] > sec_max )
              sec_max = data[i] ;
       }
    }
    return sec_max;
}
 
写一个在一个字符串(n)中寻找一个子串(m)第一个位置的函数。

答:克努特——莫里斯——普拉特操作(简称KMP算法)。KMP算法效率最好,时间复杂度是o(n+m)。

 
#include <iostream>
#include <stdlib.h>
#include <vector>
using namespace std;
 
inline void NEXT(const string& T,vector<int>&next)
{
    //按模式串生成vector,next(T.size())
    next[0]=-1;
    for(inti=1;i<T.size();i++ )
    {
       int j=next[i-1];
       while(T[i]!=T[j+1]&& j>=0)
           j=next[j] ; //递推计算
       if(T[i]==T[j+1])
next[i]=j+1;
       else
next[i]=0; //
    }
}
 
inline string::size_type COUNT_KMP(const string& S,const string& T)
{
    //利用模式串T的next函数求T在主串S中的个数count的KMP算法
    //其中T非空,
    vector<int> next(T.size());
    NEXT(T,next);
    string::size_type index,count=0;
    for(index=0;index<S.size();++index)
    {
       int pos=0;
       string::size_type iter=index;
       while(pos<T.size()&& iter<S.size())
       {
           if(S[iter]==T[pos])
           {
              ++iter;++pos;
           }
           else
           {
              if(pos==0)++iter;
              else pos=next[pos-1]+1;
           }
       }//while end
       if(pos==T.size()&&(iter-index)==T.size())++count;
    } //for end
    return count;
}
 
int main(int argc, char *argv[])
{
    string S="abaabcacabaabcacabaabcacabaabcacabaabcac";
    string T="ab";
    string::size_type count=COUNT_KMP(S,T);
    cout<<count<<endl;
    system("PAUSE");
    return 0;
}
 
如何判断一个单链表是有环的?(注意不能用标志位,最多只能用两个额外指针)
答:struct node { char val; node* next;}
bool check(const node* head) {} //return false: 无环;true: 有环
一种O(n)的办法就是(搞两个指针,一个每次递增一步,一个每次递增两步,如果有环的话两者必然重合,反之亦然):
bool check(const node* head)
{
    if(head==NULL) return false;
    node *low=head, *fast=head->next;
    while(fast!=NULL && fast->next!=NULL)
    {
       low=low->next;
       fast=fast->next->next;
       if(low==fast) return true;
    }
    return false;
}
 
嵌入式系统经常具有要求程序员去访问某特定的内存位置的特点。在某工程中,要求设置一绝对地址为x67a9的整型变量的值为xaa66。
答:这一问题测试你是否知道为了访问一绝对地址把一个整型数强制转换为一指针是合法的。典型的类似代码如下:
int *ptr;
ptr = (int *)0x67a9;
*ptr= 0xaa55;
一个较晦涩的方法是:
*(int* const)(0x67a9) = 0xaa55;
 
Typedef在C语言中频繁用以声明一个已经存在的数据类型的同义字。也可以用预处理器做类似的事。例如,思考一下下面的例子:

#define dPS struct s *
typedef struct s * tPS;
以上两种情况的意图都是要定义dPS 和 tPS 作为一个指向结构s指针。哪种方法更好呢?(如果有的话)为什么?
答:typedef更好。思考下面的例子:
dPS p1,p2;
tPS p3,p4;
第一个扩展为
struct s * p1, p2;
上面的代码定义p1为一个指向结构的指,p2为一个实际的结构,这也许不是你想要的。第二个例子正确地定义了p3 和p4 两个指针。
 
下面程序段的输出结果为?

main()

{

int x=5;

printf(“%d,%d,%dn”,x,x<<2,x>>2);

}

答: 5,20,1

 

交换变量a和b的值:#defineswap(a,b) a=a+b;b=a-b;a=a-b;

 

new、delete、malloc、free关系

答:malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。

 

delete与delete []的区别
答: delete只会调用一次析构函数,而delete[]会调用每一个成员的析构函数。在More Effective  C++中有更为详细的解释:“当delete操作符用于数组时,它为每个数组元素调用析构函数,然后调用operator delete来释放内存。”delete与New配套,delete []与new []配套。
 
OSI的七层网络结构和TCP/IP的五层结构。
答:应用层:为应用程序提供服务。
表示层:处理在两个通信系统中交换信息的表示方式。
会话层:负责维护两个结点间会话连接的建立、管理和终止,以及数据交换。
传输层:向用户提供可靠的端到端服务。UDP和TCP协议。
网络层:通过路由选择算法为分组通过通信子网选择最适当的路径,以及实现拥塞控制、网络互联等功能。数据传输单元是分组。IP地址,路由器,IP协议。
数据链路层:在物理层提供的服务基础上,数据链路层在通信的实体间建立数据链路连接,传输一帧为单位的数据包(,并采用差错控制与流量控制方法,使有差错的物理线路变成无差错的数据链路。)交换机,网桥
物理层:传输比特流。传输单元是比特。调制解调器。中继器
 
检查一个字符串是否是回文,当字符串是回文时,函数返回字符串:yes!,否则函数返回字符串:no!,并在主函数中输出。所谓回文即正向与反向的拼写都一样,例如:adgda。
char *huiwen(char *str)
{  
char *p1, *p2; int i, t=0;
p1=str;  p2= str+strlen(str)-1;
for (i=0;i<=strlen(str)/2;i++)
if (*p1++!=*p2--) {t=1; break;}
if (t== 0)
return (“yes!”);
else
return (“no!”);
}
main ()
{  
char str [50];
printf (“Input:”);scanf (“%s”, str);
printf(“%s\n ”,  huiwen(str));
}
 
以下函数creat用来建立一个带头结点的单向链表,新产生的结点总是插在链表的末尾,单向链表的头指针作为函数值返回。请填空:
struct list
{        char data;
struct list* next;
};
struct list * creat ()
{       
struct list*h, *p, *q;
char ch;
h=(struct*)malloc (sizeof(struct list));
p=q=h;
ch=getchar();
while (ch!=’?’)
{        p=(struct *)malloc (sizeof(struct list));
p->data=ch;
p->next=p;
q=p;
ch=getchar();
}
p->next=’\0’;
return h;
}
 
动态链接库(Dynamic Link Library,缩写为DLL)是一个可以被其它应用程序共享的程序模块,其中封装了一些可以被共享的例程和资源。动态链接库文件的扩展名一般是dll,也有可能是drv、sys和fon,它和可执行文件(exe)非常类似,区别在于DLL中虽然包含了可执行代码却不能单独执行,而应由Windows应用 程序直接或间接调用。

动态链接是相对于静态链接而言的。所谓静态链接是指把要调用的函数或者过程链接到可执行文件中,成为可执行文件的一部分。换句话说,函数和过程的代码就在程序的exe文件中,该文件包含了运行时所需的全部代码。当多个程序都调用相同函数时,内存中就会存在这个函数的多个拷贝,这样就浪费了宝贵的内存资源。而动态链接所调用的函数代码并没有被拷贝到应 用程序的可执行文件中去,而是仅仅在其中加入了所调用函数的描述信息(往往是一些重定位信息)。仅当应用程序被装入内存开始运行时,在Windows的管理下,才在应用程序与相应的DLL之间建立链接关系。当要执行所调用DLL中的函数时,根据链接产生的重定位信息,Windows才转去执行DLL中相应
的函数代码。

一般情况下,如果一个应用程序使用了动态链接库,Win32系统保证内存中只有DLL的一份复制品,这是通过内存映射文件实现的。DLL首先被调入Win32系统的全局堆栈,然后映射到调用这个 DLL的进程地址空间。在Win32系统中,每个进程拥有自己的32位线性地址空间,如果一个DLL被多个进程调用,每个进程都会收到该DLL的一份映 像。与16位Windows不同,在Win32中DLL可以看作是每个进程自己的代码。

动态链接库的优点:共享代码、资源和数据;隐藏实现的细节;拓展开发工具的功能 。

由于DLL是与语言无关的,因此可以创建一个DLL,被C++、VB或任何支持动态链接库的语言调用。这样如果一种语言存在不足,就可以通过访问另一种语言创建的DLL来弥补。

动态链接库的实现方法: Load-timeDynamic Linking,这种用法的前提是在编译之前已经明确知道要调用DLL中的哪几个函数,编译时在目标文件中只保留必要的链接信息,而不含DLL函数的代码;当程序执行时,利用链接信息加载DLL函数代码并在内存中将其链接入调用程序的执行空间中,其主要目的是便于代码共享。Run-time Dynamic Linking,这种方式是指在编译之前并不知道将会调用哪些DLL函数,完全是在运行过程中根据需要决定应调用哪个函数,并用LoadLibrary和GetProcAddress动态获得DLL函数的入口地址。

 

 

下面哪种排序法对12354最快。

quick sort

buble sort(正确)

merge sort

当数据规模较小时,应选择直接插入排序或冒泡排序。任何排序算法在数据量小时基本体现不出来差距。我们说快排好,是指大量随机数据下,快排效果最理想。而不是所有情况。
 
哪种结构,平均来讲,获取一个值最快。
binary tree
hash table(正确)
stack
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息