void GetNPointsInCircle(int R,int n)
{
for(int i=0;i<n;i++)
{
float x=rand(-R,R);
float y=rand(-sqrt(R*R-x*x),sqrt(R*R-x*x));
printf("%f,%f\t",x,y);
}
}
也可以通过极坐标的思路:
存放点的数据结构
typedef struct Point{
double r;
double angle;
}Point;
算法流程:
for( i=n ; i >0; i--)
产生 p.r = rand(0,R),且p.r != R
产生 p.rangle = rand(0,360) ,且 p.rangle != 360
遍历所有产生的点,若 p 已经存在,则重新生成该点.
否则将其加入到产生的点集合中.
生成第n个点,需要先遍历前n-1个点,时间复杂度为O(n),故生成n个点的时间复杂度为O(n^2).
开始把前k个元素都放到水库中,然后对之后的第i个元素,以k/i的概率替换掉这个水库中的某一个元素。
【证明】
(1)初始情况。出现在水库中的k个元素的出现概率都是一致的,都是1。这个很显然。
(2)第一步。第一步就是指,处理第k+1个元素的情况。分两种情况:元素全部都没有被替换;其中某个元素与第k+1个元素交换。
我们先看情况2:第k+1个元素被选中的概率是k/(k+1)(根据公式k/i),所以这个新元素在水库中出现的概率就一定是k/(k+1)(不管它替换掉哪个元素,反正肯定它是以这个概率出现在水库中)。下面来看水库中剩余的元素出现的概率,也就是1-P(这个元素被替换掉的概率)。水库中任意一个元素被替换掉的概率是:(k/k+1)*(1/k)=1/(k+1),意即首先要第k+1个元素被选中,然后自己在集合的k个元素中被选中。那它出现的概率就是1-1/(k+1)=k/(k+1)。可以看出来,旧元素和新元素出现的概率是相等的。
情况1:当元素全部都没有替换掉的时候,每个元素的出现概率肯定是一样的,这很显然。但具体是多少呢?就是1-P(第k+1个元素被选中)=1-k/(k+1)=1/(k+1)。
(3)归纳法:重复上面的过程,只要证明第i步到第i+1步,所有元素出现的概率是相等的即可。
3、C++ STL中vector的相关问题:
(1)、调用push_back时,其内部的内存分配是如何进行的?
(2)、调用clear时,内部是如何具体实现的?若想将其内存释放,该如何操作?
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都是用内存池来管理内存的,所以某个容器申请内存或释放内存都只是影响到内存池的剩余内存量,而不是真的把内存归还给系统。这样做一是为了避免内存碎片,二是提高了内存申请和释放的效率——不用每次都在系统内存里寻找一番。
前端服务器 / / \ \ \ hash cached主机 hash cached主机 hash cached主机 hash cached主机 hash cached主机 \ \ / / \ DB服务器 DB服务器 DB服务器
IPV6地址16字节,分4部分,一个部分4字节作为UINT。 memcached源码里我记得是有字节流哈希函数的,拿来用也许不错。
[123]、[132]、[213]、[231]、[321]、[312]
求一个组合函数。
方法1:依次从字符串中取出一个字符作为最终排列的第一个字符,对剩余字符组成的字符串生成全排列,最终结果为取出的字符和剩余子串全排列的组合。
- #include <iostream>
- #include <string>
- using namespace std;
- void permute1(string prefix, string str)
- {
- if(str.length() == 0)
- cout << prefix << endl;
- else
- {
- for(int i = 0; i < str.length(); i++)
- permute1(prefix+str[i], str.substr(0,i)+str.substr(i+1,str.length()));
- }
- }
- void permute1(string s)
- {
- permute1("",s);
- }
- int main(void)
- {
- //method1, unable to remove duplicate permutations.
- permute1("abc");
- return 0;
- }
优点:该方法易于理解,但无法移除重复的排列,如:s="ABA",会生成两个“AAB”。
方法2:利用交换的思想,具体见实例,但该方法不如方法1容易理解。
我们以三个字符abc为例来分析一下求字符串排列的过程。首先我们固定第一个字符a,求后面两个字符bc的排列。当两个字符bc的排列求好之后,我们把第一个字符a和后面的b交换,得到bac,接着我们固定第一个字符b,求后面两个字符ac的排列。现在是把c放到第一位置的时候了。记住前面我们已经把原先的第一个字符a和后面的b做了交换,为了保证这次c仍然是和原先处在第一位置的a交换,我们在拿c和第一个字符交换之前,先要把b和a交换回来。在交换b和a之后,再拿c和处在第一位置的a进行交换,得到cba。我们再次固定第一个字符c,求后面两个字符b、a的排列。
既然我们已经知道怎么求三个字符的排列,那么固定第一个字符之后求后面两个字符的排列,就是典型的递归思路了。
基于前面的分析,我们可以得到如下的参考代码:
- void Permutation(char* pStr, char* pBegin)
- {
- assert(pStr && pBegin);
- //if(!pStr || !pBegin)
- //return ;
- if(*pBegin == '\0')
- printf("%s\n",pStr);
- else
- {
- char temp;
- for(char* pCh = pBegin; *pCh != '\0'; pCh++)
- {
- if(pCh != pBegin && *pCh == *pBegin) //为避免生成重复排列,当不同位置的字符相同时不再交换
- continue;
- temp = *pCh;
- *pCh = *pBegin;
- *pBegin = temp;
- Permutation(pStr, pBegin+1);
- temp = *pCh;
- *pCh = *pBegin;
- *pBegin = temp;
- }
- }
- }
- int main(void)
- {
- char str[] = "aba";
- Permutation(str,str);
- return 0;
- }
如p([1,2,3])输出:
[1]、[2]、[3]、[1,2]、[2,3]、[1,3]、[1,2,3]
这两问可以用伪代码。