实验一 控制台应用程序——随机数
信息学院 网络工程3班 黎健成 201130720310
一. 实验要求
这是一个实际的项目衍生出来的核心算法之一。防伪码是我们现在经常在商品上看到的防伪手段之一,现在需要编写一个防伪码生成器,按照输入参数生成防伪码,并且把生成的时间及指定的防伪码输出。
1)防伪码的组成
防伪码由以下字符组成:0123456789ABCDEFGHJKLMNPQRSTUVWXYZ
(数字1和字母I相近、数字0和字母O相近,所以去掉字母I和字母O。全部字母大写)
2)在命令行中输入2个参数,分别是:
防伪码长度,防伪码个数
例如:在命令行中调用程序为:学号.exe 10 10000
指的是防伪码长度为10,生成10000个防伪码。
3)防伪码的生成及注意事项
防伪码的长度由命令行参数决定;
所生成的防伪码不能重复(按照以上例子,生成了10000个防伪码,这10000个防伪码就肯定不能重复)。
二. 设计思路
1. 首先根据格输入“exe 防伪码长度 防伪码个数”读入防伪码的个数,由于C#不支持在一行里面读入两个数字,所以写了函数来实现这一功能。
核心代码:
public static void ReadKeys(ref int icount, ref int ilength)
{
try
{
string[] str =Console.ReadLine().Split(' ');//根据空格拆分读入字符串
icount =Convert.ToInt32(str[0]);
if (str.Length > 1)//如果查分到两个字符串,即同时输入了两个参数
{
ilength =Convert.ToInt32(str[1]);
}
else//继续读下一个参数
{
ilength =Convert.ToInt32(Console.ReadLine());
}
}
catch (Exception ex)//如果输入有误,抛出异常
{
throw newException(ex.Message);
}
}
2. 接着根据防伪码的长度(icount)和个数(ilength)产生防伪码。并将产生的防伪码加入到哈希集(hashSet)中。将防伪码插入哈希集中,如果没有加入成功,即哈希集中没有重复的防伪码则总个数加1。循环地生成规定长度的防伪码直到总个数达到规定的要求。
核心代码:
public static voidPlayRandom(int icount, int ilength)
{
try
{
int i = 0;
HashSet<string> hashSet =new HashSet<string>();
Random ra = newRandom(DateTime.Now.Millisecond);
StringBuilder strBuilder = newStringBuilder();
while (i < ilength)//当没有达到规定长度的时候继续生成防伪码
{
strBuilder.Remove(0,strBuilder.Length);
for (int j = 0; j <icount; j++)
{
strBuilder.Append(randomList[ra.Next(randomList.Length)]);
}//根据长度,产生防伪码
if(hashSet.Add(strBuilder.ToString())) i++;//如果没有重复,总数加1
}
}
catch (Exception ex)
{
throw newException(ex.Message);
}
}程序运行效果图
1.第一组测试数据(10 10000),见图1。
2.第二组测试数据(20 1000000),见图2。
3.第三组测试数据(50 1000000),见图3。
三. 实验总结
作为本学期的第一个作业,乍一看上去,还是挺困难的。但是,看看QQ群上的同学们的讨论,加上在网络上搜索的算法,也给了我不少的提示。
原先以为这是一个非常复杂的过程,但是实际编程的时候确发现还是比较容易实现功能的。但是耗费大量时间才出结果的确令人感到不爽。为此,甚至还动用到了多线程,但是发现结果却还更慢了。于是只好放弃。
最后,在我请教了我班的大神之后,我改用了利用哈希表中的Contains方法直接比较两个防伪码的哈希码,而不是用ContainsValue直接比较两个防伪码是否相同,这样,由原先的O(n)时间复杂度降为O(1),就可以发现防伪码是否重复。
后来,在课上听老师说了哈希集(HashSet)的使用方法,然后就将容器由哈希表改为了哈希集,结果速度又有了很大的提升,更加使我感到无比地兴奋!
总体来说,这次的实验让我对哈希表和哈希集的运用有所加深,也深刻体会到了其便捷。
附完整代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Collections;
namespace test1
{
class Program
{
public static string randomList = "0123456789ABCDEFGHJKLMNPQRSTUVWXYZ";
public static void Pause()
{
Console.Write("请键入任意字符以结束……");
Console.ReadKey(true);
}
public static void ReadKeys(ref int icount, ref int ilength)
{
try
{
Console.WriteLine("输入格式:长度 个数");
string[] str = Console.ReadLine().Split(' ');
icount = Convert.ToInt32(str[0]);
if (str.Length > 1)
{
ilength = Convert.ToInt32(str[1]);
}
else
{
ilength = Convert.ToInt32(Console.ReadLine());
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
public static void PlayRandom(int icount, int ilength)
{
try
{
int i = 0;
HashSet<string> hashSet = new HashSet<string>();
Random ra = new Random(DateTime.Now.Millisecond);
StringBuilder strBuilder = new StringBuilder();
while (i < ilength)
{
strBuilder.Remove(0, strBuilder.Length);
for (int j = 0; j < icount; j++)
{
strBuilder.Append(randomList[ra.Next(randomList.Length)]);
}
if (hashSet.Add(strBuilder.ToString())) i++;
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
static void Main(string[] args)
{
Stopwatch timer1 = new Stopwatch();
int icount = 0, ilength = 0;
try
{
ReadKeys(ref icount, ref ilength);//读入防伪码长度,个数
timer1.Start();
PlayRandom(icount, ilength);//产生随机防伪码
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
timer1.Stop();
double dMilliseconds = timer1.Elapsed.TotalMilliseconds;
Console.WriteLine("生成个数为:{0},运行时间为:{1}ms", ilength, dMilliseconds);
}
Pause();
}
}
}