none
C#如何生成随机,但是不重复的数字? RRS feed

  • 问题

  • C#如何生成随机,但是不重复的数字?用户在Textbox1里,写上20,代表全体员工数. 在Textbox2里,写上4,代表要参加义务植树活动. 就是要在20个数里,随机抽取4个。不能重复的。

    请问,用C#如何实现?我看过Random类了。它不行,只是简单地生成一个数。而且,下一次点击按钮生成后,和上一次点击按钮生成的,都很多重复的。


    本人现在使用Windows Server 2003, CentOS Linux 5.2, Windows XP, VirtualBox 2.1.4, Visual Studio 2005, Eclipse 3.4, Microsoft.NET Framework 2.0 SP2, C# 2.0, IIS 6.0, Apache 1.3.41, Nginx-0.6.36, SQL Server 2000, MySQL 5.0, FireBird 2.1.1, PHP 5.2.4, Office 2007, OpenOffice 3.0和永中Office2009.
    2009年5月7日 13:29

答案

  • 你好!
         容易实现啊!用Random类生成随机数,然后还前面生成的随机数比较,如果相同就放弃,继续用Random生成随机数只到生成一个不重复的!
    周雪峰
    • 已标记为答案 dvdvip 2009年5月8日 1:16
    2009年5月7日 14:05
    版主
  • 刚才我帮你写了一个,不是很好,但是可以用:
     int[] randomArray = new int[4];
                Random random=new Random();
                randomArray[0] = random.Next(1, 21);

                for (int i = 1; i < 4; i++)
                {
                   
                   
                    bool foundSame = false;
                    do
                    {
                        foundSame = false;
                        randomArray[i] = random.Next(1, 21);
                        for (int j = 0; j < i; j++)
                        {
                            if (randomArray[i] == randomArray[j])
                            {
                                foundSame = true;
                                break;
                            }
                        }

                    } while (foundSame);
                }
    周雪峰
    • 已标记为答案 dvdvip 2009年5月8日 1:16
    2009年5月7日 14:56
    版主
  • private void button1_Click(object sender, EventArgs e)
    {
        Random fRandom = new Random();
    
        int fMaxNum = 20;
        int fCurNum = 0;
        int fCount = 4;
    
        List<int> fResult = new List<int>();
        while (fResult.Count < fCount)
        {
            fCurNum = fRandom.Next(0, fMaxNum);
            if (!fResult.Contains(fCurNum))
                fResult.Add(fCurNum);
        }
    
        foreach (int f in fResult)
        {
            MessageBox.Show(f.ToString());
        }
    }

    知识改变命运,奋斗成就人生!
    • 已标记为答案 dvdvip 2009年5月8日 1:16
    2009年5月7日 15:07
    版主
  • 我给你写的是原理,你自己改成函数参数做输入就可以了!
    周雪峰
    • 已标记为答案 dvdvip 2009年5月8日 7:51
    2009年5月8日 5:13
    版主
  • 我有好的思路,是从一个洗牌程序启发的,我还写了个抽取彩票呢!
                int[] numbers=new int [20];     //建立一个数组
                Random rand=new Random (); //生成随机数
                string result="";                    //保存结果
                for (int i = 0; i < 20; i++)       //初始化数组
                    numbers[i] = i+1;
                for (int i = 0; i < 20; i++)          //洗牌
                  {
                    int temp = rand.Next(20);
                    int tempNumber = numbers[i ];
                    numbers[i] = numbers[temp ];
                    numbers[temp] =tempNumber ;
                  }
                for (int i = 0; i < 4; i++)          //这个用来排列你想要的那4个数
                    for (int j = 0; j < 4; j++)         
                    {                                           //你不需要就去掉它
                        int temp;
                        if (numbers[i] < numbers[j])
                        {
                            temp = numbers[j];
                            numbers[j] = numbers[i];
                            numbers[i] = temp;
                        }
                        else
                            continue;
                    }                                         //生成结果项
                        for (int i = 0; i < 4; i++)
                            result += "result" + i.ToString() + "==>" + numbers[i].ToString() + Environment.NewLine;
                          MessageBox.Show(result );     //输出结果


    这个思路挺好的,洗牌程序都应该是这样的 我感觉。
    • 已标记为答案 dvdvip 2009年5月8日 13:57
    2009年5月8日 12:55
  • 这里面得解答胖胖亮的洗牌解法是最优的。

    首先创建一个大小为 N 的数组 array,目的是打乱这个数组,使得里面的元素随机分布。
    如何打乱呢?
    设 I = N - 1,然后用Randam产生一个 1 - N 的随机数。假设得到的结果是 J。那么就交换 array[I] 和 array[J]
    把 I 减少1. 继续循环,一直到 I = 0


    这里,若是我们只需要 M 个随机数,那么就不用把 I 减少到 0,减少到 N - M 即可,也就是循环 M 次。那么数组前 M 个元素就是输出。

    MCPD (Windows & Web)
    • 已标记为答案 dvdvip 2010年10月10日 23:34
    2009年5月9日 8:57
  • 看楼主的发帖日期是2009年5月份的,我记得这个时候C#的Random函数已经有种子的说法了啊。Random ran=new Random(int seed); 这个seed就是种子,只要保证每次new Random时的种子seed不同,就可以肯定取到的随机数不同了。

    我一般是这样给seed赋值: int seed = DateTime.Now.Day * 24 * 3600 * 1000 + DateTime.Now.Hour * 3600 * 1000 + DateTime.Now.Minute * 60 * 1000 + DateTime.Now.Second * 1000 + DateTime.Now.Millisecond;

    也就是每次都取当前时间的总毫秒数作为种子。

    然后再int num=ran.Next(20);就能取到20以内的不同的数了。

    最后按照版主的方法剔除重复就可以了。

    • 已建议为答案 东方血狼 2010年10月8日 7:13
    • 已标记为答案 dvdvip 2010年10月10日 23:33
    2010年10月8日 7:11

