static public int CountPrimes(int n)
{
//buf 存放所有数据,默认全部为素数
bool[] buf = new bool[n];

//primeBuf 存放素数,这是有序的,从小到大。
int[] primeBuf = new int[n];

//标记已存放多少个素数
int primeSize = 0;


//从第一个素数开始
for (int i = 2; i < n; i++)
{
//识别为素数
if(!buf[i])
{
//将素数存放进数组中
primeBuf[primeSize] = i;
//标记数增加
primeSize++;
}

//遍历存放素数的数组
//j 少于 primeBuf下标的最大值 且不能超出 用来存放所有数据的 buf 的范围
for (int j = 0; j < primeSize && i*primeBuf[j] {
//数字“i * primeBuf[j]”为合数,因为能被素数i整除
buf[i * primeBuf[j]] = true;

//下面这段是重点:防止冗余(去掉重复部分)。如12 可由2 * 6 或 3 * 4 所得 ,我们只取最小素因子即可
//假设整数X为另一个乘数
//由 i = primeBuf[j] * X
// i * primeBuf[j+1] = primeBuf[j] * (X * primeBuf[j+1]) 如12 = 2*6 = 2*2*3 下面我们break排除了2*2*3
// (X * primeBuf[j+1])是一个正整数
// 所以,若i能被primeBuf整除
// i * primeBuf[j+1] 也能被 primeBuf[j] 整除
if (i%primeBuf[j]==0)
{
break;
}
}
}

return primeSize;
}