笔试/面试题

1、编写strcpy函数

char *strcpy(char *strDestination, const char *strSource)
{
  assert(strDestination!=NULL && strSource!=NULL);
  char *strD=strDestination;
  while ((*strDestination++=*strSource++)!='\0');
  return strD;
}

2、进程间通信的方法:

# 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
# 有名管道 (named pipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
# 消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
# 信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
# 套接字( socket ) : 套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。

3、进程线程同步的方法:

1临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。   
2互斥量:为协调共同对一个共享资源的单独访问而设计的。   
3信号量:为控制一个具有有限数量用户资源而设计。   
4事件:用来通知线程有一些事件已发生,从而启动后继任务的开始。

 4、引用和指针的区别:

1、指针是一个实体,而引用仅是个别名;
2、引用只能在定义时被初始化一次,之后不可变;指针可变;
3、引用不能为空,指针可以为空;
4、“sizeof引用”得到的是所指向的变量(对象)的大小,而“sizeof指针”得到的是指针本身的大小;
5、指针和引用的自增(++)运算意义不一样;
6、引用是类型安全的,而指针不是(引用比指针多了类型检查) 

5、const有什么作用:

第一,限定一个只读变量(不是常量)。如const double PI = 3.14
第二,限定函数参数,如,
void function(const char *p) //函数只能读取不能改变p的值

C++里入了这两个以外还有一个,就是类的const成员函数,
class A
{
public: void function(int arg) const;
}
这个const是限定这个成员函数不能改变类数据成员的值,就把this指针限定为const this。

6、static的作用:

7、

http://blog.csdn.net/lock0812/article/details/2644109

8、判断单链表是否有环

一、判断链表是否存在环,办法为:
设置两个指针(fast, slow),初始值都指向头,slow每次前进一步,fast每次前进二步,如果链表存在环,则fast必定先进入环,而slow后进入环,两个指针必定相遇。(当然,fast先行头到尾部为NULL,则为无环链表)程序如下:
bool IsExitsLoop(slist *head) 
{    
  slist *slow = head;
  slist *fast = head;     
  while ( fast &&fast->next )    
   {        
    slow = slow->next;        
    fast = fast->next->next;         
    if ( slow ==fast ) 
    break;    
  }    
  return !(fast == NULL || fast->next == NULL);
}

二、找到环的入口点

当fast若与slow相遇时,slow肯定没有走遍历完链表,见注释(1)而fast已经在环内循环了n圈(1<=n)。假设slow走了s步,则fast走了2s步(fast步数还等于s 加上在环上多转的n圈),设环长为r,则:
 2s = s + nr    s= nr
设整个链表长L,入口环与相遇点距离为x,起点到环入口点的距离为a。   a + x = nr   a + x = (n – 1)r +r = (n-1)r + L - a   a = (n-1)r + (L – a – x)
(L – a – x)为相遇点到环入口点的距离,由此可知,从链表头到环入口点等于(n-1)循环内环+相遇点到环入口点,于是我们从链表头、与相遇点分别设一个指针,每次各走一步,两个指针必定相遇,且相遇第一点为环入口点。程序描述如下:
slist* FindLoopPort(slist *head) 
{    
  slist *slow = head, *fast = head;    
  while ( fast &&fast->next )    
  {        
    slow = slow->next;        
    fast = fast->next->next;         
    if ( slow ==fast ) 
    break;    
  }    
  if (fast == NULL || fast->next == NULL)        
  return NULL;    
slow =head;    
  while (slow != fast)    
  {         
    slow = slow->next;         
    fast = fast->next;    
  }    
  return slow;
}


另一个方法
slist* FindLoopPort(slist *head) 
{    
  slist *p1,p2;
  p1=p2=head;
  while(p1)
  {
    p1=p1->next;
    p2=head;
    while(p2)
    {
      if(p2==p1->next && p2!=p1)
      {
        return p2;
      }
      p2=p2->next;
    }
  }
  return NULL;
}
 

扩展问题:

判断两个单链表是否相交,如果相交,给出相交的第一个点(两个链表都不存在环)。

比较好的方法有两个:

一、将其中一个链表首尾相连,检测另外一个链表是否存在环,如果存在,则两个链表相交,而检测出来的依赖环入口即为相交的第一个点。

二、如果两个链表相交,那个两个链表从相交点到链表结束都是相同的节点,我们可以先遍历一个链表,直到尾部,再遍历另外一个链表,如果也可以走到同样的结尾点,则两个链表相交。

这时我们记下两个链表length,再遍历一次,长链表节点先出发前进(lengthMax-lengthMin)步,之后两个链表同时前进,每次一步,相遇的第一点即为两个链表相交的第一个点。

注释1

设r为环长,则fast指针r/2内可以跑完一圈,若r为奇数,刚r步内fast会遍历循环内所有点.刚r内一定会跟slow相遇.若r为偶数,r/2步内可令fast跟slow的最近距离为2或1(f追赶s).若为2,则

          fast+2=slow

   所以下一步时slow的位置是slow+1;而fast则为fast+2;

   再下步slow+2,fast+4;

   因为之前fast+2=slow,所以

         slow-2+4=slow+2

   又因为最近距离为1时,只要两指针各走一步便相遇.

   所以两指针相遇.最大步数为s<=r/2+2(r>=4)

9、全排列

http://blog.csdn.net/morewindows/article/details/7370155

 

 

原文地址:https://www.cnblogs.com/quansir/p/2752847.html