全部回复

  • 你好!
         容易实现啊!用Random类生成随机数,然后还前面生成的随机数比较,如果相同就放弃,继续用Random生成随机数只到生成一个不重复的!
    周雪峰
    • 已标记为答案 dvdvip 2009年5月8日 1:16
    2009年5月7日 14:05
    版主
  • 刚才我帮你写了一个,不是很好,但是可以用:
     int[] randomArray = new int[4];
                Random random=new Random();
                randomArray[0] = random.Next(1, 21);

                for (int i = 1; i < 4; i++)
                {
                   
                   
                    bool foundSame = false;
                    do
                    {
                        foundSame = false;
                        randomArray[i] = random.Next(1, 21);
                        for (int j = 0; j < i; j++)
                        {
                            if (randomArray[i] == randomArray[j])
                            {
                                foundSame = true;
                                break;
                            }
                        }

                    } while (foundSame);
                }
    周雪峰
    • 已标记为答案 dvdvip 2009年5月8日 1:16
    2009年5月7日 14:56
    版主
  • private void button1_Click(object sender, EventArgs e)
    {
        Random fRandom = new Random();
    
        int fMaxNum = 20;
        int fCurNum = 0;
        int fCount = 4;
    
        List<int> fResult = new List<int>();
        while (fResult.Count < fCount)
        {
            fCurNum = fRandom.Next(0, fMaxNum);
            if (!fResult.Contains(fCurNum))
                fResult.Add(fCurNum);
        }
    
        foreach (int f in fResult)
        {
            MessageBox.Show(f.ToString());
        }
    }

    知识改变命运,奋斗成就人生!
    • 已标记为答案 dvdvip 2009年5月8日 1:16
    2009年5月7日 15:07
    版主
  • 方法很多,这个能好一些:
                Random random = new Random();
                int[] randomArray = new int[4];

                bool foundSame;

                for (int i = 0; i < 4; )
                {
                    randomArray[i] = random.Next(1, 21);
                    foundSame = false;
                    for (int j = 0; j < i; j++)
                        if (randomArray[i] == randomArray[j])
                        {
                            foundSame = true;
                            break;
                        }
                    if (!foundSame)
                        i++;
                }

    周雪峰
    2009年5月7日 15:30
    版主
  • XXY的用到了泛型List,也是很好的方法啊!
    学习了啊!
    周雪峰
    2009年5月7日 15:34
    版主
  • 谢谢了,但是我水平不够,看得不是很明白。
    本人现在使用Windows Server 2003, CentOS Linux 5.2, Windows XP, VirtualBox 2.1.4, Visual Studio 2005, Eclipse 3.4, Microsoft.NET Framework 2.0 SP2, C# 2.0, IIS 6.0, Apache 1.3.41, Nginx-0.6.36, SQL Server 2000, MySQL 5.0, FireBird 2.1.1, PHP 5.2.4, Office 2007, OpenOffice 3.0和永中Office2009.
    2009年5月8日 1:17
  • 不客气啊!
    但是你是哪个没有看明白啊?
    周雪峰
    2009年5月8日 1:19
    版主
  • 你这种方法,好像不是真正的提取,就像高中是学的数学那种。


    你这是把已经出现过数排除。再进行Random. 感觉效率不高。


    我的想法是,用户是输入数字20, 就自动生成1到20这20个数。然后,程序从这20个数中,随机选择里面的几个数。这样就灵活。不然,下次有400员工,80个要去植树。这程序不是又要变了?
    本人现在使用Windows Server 2003, CentOS Linux 5.2, Windows XP, VirtualBox 2.1.4, Visual Studio 2005, Eclipse 3.4, Microsoft.NET Framework 2.0 SP2, C# 2.0, IIS 6.0, Apache 1.3.41, Nginx-0.6.36, SQL Server 2000, MySQL 5.0, FireBird 2.1.1, PHP 5.2.4, Office 2007, OpenOffice 3.0和永中Office2009.
    2009年5月8日 4:09
  • 我给你写的是原理,你自己改成函数参数做输入就可以了!
    周雪峰
    • 已标记为答案 dvdvip 2009年5月8日 7:51
    2009年5月8日 5:13
    版主
  • 我有好的思路,是从一个洗牌程序启发的,我还写了个抽取彩票呢!
                int[] numbers=new int [20];     //建立一个数组
                Random rand=new Random (); //生成随机数
                string result="";                    //保存结果
                for (int i = 0; i < 20; i++)       //初始化数组
                    numbers[i] = i+1;
                for (int i = 0; i < 20; i++)          //洗牌
                  {
                    int temp = rand.Next(20);
                    int tempNumber = numbers[i ];
                    numbers[i] = numbers[temp ];
                    numbers[temp] =tempNumber ;
                  }
                for (int i = 0; i < 4; i++)          //这个用来排列你想要的那4个数
                    for (int j = 0; j < 4; j++)         
                    {                                           //你不需要就去掉它
                        int temp;
                        if (numbers[i] < numbers[j])
                        {
                            temp = numbers[j];
                            numbers[j] = numbers[i];
                            numbers[i] = temp;
                        }
                        else
                            continue;
                    }                                         //生成结果项
                        for (int i = 0; i < 4; i++)
                            result += "result" + i.ToString() + "==>" + numbers[i].ToString() + Environment.NewLine;
                          MessageBox.Show(result );     //输出结果


    这个思路挺好的,洗牌程序都应该是这样的 我感觉。
    • 已标记为答案 dvdvip 2009年5月8日 13:57
    2009年5月8日 12:55
  • 补充一下
    我感觉这个用途挺广的,播放器的随机列表应该就是这么来的 嘿嘿

    2009年5月8日 13:20
  • 没有人理我的问题 我给再改写一下你要的那个输入数就能自动生成随机数的程序
    这个程序看着挺长的,不过简单易懂,而且很效率
    private int yourNumber=20;                                      //你更改 yourNumber 成你想要的值
    private void GetRandomNumbers(int length)                // length 表示你想从中 提取几个随机数
    {
    int[] numbers=new int [yourNumber];     //建立一个数组
                Random rand=new Random (); //生成随机数
                string result="";                    //保存结果
                for (int i = 0; i < yourNumber; i++)       //初始化数组
                    numbers[i] = i+1;          //你好像要求不从0开始
                for (int i = 0; i < yourNumber; i++)          //洗牌
                  {
                    int temp = rand.Next(yourNumber);
                    int tempNumber = numbers[i ];
                    numbers[i] = numbers[temp ];
                    numbers[temp] =tempNumber ;
                  }
                for (int i = 0; i <length; i++)          //这个用来排列你想要的数
                    for (int j = 0; j < length; j++)         
                    {                                           //你不需要就去掉它
                        int temp;
                        if (numbers[i] < numbers[j])
                        {
                            temp = numbers[j];
                            numbers[j] = numbers[i];
                            numbers[i] = temp;
                        }
                        else
                            continue;
                    }                                         //生成结果项
                        for (int i = 0; i < length; i++)
                            result += "result" + i.ToString() + "==>" + numbers[i].ToString() + Environment.NewLine;
                          MessageBox.Show(result );     //输出结果

    }

    Best regards,
    PPLiang
    2009年5月8日 13:30
  • 感谢胖胖亮分享你的经验啊!
    值得大家学习啊!
    周雪峰
    2009年5月8日 13:54
    版主
  • 你这种方法,好像不是真正的提取,就像高中是学的数学那种。


    你这是把已经出现过数排除。再进行Random. 感觉效率不高。


    我的想法是,用户是输入数字20, 就自动生成1到20这20个数。然后,程序从这20个数中,随机选择里面的几个数。这样就灵活。不然,下次有400员工,80个要去植树。这程序不是又要变了?
    本人现在使用Windows Server 2003, CentOS Linux 5.2, Windows XP, VirtualBox 2.1.4, Visual Studio 2005, Eclipse 3.4, Microsoft.NET Framework 2.0 SP2, C# 2.0, IIS 6.0, Apache 1.3.41, Nginx-0.6.36, SQL Server 2000, MySQL 5.0, FireBird 2.1.1, PHP 5.2.4, Office 2007, OpenOffice 3.0和永中Office2009.

    你可以这么做:

    假设需要从 N 个元素的集合里面随机的选出 M 个元素,这里 M < N。

    令 I 为当前位置,初设 I = 0。然后开始“走”。每次走的步数由 Random.Next 随机生成。每当停下的时候,把该元素从原集合里面移出。然后继续向前走,若是到了集合的末尾,那么就回到位置 0。也即,令 I = (I + RandomNext) % N。

    若是原集合是数组,那么要注意从数组里面删除一个元素的操作开销比较大的,若是 N 比较小,可以考虑给每个元素里面加上一个布尔值,用来标示是否被移出。若是 N 比较大,可以考虑使用链表。


    MCPD (Windows & Web)
    2009年5月8日 13:54
  • 我觉得你可以做周润发的继承人了。

    果然是赌神。


    本人现在使用Windows Server 2003, CentOS Linux 5.2, Windows XP, VirtualBox 2.1.4, Visual Studio 2005, Eclipse 3.4, Microsoft.NET Framework 2.0 SP2, C# 2.0, IIS 6.0, Apache 1.3.41, Nginx-0.6.36, SQL Server 2000, MySQL 5.0, FireBird 2.1.1, PHP 5.2.4, Office 2007, OpenOffice 3.0和永中Office2009.
    2009年5月8日 13:59
  • 感谢隐约有歌的解决方案啊!
    我认为这个方法也比较巧妙,但是如果是数组的话,可能性能开销比较大,建议使用List来存放数据!实际上即使如此,遍历List的时候也会产生一定的性能开销!
    周雪峰
    2009年5月8日 14:06
    版主
  • 论坛头一次有人夸我
    真是说不出的激动啊!
    终于也贡献了一回
    我从论坛也学到了很多东西,希望大家都能提高
    2009年5月8日 14:10
  • 是呀!大家多多交流才能提高嘛!
    很高兴认识你啊!我是周雪峰!
    我的MSN:xuefeng1982@live.cn
    周雪峰
    2009年5月8日 14:15
    版主
  • 我也很喜欢图书,我自己的书架上也有N多。。。。。而且继续增多中啊!
    周雪峰
    2009年5月8日 14:54
    版主
  • 这里面得解答胖胖亮的洗牌解法是最优的。

    首先创建一个大小为 N 的数组 array,目的是打乱这个数组,使得里面的元素随机分布。
    如何打乱呢?
    设 I = N - 1,然后用Randam产生一个 1 - N 的随机数。假设得到的结果是 J。那么就交换 array[I] 和 array[J]
    把 I 减少1. 继续循环,一直到 I = 0


    这里,若是我们只需要 M 个随机数,那么就不用把 I 减少到 0,减少到 N - M 即可,也就是循环 M 次。那么数组前 M 个元素就是输出。

    MCPD (Windows & Web)
    • 已标记为答案 dvdvip 2010年10月10日 23:34
    2009年5月9日 8:57
  • 看楼主的发帖日期是2009年5月份的,我记得这个时候C#的Random函数已经有种子的说法了啊。Random ran=new Random(int seed); 这个seed就是种子,只要保证每次new Random时的种子seed不同,就可以肯定取到的随机数不同了。

    我一般是这样给seed赋值: int seed = DateTime.Now.Day * 24 * 3600 * 1000 + DateTime.Now.Hour * 3600 * 1000 + DateTime.Now.Minute * 60 * 1000 + DateTime.Now.Second * 1000 + DateTime.Now.Millisecond;

    也就是每次都取当前时间的总毫秒数作为种子。

    然后再int num=ran.Next(20);就能取到20以内的不同的数了。

    最后按照版主的方法剔除重复就可以了。

    • 已建议为答案 东方血狼 2010年10月8日 7:13
    • 已标记为答案 dvdvip 2010年10月10日 23:33
    2010年10月8日 7:11