以32位无符号整型为例。

1: int Count(unsigned x) {
2: x = x - ((x >> 1) & 0x55555555);
3: x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
4: x = (x + (x >> 4)) & 0x0F0F0F0F;
5: x = x + (x >> 8);
6: x = x + (x >> 16);
7: return x & 0x0000003F;
8: }

这里用的是二分法,两两一组相加,之后四个四个一组相加,接着八个八个,最后就得到各位之和了。

还有一个更巧妙的HAKMEM算法

1: int Count(unsigned x) {
2: unsigned n;
3:
4: n = (x >> 1) & 033333333333;
5: x = x - n;
6: n = (n >> 1) & 033333333333;
7: x = x - n;
8: x = (x + (x >> 3)) & 030707070707;
9: x = modu(x, 63);
10: return x;
11: }

首先是将二进制各位三个一组,求出每组中1的个数,然后相邻两组归并,得到六个一组的1的个数,最后很巧妙的用除63取余得到了结果。

因为2^6 = 64,也就是说 x_0 + x_1 * 64 + x_2 * 64 * 64 = x_0 + x_1 + x_2 (mod 63),这里的等号表示同余。

posted @ 2011-09-05 19:40 CSDN大笨狼 阅读(31) 评论(0) 编辑


主定理(master theorem)
 
T(n)=aT(n/b)+cn

a<b, T(n)=O(n);
a=b, T(n)=O(nlogn);
a>b, T(n)=O(nlogba)
//b为底 logba 为n的次数

你懂得,你不懂,我也没办法。

posted @ 2011-09-02 11:18 CSDN大笨狼 阅读(37) 评论(0) 编辑

--create table Oders (OdersID int  identity(1,1) primary key, UsersID int)
--create table OderIterms( OdersID int,ProductID int)
--create table Product(ProductID int identity(1,1) primary key , ProductName varchar(50) )
--create table Users(UsersID  int  identity(1,1) primary key,gender bit,age int )
--declare @i int
--set @i=0
----
--while @i< 10000
--begin
--insert Users select case when rand()>0.5 then 1 else 0 end  as gender,CAST( rand()*100 as int) as age
--set @i=@i+1
--end
----
----
--set @i=0
--while @i<10*10000
--begin
--insert Product select '产品'+ CAST( rand()*100 as varchar) as ProductName
--set @i=@i+1
--end
----
----
--set @i=0
--while @i<100*10000
--begin
--insert Oders select top 1 UsersID   as UsersID from Users order by NEWID()
--set @i=@i+1
--end
--
declare @i int
set @i=0
declare @maxUser int
select @maxUser= MAX(UsersID) from Users
 select CAST( RAND()*@maxUser as int)
declare @minUser int
select @minUser=Min(UsersID) from Users

declare @maxOders int
select @maxOders= MAX(OdersID) from Oders

declare @minOders int
select @minOders= Min(OdersID) from Oders

while @i<1000*10000
begin
insert OderIterms select
 @minUser+ CAST(RAND()*@maxUser as int) as OdersID ,
@minOders + CAST(RAND()*@maxOders as int) as OdersID
set @i=@i+1
end

--select COUNT(*) from dbo.OderIterms
--delete from dbo.Users
--delete from dbo.OderIterms
--delete from dbo.Oders
--delete from  dbo.Product 
--select COUNT(*) from  Product
--十万商品
declare @PID int
set @PID=12345
select top 10  A.productID,COUNT(A.productID) 数量
from  dbo.OderIterms A
inner join dbo.Oders B
on A.productID!=@PID
and B.UsersID in
(select C.Usersid from  dbo.Oders C inner join OderIterms D
on C.OdersID=D.OdersID where D.productID=@PID)
group by A.productID
order by 数量 desc


 
select   A.productID productID ,B.UsersID UsersID into #tb  from
OderIterms A  inner join Oders B
on A.OdersID=B.OdersID

select top 1 A.productID,B.productID,count(*) from #tb A inner join #tb B
on A.UsersID=B.UsersID and A.productID>B.productID
group by A.productID,B.productID
order by count(*)
 
  
 
 

posted @ 2011-07-22 01:14 CSDN大笨狼 阅读(46) 评论(0) 编辑

O(1)的时间,根据前一组合枚举下一组合
 

using System;

namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
combian(
5, 3);
Console.Read();
}
static void combian(int n, int k)
{
if (!(n >= k && k > 0 && n < 30))
{
return;
}
int ik = (1 << k) - 1;
while (ik != 0)
{
// 输出组合
for (int i = 0; i < n; ++i)
{
if ((ik & (1 << i)) != 0)
{
Console.Write(i);
}
}
//输出空行分隔之
Console.WriteLine();
ik
= next_combination(n, ik);
}



}
static int next_combination(int n, int k)
{
int ret, b = k & -k, t = (k + b);
ret
= (((t ^ k) >> 2) / b) | t;
if ((1 << ret) < k)
{
return 0;
}
else
{
return ret;
}
}


}
}


根据k,得到比k大,并且二进制下有相同个数的’1′,而且是当中最小的数
比如把1011,变成1101
首先,因为1的个数要相同,并且比原数要大,那么,先要找出右起第一次出现1的位置,对这个数加上1,然后在最右边补上少了的1就可以了。
找出右起第一次出现1的位置的算法很简单,就是(n & -n),这里的b就是得到这个位置,t就是加了以后的结果,这个应该不难明白,关键的,是后面的计算。

后面的计算,主要是针对右边补1的个数,细心想一下,你就知道,要补的1的个数,等于原数右起第一个1向左数,连续的1的个数减1,然后,t^k是什么意思呢?这个就非常有技巧了,它的效果其实和x ^ (x – 1)很类似。

而x ^ (x – 1)的作用,是保留右起第一个“1”,同时把右起第1个“1”右边全部变为“1”,类似1101000 -> 1111
逆向过来说,就是k = 1100111,对它 +1后,得到t = 1101000,用这个运算可以得到1111,位数和少掉的1成常数差的关系
事实上,这样我们变相地得到少掉的1的个数(这个例子中是少了两个1),我们只需要对运算结果中1的个数减2即可,用>>2解决之

不过,在当k最右边不是1,有若干个0的时候,前一个步骤得到的数的最右边,就会有同样多的0,如何去掉这些0?
这时候,我们最初计算的b,即(n & -n)就太有作用了,只要除以这个b,0就没有了,最后,就是最右边应该补上的值,和前面的t求和,或者求并均可。

输出结果是:
0 1 2
0 1 3
0 2 3
1 2 3
0 1 4
0 2 4
1 2 4
0 3 4
1 3 4
2 3 4
posted @ 2011-07-20 08:00 CSDN大笨狼 阅读(129) 评论(0) 编辑
微软的面试题,我做过。鸽巢原理。
using System;
using System.Linq;
using System.Collections.Generic;
namespace ConsoleApplication1
{
  class Program
  {
  static Random Rand = new Random();

  static void Main(string[] args)
  {
  int count = 10000;
  List<int> Input = new List<int>();
  for (int i = 0; i < count; i++)
  {
  Input.Add(Rand.Next(int.MinValue, int.MaxValue));
  }

  ulong re = PigeonNest(Input, ulong.MaxValue);
  Console.WriteLine(re);
  Console.WriteLine("-------------");
  Console.Read();
  }

  //鸽巢原理。
  static ulong PigeonNest(List<int> List, ulong MinResult)
  {
  switch (List.Count)
  {
  case 0:
  case 1:
  return MinResult;
  case 2:
  return ABS(List[0], List[1]);
  default:
  break;
  }
  int min = List.Min();
  //确定桶的大小。
  int width = (int)Math.Ceiling((double)(List.Max() - min) / List.Count);
  //不可能比1还小了。
  if (width == 1) { return 1ul; }
  //把数据丢到桶里。
  Dictionary<int, NumbersInfo> EachNestNum = new Dictionary<int, NumbersInfo>();
  foreach (int n in List)
  {
  int Key = Convert.ToInt32(Math.Ceiling((double)(n - min) / width));
  if (!EachNestNum.ContainsKey(Key))
  {
  EachNestNum.Add(Key, new NumbersInfo(Key));
  }
  EachNestNum[Key].Add(n);
  }
  //找到所有桶里,和相邻两桶的最大最小值距离,三个数中最近的。
  foreach (int Key in EachNestNum.Keys)
  {
  MinResult = Min(MinResult, EachNestNum[Key].minresult(EachNestNum, MinResult));
  }
  return MinResult;
  }
  class NumbersInfo
  {
  public NumbersInfo(int k)
  { key = k; }
  private List<int> List = new List<int>();
  private int key;
  public int max = int.MinValue;
  public int min = int.MaxValue;
  public int count { get { return List.Count; } }
  public ulong minresult(Dictionary<int, NumbersInfo> EachNestNum, ulong re)
  {
  //在三个数中选最小的。  
  //当命中数大于1的时候,递归这个过程。由于迅速收敛,故复杂度忽略不计。
  if (List.Count > 1)
  {
  re = PigeonNest(List, re);
  }
  if (EachNestNum.ContainsKey(key - 1))
  {
  re = Min(ABS(EachNestNum[key].min, EachNestNum[key - 1].max), re);
  }
  if (EachNestNum.ContainsKey(key + 1))
  {
  re = Min(ABS(EachNestNum[key].max, EachNestNum[key + 1].min), re);
  }
  return re;
  }
  public void Add(int x)
  {
  List.Add(x);
  if (x > max) { max = x; }
  if (x < min) { min = x; }
  }
  }


