【项目实战】从抽奖算法感受算法奥妙

【前言】

           最近因为公司年会需要,组长让我们花几天时间开发了个抽奖系统。虽然就是cs的一个小例子,不过自己设计算法的过程还是蛮有意思的。下面先给大家看看,最后成品的样子。主要实现的就是excel表的导入导出和抽奖功能, 这篇就讲一下抽奖功能的实现。目前实现的效果是点击开始时,全屏隐去,只剩下名字在滚动显示,需要停止时在datagridview中显示出获奖人信息。

【设计思路



首先从excel导入名单到dataset,用timer 控制label(lblgetname)每毫秒显示

一个dataset中的名字,循环显示。 然后写一个getname方法, 让timer启动一下,

系统延迟10毫秒,然后停一下,得到一个名字。 再写一个getnewName(string[]

nameSet,string tmpName,int times)方法用来查重,将抽到的名字传进去和

抽到的名字集合nameset做比较,有重复的,重新抽取。 SelectPerson就是调用get

name和getNewName获得抽奖人,然后把已经抽到的人从dataSet中删除,防止多次抽

奖重复抽取一个人。 这是这一版的实现思路,最终成型的和这个又有差别。



正文

       

      最初的想法是通过随机数来实现抽奖, 但是到多次抽奖间不重复的时候卡住了, 不知道怎么让随机数产生时刨除确定的几个数。

        最后是通过label和timer实现的选人,每选一次就从dataSet中删除一部分人。代码如下:

       

  private void btnBegin_Click(object sender, EventArgs e)
        {
            label1.Visible = false; 
            label2.Visible = false;
            label3.Visible = false;
            txtNumber.Visible = false;
            btnLook.Visible = false;
            btnBegin.Visible = false;
            btnPreserve.Visible = false;
            btnResetting.Visible = false;
            dgv.Visible = false;
            lblgetName.Visible = true;
            dgv.Rows.Clear();
            if (user != "")
            {
                if (txtNumber.Text.Trim() != "")
                {
                    lblgetName.Text = "吴迪";
                    if (ds.Tables[0].Rows.Count > int.Parse(txtNumber.Text) * 1.3)
                    {
                        timer1.Start();
                      
                        btnBegin.Enabled = false;
                    }
                    else
                    {
                        MessageBox.Show("剩余人数已不足");
                        lblgetName.Visible = false;
                        label1.Visible = true;
                        label2.Visible = true;
                        label3.Visible = true;
                        txtNumber.Visible = true;
                        btnLook.Visible = true;
                        btnBegin.Visible = true;
                        btnPreserve.Visible = true;
                        btnResetting.Visible = true;
                        dgv.Visible = true;
                        return;
                    }

                }
                else
                {
                    MessageBox.Show("请输入要选出的人数");
                }

            }
            else
            {
                MessageBox.Show("请导入人员信息!");
            }
        }

        private void lblgetName_Click(object sender, EventArgs e)
        {
            int number = int.Parse(txtNumber.Text.Trim());
            string[] nameSet = selectPerson(number);

            try
            {
                for (int rows = 0; rows <= ds.Tables[0].Rows.Count - 1; rows++)
                {
                    for (int times = 0; times < number; times++)
                    {
                        if (ds.Tables[0].Rows[rows][1].ToString().Trim() == nameSet[times].ToString().Trim())
                        {
                            ds.Tables[0].Rows[rows][2] = "是";
                            ds.AcceptChanges();
                        }
                    }
                }
            }
            catch (Exception)
            {

                MessageBox.Show("剩余人数不足", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }

            List<LuckyPerson> luckyPeople = new List<LuckyPerson>();
            int reCount = ds.Tables[0].Rows.Count - 1;
            for (int rows = 0; rows <= reCount; rows++)
            {

                if (ds.Tables[0].Rows[rows][2].ToString().Trim() == "是")
                {
                    LuckyPerson lucky = new LuckyPerson();
                    lucky.Name = ds.Tables[0].Rows[rows][1].ToString().Trim();
                    //2表示电话所在列
                    lucky.Tel = ds.Tables[0].Rows[rows][2].ToString().Trim();
                    luckyPeople.Add(lucky);
                }


            }

            dgv.Rows.Add(luckyPeople.Count);
            for (int i = 0; i < luckyPeople.Count; i++)
            {
                dgv.Rows[i].Cells[0].Value = luckyPeople[i].Name;
                dgv.Rows[i].Cells[1].Value = luckyPeople[i].Tel;

            }
            deletLuky(reCount);
            btnBegin.Enabled = true;
            
            label1.Visible = true;
            label2.Visible = true;
            label3.Visible = true;
            txtNumber.Visible = true;
            btnLook.Visible = true;
            btnBegin.Visible = true;
            btnPreserve.Visible = true;
            btnResetting.Visible = true;
            dgv.Visible = true;
            lblgetName.Visible = false;
        }

  #region 抽奖功能-宋荣凯-2017年3月14日
        /// <summary>
        /// 
        //抽出幸运观众selectPerson-宋荣凯-2017年3月14日
        /// </summary>
        /// <param name="times">抽取数量</param>
        /// <returns>获奖人的集合</returns>

        public String[] selectPerson(int times)
        {
            String[] nameSet = new String[times];
            string nameTmp;
            //循环将抽中人员放入集合中
            for (int i = 0; i < times; i++)
            {

                nameTmp = getName();
                if (i == 0)
                {
                    nameSet[i] = nameTmp;
                }
                else
                {
                    //检查是否本次内是否有重复人员
                    nameSet[i] = getNewName(nameSet, nameTmp, i);
                }
            }
            return nameSet;

        }
        /// <summary>
        /// 若重复重新抽取--getNewName--宋荣凯-2017年3月14日
        /// </summary>
        /// <param name="nameSet">本次已抽中人</param>
        /// <param name="nameTmp">当前抽中人</param>
        /// <param name="times">已抽中人数</param>
        /// 通过循环递归,将
        /// 
        /// <returns>不重复的获奖人</returns>
        public String getNewName(String[] nameSet, String nameTmp, int times)
        {
            int n = 0;
            string finalName = "";
            while (n < times)
            {
                if (nameSet[n].ToString().Trim() == nameTmp.ToString().Trim())
                {
                    nameTmp = getName();
                    finalName = getNewName(nameSet, nameTmp, times);
                }
                else
                {
                    finalName = nameTmp;
                }
                n++;
            }
            return finalName;
        }
        /// <summary>
        /// 抽取获奖人-getName-宋荣凯-2017年3月14日
        /// </summary>
        /// 通过timer的开关,获取label中的名字
        /// <returns>获奖人姓名</returns>
        public String getName()
        {
            string name;
            timer1.Start();
            Thread.Sleep(100);
            System.Windows.Forms.Application.DoEvents();
            timer1.Stop();
            name = this.lblgetName.Text;
            return name;

        }
        #endregion
       //从dataSet中删去已抽中的人
        public void deletLuky(int reCount)
        {
            for (int rows = 0; rows <= reCount; rows++)
            {
                if (ds.Tables[0].Rows[rows][2].ToString().Trim() == "是")
                {
                    ds.Tables[0].Rows[rows].Delete();
                    ds.AcceptChanges();
                    reCount--;
                    rows--;
                }

            }
        }

 private void timer1_Tick(object sender, EventArgs e)
        {
            if (i > ds.Tables[0].Rows.Count - 1)
            {
                i = 0;
            }
            if (ds.Tables[0].Rows[i][1].ToString() != null)
            {
                this.lblgetName.Text = ds.Tables[0].Rows[i][1].ToString();
            }
            else
            {
                i = i + 1;
                this.lblgetName.Text = ds.Tables[0].Rows[i][1].ToString();
            }

            i++;
          
        }

【总结】

      其实最后成型的这个抽奖算法挺简单也用啥思想, 但是设计过程中思考的时候去重借鉴过选择排序,借鉴过散列表去重等等方法。第一次感觉算法这么有意思。 还是自己实际用到了才能感觉到好处。 感觉非常不错。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 17
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农胖虎-java

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值