1、设rand(s,t)返回[s,t]之间的随机小数,利用该函数在一个半径为R的圆内找随机n个点,并给出时间复杂度分析。
解析:由于rand(s,t)可以返回[s,t]之间的随机小数。对于一个点,我们可以根据两个条件得到它:a.如果能够随机求出点的x和y坐标。b:已知点到圆心的距离和该连线的角度,也可以。
第一种情况:x = rand(-1,1)*R;y = rand(-1,1)*R则点(x,y)就是其中一个点。循环N次得到N个点。
第二种情况 :l = R*rand(-1,1).角度θ = arcsin(rand(-1,1));则x = l*sinθ ;y = l*cosθ
设rand(s,t)的时间复杂度为T(n),则总的时间复杂度为O(2n*T(n)) ===>O(n*T(n))
2、为分析用户行为,系统常需存储用户的一些query,但因query非常多,故系统不能全存,设系统每天只存m个query,现设计一个算法,对用户请求的query进行随机选择m个,请给一个方案,使得每个query被抽中的概率相等,并分析之,注意:不到最后一刻,并不知用户的总请求量。
解析:本体考察的是抽样算法。由于不知道总的请求量,故不能根据总数求出每条记录被抽取的概率。有一种算法是蓄水池抽样。该算法的大致思路是:对于前m条记录。百分百抽中。对于之后的记录(t = m+1,m+2,........),取随机数rand(0,t)。如果结果落在【0,m)之间,则选中该记录,并随机替换前面选中的m条记录中的某一条记录。这样在第n条记录时刻,每条记录被选中的概率为m/n,是等概率的。
该思路对应的代码如下:
#include <stdio.h>
#include <stdlib.h>
#define N 10000
#define M 20
int getRandM(int *a,int n,int *result,int m){
int i,j;
for(i = 0;i < m;i++){
result[i] = a[i];
}
for(j = i; j < n; j++){
int randN = rand()%j;
if(randN >= 0 && randN < m){
int randChange = rand()%m;
result[randChange] = a[j];
}
}
}
int main(){
int inStream[N];
for( int i = 0;i < N;i++){
inStream[i] = i;
}
int outStream[M];
getRandM(inStream,N,outStream,M);
for(int i = 0;i<M;i++){
printf("%d ",outStream[i]);
}
printf("\n");
}
3、C++ STL中vector的相关问题:
(1)、调用push_back时,其内部的内存分配是如何进行的?
(2)、调用clear时,内部是如何具体实现的?若想将其内存释放,该如何操作?
为了提高效率,实际上vector 并不是随每一个元素的插入而增长自己,而是当vector 需要增长自身时,它实际分配的空间比当前所需的空间要多一些.。也就是说它分配了一些额外的内存容量,额外容量的确切数目由具体实现定义,这个策略使容器的增长效率更高.但是你删除数据的时候,它却不会缩小。vector为了防止大量分配连续内存的开销,保持一块默认的尺寸的内存,clear只是清数据了,未清内存,因为vector的capacity容量未变化,系统维护一个的默认值。
引用总结(http://www.cnblogs.com/kex1n/archive/2011/10/19/2217342.html):
vector的工作原理是系统预先分配一块CAPACITY大小的空间,当插入的数据超过这个空间的时候,这块空间会让某种方式扩展,但是你删除数据的时候,它却不会缩小。
vector为了防止大量分配连续内存的开销,保持一块默认的尺寸的内存,clear只是清数据了,未清内存,因为vector的capacity容量未变化,系统维护一个的默认值。
有什么方法可以释放掉vector中占用的全部内存呢?
标准的解决方法如下
template < class T >
void ClearVector( vector< T >& vt )
{
vector< T > vtTemp;
veTemp.swap( vt );
}
事实上,vector根本就不管内存,它只是负责向内存管理框架acquire/release内存,内存管理框架如果发现内存不够了,就malloc,但是当vector释放资源的时候(比如destruct), stl根本就不调用free以减少内存,因为内存分配在stl的底层:stl假定如果你需要更多的资源就代表你以后也可能需要这么多资源(你的list, hashmap也是用这些内存),所以就没必要不停地malloc/free。如果是这个逻辑的话这可能是个trade-off
一般的STL内存管理器allocator都是用内存池来管理内存的,所以某个容器申请内存或释放内存都只是影响到内存池的剩余内存量,而不是真的把内存归还给系统。这样做一是为了避免内存碎片,二是提高了内存申请和释放的效率——不用每次都在系统内存里寻找一番。
二、系统设计
正常用户端每分钟最多发一个请求至服务端,服务端需做一个异常客户端行为的过滤系统,设服务器在某一刻收到客户端A的一个请求,则1分钟内的客户端任何其它请求都需要被过滤,现知每一客户端都有一个IPv6地址可作为其ID,客户端个数太多,以至于无法全部放到单台服务器的内存hash表中,现需简单设计一个系统,使用支持高效的过滤,可使用多台机器,但要求使用的机器越少越好,请将关键的设计和思想用图表和代码表现出来。
解析:该题目的考点有:hash。分布式。首先服务器接收到客户端的请求,然后根据客户端的ID值,根据某个特定的hash函数(例如ip各段和 mod n),将该客户的请求转向某一台子服务器,由该服务器代理该客户端的请求并作相应的过滤。其他客户的请求也与之相同,需要注意的是考虑各个子服务器的负载均衡,使得几乎每台子服务器处理的客户机的数量是接近平均分配的。如果还要处理客户的其他请求,且考虑到子服务器可能宕机的情况,需要做分布式一致hash,使得子服务器宕机时,不会有太多的客户请求受到影响。
分布式一致hash的原理图:
关于分布式一致hash的详细介绍,可以参考这篇文章:
http://blog.csdn.net/sparkliang/article/details/5279393
三、求一个全排列函数:
如p([1,2,3])输出:
[123]、[132]、[213]、[231]、[321]、[323]
求一个组合函数
如p([1,2,3])输出:
[1]、[2]、[3]、[1,2]、[2,3]、[1,3]、[1,2,3]
这两问可以用伪代码。
解析:关于求排列组合的问题,已经做过相关总结。本blog的传送地址:http://blog.csdn.net/ohmygirl/article/details/7859497。
为了方便,这里再次给出代码:
//全排列 问题的回溯解法
void permutation(int *a, int n,int k){
if(n==k){
printf("{");
for(int i = 0;i<n;i++){
printf("%d ",a[i]);
}
printf("}\n");
return ;
}
for(int i = k;i<n;i++){
swap(&a[i],&a[k]);
permutation(a,n,k+1);
swap(&a[i],&a[k]);
}
}
//组合问题的位向量解法
void getSubSet(int *a,int *b,int n,int k){
if(k==n){
for(int i = 0;i < n;i++){
if(i == 0){
printf("{ ");
}else if(i==(n-1)){
printf(" }\n");
}
if(b[i]){
printf("%d, ",a[i]);
}
}
return ;
}
b[k] = 1;
getSubSet(a,b,n,k+1);
b[k] = 0;
getSubSet(a,b,n,k+1);
}