  static ulong ABS(int x, int y)
  {
  //三分。
  switch (x.CompareTo(y))
  {
  case -1:
  return (ulong)y - (ulong)x;
  case 1:
  return (ulong)x - (ulong)y;
  }
  return 0ul;

  }

  static ulong Min(ulong x, ulong y)
  {
  if (x > y) { return y; }
  return x;
  }
  }
}
posted @ 2011-07-10 01:30 CSDN大笨狼 阅读(207) 评论(1) 编辑

25匹赛马,5个跑道,也就是说每次有5匹马可以同时比赛。问最少比赛多少次可以知道跑得最快的5匹马?



posted @ 2011-07-10 01:23 CSDN大笨狼 阅读(152) 评论(1) 编辑
摘要: 最近点对问题,三分治法,和求中位数思路是一样的,1,随机选一个数X,线性扫描,比X小的一堆A,比X大的一堆B,同时可以得到Min=Min(MinB-X,x-MaxA)2, 对于这两堆,分别重复1的步骤,直到结束。求中位数,需要抛弃掉一半数据,只求其中一个子集合的n/2-k大即可。《算法概论》上有证明递推式复杂度的通式。对于递推式T(n)=aT(n/b)+O(n^d)有如下结论:1,当d>log(b,a)时复杂度是O(n^d)2,当d=log(b,a)时复杂度是O(n^d*logn)3, 当d<log(b,a)时复杂度是O(n^(log(b,a))这个公式可以适用于快速排序,中位数等阅读全文
posted @ 2011-07-06 17:03 CSDN大笨狼 阅读(385) 评论(0) 编辑
摘要: using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Numerics;using System.Globalization;using System.Diagnostics;namespace ConsoleApplication11{ class Program { static int[] HowMuch1 = new int[] { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,阅读全文
posted @ 2011-07-05 01:15 CSDN大笨狼 阅读(71) 评论(1) 编辑
摘要: using System;using System.Collections.Generic;using System.IO;using System.Text;namespace ConsoleApplication1{ public class Idiom { public static Dictionary<Char, List<int>> Dict = new Dictionary<char, List<int>>(); public static List<Idiom> IdiomList = new List<Idio阅读全文
posted @ 2011-07-01 19:19 CSDN大笨狼 阅读(69) 评论(0) 编辑
摘要: 再次展示算法的力量!~~三分钟的程序优化到了90毫秒,还是那句话,位运算神马的最给力了。淘宝卖家想知道,哪些商品的组合是最受欢迎的。已知十万多订单项里,有几十种商品,有一万多相关用户,要求输出2-6种商品的全部组合,对应的订单数。订单项,记录的是产品编号,用户编号,可以随机模拟。这个程序,同事小张,在输出2种商品的情况下,就耗时3分多钟。在他原有的代码上,我把他原来的复杂度O(n^2*m^2),利用哈希表,优化到了O(n^2*m),还需要59秒。今天决定得瑟一下,突破性能极限,显露一下位运算的威武。原理如下:63个数以内的排列组合,不管几选几,都可以用一个Ulong整数来表示。比如:【1,3,阅读全文
posted @ 2011-06-29 17:29 CSDN大笨狼 阅读(575) 评论(5) 编辑