再谈非重复随机序列号生成算法
来源:互联网 发布:淘宝卖家淘宝客推广 编辑:程序博客网 时间:2024/06/05 22:38
这段时间项目中又要开发兑换码功能,此前的项目已经开发过,但是为了保证这个功能在将来的可重复利用,我决定重构一下相关模块。
原来的模块不是我开发的,但也已经可以完成这个要求。但其中存在两个问题,这也是基本上非重复随机序列生成算法都要面对的问题
(1)是非重复性
(2)是效率
我们原来的程序员开发的,是使用的最低效的方式,即随机生成后,遍历已经生成的所有随机序列号,如果重复则放弃这组随机序列号,重新生成。在这个过程中,首先暴露的是低效,其次是只能保证本批次的序列号不重复,再次启动工具生成,两个批次的随机序列号就无法保证不重复了。
那么也会有人问,为什么不使用GUID之类的算法,因为兑换码这个东西,其实有很多额外的需求,比如长度,随机码中使用的字符,有纯数字的序列号,也有纯字母的,所以诸如GUID,MD5,SHA等都不完全适合。
我前几天曾经转了一篇非重复随机序列生成算法 ,其中作者的思路确实提供我很大的帮助,但是仔细看了作者的实现后,其实也发现了一点欠缺,该文中的算法解决了效率问题,也解决了重复问题,但是其能生成的序列号数量大大减少。打个比方,如果是生成长度10的序列号,文中的算法将保证[0~9]的数组只出现一次,按照排列组合的算法,最终出现的序列号总数是10*9*7*6*5*4*3*2*1,但实际我们需求的序列号,每一位的数字可以重复,但整个序列号不能产生重复,换句话说,我们的序列号总数应该是10的10次幂。
改进方案
(一)对于一个非重复的随机序列号,要做到非重复,其N位上出现的字符的顺序不能有相同的情况。使用排列组合的知识我们知道,假设我们有N位,每一位上允许的字符有m个的话,我们能产生的不重复的排列组合总量为m1 m2 * m3 …*mN个,这就是非重复性
(二)随机性,也就是我们从上述m的N次幂的序列中,随机抽取K个,就能完成我们的目标。当然,不能用随机数来决定抽取哪一个,这样还得遍历已经抽取出来的序列号,来判断是否两次挑选序列号是否挑到了同一个
(三)我的算法思路,首先求得一个排列组合的子集,即s1 * s2 * s3 *,,,*sN = C,C为我们要生成的序列号总量,s是m的一个字符子集,s这个子集是从m集合中抽取的随机的不重复的字符。这样就能保证C的序列号是完全不会重复的序列号。s的子集,我使用了转载文章中作者的算法,通过构建一个包含m个不同字符的数组,并对数组随机抽取索引,进行移位交换,最后得到一个包含不重复字符的s子集
(四)序列号需求,对于任意长度的序列号,我们只需要增加N,对于序列号中出现的字符限制,我们只需要更改m集合中的字符内容,就可以得到纯字符,或是纯数字,或是混合的序列号
(五)不同批次的永不重复性,这个我选择了使用增加前缀的方法,比如采用时间,来确定唯一性,然后将时间作为序列号的一部分,加入前缀或是后缀,也可以自定义。
其实还有一种方法就是先利用本算法生成K个较短长度的非重复随机序列号,K足够大,保证这批序列号足够使用,然后存入一个文件中,以后再生成时,将这K个中随机抽取一个,作为批次的标识,生成一次,就抛弃K中的一个,就可以了
附上相应的只要算法代码
if (count.ToString().Length > length){ Console.WriteLine("生成数量大于位数,无法生成"); return null;}var seed = DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0);var random = new Random((int)seed.TotalSeconds);int[] bitTimes = new int[length];int total_count = 1;int idx = 0;while (idx < length){ int f = random.Next(0, 10); bitTimes[idx] = f; total_count *= f > 0 ? f : 1; idx++; if (total_count >= count) { break; }}while (total_count < count){ for (int i = 0; i < length; i++) { if (bitTimes[i] < 10) { var c = bitTimes[i]; bitTimes[i] += 1; total_count = total_count + total_count / c; } if (total_count >= count) { break; } }}var codes = new string[total_count];for (int i = 0; i < length; i++){ int coloum = bitTimes[i]; coloum = Math.Max(1, coloum); int row = total_count / coloum; int[] num_array = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int[] num = new int[coloum]; int x = 0, tmp = 0, n = 0; for (int m = num_array.Length - 1; m > 0; m--) { x = random.Next(0, m + 1); tmp = num_array[m]; num_array[m] = num_array[x]; num_array[x] = tmp; num[n] = num_array[m]; n++; if (n >= coloum) { break; } } for (int j = 0; j < row; j++) { for (int k = 0; k < coloum; k++) { var index = j * coloum + k; codes[index] = i == 0 ? num[k].ToString() : codes[index] + num[k]; } }}return codes;
这里只有实现,还未作优化,相关优化,代码工程请移步
https://github.com/duotemplar/RedeemCodeGenerator
- 再谈非重复随机序列号生成算法
- 生成数据库随机序列号
- 不重复随机数列生成算法
- 不重复随机数列生成算法
- 不重复随机数列生成算法
- 不重复随机数列生成算法
- 不重复随机数列生成算法
- 【算法】非重复随机序列生成
- 不重复随机数列生成算法
- 不重复随机数列生成算法
- 不重复随机数列的生成算法
- 非重复随机序列生成算法
- delphi生成一个随机序列号
- 序列号生成算法分析
- O(n)的随机生成不重复算法
- java经典算法_033随机生成不重复的数字
- 随机生成不重复的随机数的简单算法
- 非重复随机序列生成算法-交换法
- hadoop安装前的准备
- SOCKET 网络通信
- 反卷积结构及原理
- 《Java开发实战1200例》(第2卷)学习笔记—TCP套接字
- Single-image shadow detection and removal using paired regions学习解读
- 再谈非重复随机序列号生成算法
- jquery写的表单验证
- 快速扫描算法提取鱼眼图像有效区域
- H5手游页游的资源版本管理(带Egret例子)
- 《剑指Offer》做题总结(一)
- (二)在centos7 下安装docker
- tensorflow 设置图片大小与翻转
- 2017814作业
- phantomjs 抓取、截图中文网站乱码的问题的解决