上一篇文章(http://blog.csdn.net/xzjxylophone/article/details/6832211)我们已经按照面试题的要求完成了Rand10的功能。
在文章的结尾处,猜测了有可能有其他的方法去实现Rand10.
那么这篇文章就来说说如何去实现10=5*2(5个集合,每个集合有2个元素)和12=2*6(2个集合,每个集合有6个元素)
既然我们知道有代码重构这个概念,我想有必要代码重构下!Let's Go
首先一个所有随机数的抽象类
Rand
//抽象类 //随即数范围是[1, MaxNum] //注:[a,b],表示包括a也包括b //(a,b],表示不包括a但是包括b //数学中闭合的关系 public abstract class Rand { //获取下一个随机数 public abstract int Next(); //随机数类的实例 protected static Rand rand; //指明的最大数 protected int _maxNum; public int MaxNum { get { return _maxNum; } } }Rand7:
//1~7的随机数产生类 public class Rand7 : Rand { private readonly Random _random = new Random(); private Rand7() { _maxNum = 7; } public static Rand7 GetInstance() { if (rand == null || !(rand is Rand7)) { rand = new Rand7(); } return (Rand7)rand; } //获得随机数 override public int Next() { return _random.Next(1, 8); } }
Rand7Base:
//该类的作用表示其他随机数是以Rand7为基础 public abstract class Rand7Base : Rand { protected Rand7 _rand7 = Rand7.GetInstance(); }
//1~10的随机数产生类 public class Rand10 : Rand7Base { private Rand10() { _maxNum = 10; } public static Rand10 GetInstance() { if (rand == null || !(rand is Rand10)) { rand = new Rand10(); } return (Rand10)rand; } //2个集合,每个集合5个元素 //(1,3,5,7,9)(2,4,6,8,10) override public int Next() { int num; //均匀产生1、 2 、3、4、5 while (true) { num = _rand7.Next(); if (num <= 5) break; } while (true) { int n = _rand7.Next(); if (n == 1) continue; //n大于4的数字有5、6、7,因为是由Rand7产生的,所以概率均匀 if (n > 4) //因为num只可取值1、2、3、4、5并且取值概率均匀,num*2可得2、4、6、8、10也概率均匀 num *= 2; //n小于4的数字有1、2、3,因为是由Rand7产生的,所以概率均匀 else //因为num只可取值1、2、3、4、5并且取值概率均匀,num*2-1可得1、3、5、7、9也概率均匀 num = num * 2 - 1; break; } return num; } } public class Rand12 : Rand7Base { private Rand12() { _maxNum = 12; } public static Rand12 GetInstance() { if (rand == null || !(rand is Rand12)) { rand = new Rand12(); } return (Rand12)rand; } //获得随机数 //3个集合,每个集合有4个数据 //(3,6,9,12)(2,5,8,11)(1,4,7,10) override public int Next() { //3*4 int num; while (true) { num = _rand7.Next(); if (num <= 4) break; } while (true) { int n = _rand7.Next(); if (n == 1) continue; if (n > 5) num *= 3; else if (n > 3) num = num * 3 - 1; else num = num * 3 - 2; break; } return num; } }
[System.Runtime.InteropServices.DllImport("Kernel32.dll")] static extern bool QueryPerformanceCounter(ref long count); [System.Runtime.InteropServices.DllImport("Kernel32.dll")] static extern bool QueryPerformanceFrequency(ref long count); //测试随即数产生的概率 static void SubTestRand(Rand rand) { long total = 10000000; long count = 0; long count1 = 0; long freq = 0; double result = 0; QueryPerformanceFrequency(ref freq); QueryPerformanceCounter(ref count); int[] numArray = new int[rand.MaxNum]; double[] doubleResult = new double[rand.MaxNum]; for (long i = 0; i < total; i++) { int randomNumber = rand.Next(); numArray[randomNumber - 1]++; } //打印产生各数的概率 for (int i = 0; i < numArray.Length; i++) { double res = (Double)numArray[i] / total; doubleResult[i] = res; string eachResult = string.Format("产生{0}的概率是:{1:0.0000000}", i + 1, res); Console.WriteLine(eachResult); } QueryPerformanceCounter(ref count1); count = count1 - count; result = (double)(count) / (double)freq; string spendTime = string.Format("耗时: {0} 秒", result); Console.WriteLine(spendTime); double average = (double)1 / doubleResult.Length; double max = doubleResult[0]; double min = doubleResult[0]; for (int i = 0; i < doubleResult.Length; i++) { max = max > doubleResult[i] ? max : doubleResult[i]; min = min < doubleResult[i] ? min : doubleResult[i]; } string totalMes = string.Format("Average:{0:0.0000000};Max:{1:0.0000000};Min:{2:0.0000000}", average, max, min); string maxMes = string.Format("Max:{0:0.0000000}, Max-Average:{1:0.0000000}, Bits:{2:0.0000000}%", max, max - average, (max - average) / average * 100); string minMes = string.Format("Min:{0:0.0000000}, Min-Average:{1:0.0000000}, Bits:{2:0.0000000}%", min, min - average, (min - average) / average * 100); Console.WriteLine(totalMes); Console.WriteLine(maxMes); Console.WriteLine(minMes); } static void TestRand(Rand rand) { Console.WriteLine(string.Format("计算Rand{0}的概率如下", rand.MaxNum)); SubTestRand(rand); }
static void TestRand10() { Rand10 rand = Rand10.GetInstance(); TestRand(rand); } static void TestRand12() { Rand12 rand = Rand12.GetInstance(); TestRand(rand); }
static void Main(string[] args) { TestRand10(); TestRand10(); Console.ReadLine(); }
以上这么多内容只是说了重构,现在我们来实现10=5*2(5个集合,每个集合有2个元素)和12=2*6(2个集合,每个集合有6个元素)。
实现10=5*2, 假设类名为:Rand10_2(表示Rand10的第二种实现方案)
public class Rand10_2:Rand7Base { private Rand10_2() { _maxNum = 10; } public static Rand10_2 GetInstance() { if (rand == null || !(rand is Rand10_2)) { rand = new Rand10_2(); } return (Rand10_2)rand; } //5个集合,每个集合2个元素 //(1,6)(2,7)(3,8)(4,9)(5,10) override public int Next() { int num; //均匀产生1、 2 、3、4、5 while (true) { num = _rand7.Next(); if (num <= 2) break; } while (true) { int n = _rand7.Next(); if (n > 5) continue; //n是从1到5 //num刚开始只是1或者2 //所以要-1 num = 5 * num - n + 1; break; } return num; } }在测试类添加如下函数:
//此函数的作用是表示随机数的其他方法 static void TestRand(Rand rand, string message) { Console.WriteLine(string.Format("计算{0}的概率如下", message)); SubTestRand(rand); } static void TestRand10_2() { Rand10_2 rand = Rand10_2.GetInstance(); TestRand(rand, "Rand10_2"); }
public class Rand12_2 : Rand7Base { private Rand12_2() { _maxNum = 12; } public static Rand12_2 GetInstance() { if (rand == null || !(rand is Rand12_2)) { rand = new Rand12_2(); } return (Rand12_2)rand; } //2个集合,每个集合有6个数据 //(2,4,6,8,10,12)(1,3,5,7,9,11) override public int Next() { int num; while (true) { num = _rand7.Next(); if (num <= 6) break; } while (true) { int n = _rand7.Next(); if (n == 1) continue; if (n > 4) num *= 2; else num = num * 2 - 1; break; } return num; } }
static void TestRand12_2() { Rand12_2 rand = Rand12_2.GetInstance(); TestRand(rand, "Rand12_2"); }
static void Main(string[] args) { TestRand10(); TestRand10_2(); TestRand12(); TestRand12_2(); Console.ReadLine(); }
计算Rand10的概率如下 产生1的概率是:0.0999950 产生2的概率是:0.1000683 产生3的概率是:0.1000904 产生4的概率是:0.0998266 产生5的概率是:0.1000829 产生6的概率是:0.0999189 产生7的概率是:0.1000285 产生8的概率是:0.0999484 产生9的概率是:0.0999287 产生10的概率是:0.1001123 耗时: 2.23924715284627 秒 Average:0.1000000;Max:0.1001123;Min:0.0998266 Max:0.1001123, Max-Average:0.0001123, Bits:0.1123000% Min:0.0998266, Min-Average:-0.0001734, Bits:-0.1734000% 计算Rand10_2的概率如下 产生1的概率是:0.1001656 产生2的概率是:0.0998927 产生3的概率是:0.1000315 产生4的概率是:0.1000447 产生5的概率是:0.1000213 产生6的概率是:0.0998959 产生7的概率是:0.0999171 产生8的概率是:0.0998640 产生9的概率是:0.1000109 产生10的概率是:0.1001563 耗时: 4.63440941163983 秒 Average:0.1000000;Max:0.1001656;Min:0.0998640 Max:0.1001656, Max-Average:0.0001656, Bits:0.1656000% Min:0.0998640, Min-Average:-0.0001360, Bits:-0.1360000% 计算Rand12的概率如下 产生1的概率是:0.0832689 产生2的概率是:0.0833657 产生3的概率是:0.0832885 产生4的概率是:0.0833306 产生5的概率是:0.0833956 产生6的概率是:0.0832436 产生7的概率是:0.0833872 产生8的概率是:0.0833305 产生9的概率是:0.0832966 产生10的概率是:0.0834083 产生11的概率是:0.0834503 产生12的概率是:0.0832342 耗时: 2.61100502823934 秒 Average:0.0833333;Max:0.0834503;Min:0.0832342 Max:0.0834503, Max-Average:0.0001170, Bits:0.1403600% Min:0.0832342, Min-Average:-0.0000991, Bits:-0.1189600% 计算Rand12_2的概率如下 产生1的概率是:0.0834729 产生2的概率是:0.0832840 产生3的概率是:0.0833406 产生4的概率是:0.0834923 产生5的概率是:0.0833294 产生6的概率是:0.0830786 产生7的概率是:0.0834936 产生8的概率是:0.0833099 产生9的概率是:0.0834100 产生10的概率是:0.0832989 产生11的概率是:0.0832233 产生12的概率是:0.0832665 耗时: 2.46493227776721 秒 Average:0.0833333;Max:0.0834936;Min:0.0830786 Max:0.0834936, Max-Average:0.0001603, Bits:0.1923200% Min:0.0830786, Min-Average:-0.0002547, Bits:-0.3056800%
我想这个随机数是可以接受了。
既然10和12都可以通过7来获得,那么11该如何通过7来获得了? 下一篇文章我们来介绍如何通过Rand7来得到Rand11.