点击获取项目文件

1、对项目的分析与初步计划:

  • 起初拿到这个项目是非常懵逼的,因为涉及到很多个人的知识盲区,诸如:C语言文件的操作、命令行参数、Code Quality Analysis工具、性能分析工具Studio Profiling Tools、GitHub……。可以说在这之前根本就没有接触过这些东西。
  • 虽然什么都不会,但不能什么都不做,于是我制定了以下计划:
    • 什么都不管,先写好代码再说。
    • 翻开《C 程序设计(第四版) 谭浩强》学习C文件的基本操作。
    • 百度了解命令行参数。
    • 其他的太缥缈了,走一步看一步啦。

2、具体实现过程:

  • 根据项目要求,我把代码分成“生成数独终局”和“求解数独残局”两部分。
Creat_ShuDu(argv[]);//生成数独终局 
Solve_shuDu(argv[]);//求解数独残局 
  • 生成数独终局:

    • 对于这一部分,我先生成了一个叫“First line.txt”的文本文件。这个文件用来存储所有可能的数独第一排数据,当需要生成数独终局时,就从这个文件里挑一组数据出来完成数独第一行。(写完这句话我才发现我这不是多此一举吗?!根本没必要啊!)
    • 如何生成一个完成的数独终局,这是一个问题。百度上给了多种方法,考虑到自己的能力,最终选择了暴力回溯法。
      • 对于数独中的每一个小格,它只能填写1~9这9个数字,并且每两个小格间都存在着一定的联系,这给我们的回溯提供了依据。
      • 项目要求生成足够的数独数目。一次性生成多个数独,我可以先写只生成一个数独终局的代码。
      • 从某一小格的某一种可能出发, 搜索从这种情况出发所能达到的所有可能, 当这一条路走到” 尽头 “或者这条路失败的时候, 再倒回到上一步, 从另一个可能出发, 继续搜索. 直到得到足够的终局。
  • 求解数独残局:
    • 其实写完了“生成数独终局”,再写求解部分是非常简单的,因为他们的主要算法都是回溯。唯一的不同就是求解的时候,有些位置已经有了确定的数字。

3、关键代码说明:

  在整个项目代码中最重要的代码当属judge(int i, int j)函数。

int judge(int i, int j)  //搜索第( i , j )位置处可以存储的数字,找到解则返回1,否则返回0
{
     || j > ) ;//搜索结束
    ; k <= ; k++)
    {
        ;                // can 变量用于记录数字k能否放在 ( i , j ) 处
        ; m < i; m++) // 检查同一列是否出现过数字k
        {
            if (shuDu[m][j] == k)  //该列出现过数字k
            {
                can = ;
                break;
            }
        }
        )
        {
            ; n < j; n++) // 检查同一行是否出现过数字k
            {
                if (shuDu[i][n] == k)  //该行出现过数字k
                {
                    can = ;
                    break;
                }
            }
        }
        )                     // 检查在3×3的小方格中是否出现了同一个数字
        {
            ) *  + ; // (i,j)方格所在的3×3小方格i坐标的上限
            ) *  + ;  // (i,j)方格所在的3×3小方格在j坐标的上限

             == ) up1 = i;   //这是针对特殊情况的处理
             == ) up2 = j;

            ; p <= up1; p++)  /* 检查在3×3的小方格中是否出现了同一个数字 */
            {
                ; q <= up2; q++)
                {
                    if (shuDu[p][q] == k)
                    {
                        can = ;
                        break;
                    }
                }
            }
        }
        ) //can==1说明数字k可以放在该位置上
        {
            shuDu[i][j] = k;
            )
            {
                ) == ) ;  /* 到同一行的下一位置开始搜索 */
            }
            else
            {
                )
                {
                    , ) == ) ;   /* 到下一行的第一个空格开始搜索 */
                }
                else
                {
                    num++;
                    if (num<numbers)
                    {
                        Print_shuDu(num);
                    }
                    else
                    {
                        Print_shuDu(num);
                        ;   /* i >= 9  && j >= 9  , 搜索结束 */
                    }
                }
            }
            shuDu[i][j] = ;  /* 关键这一步:找不到解就要回复原状,否则会对下面的搜索造成影响 */
        }
        else continue;//继续尝试其他数字
    }
    ;  /*  1到9都尝试过都不行,则返回递归的上一步 */
}

    这段代码使用的是典型的回溯法。弄懂了这个函数,再写求解数独残局的函数就变的相当简单了。

4、代码优化:

  • 因为我使用的是暴力回溯法,所以能够优化的地方确实不多。我主要优化的是“数独输出函数”。 
void Print_shuDu(int n) //数独输出函数 
    • 起初我通过 fprintf() 函数将数据输出到文件,测试时输出1000000个数独终局需要近2分钟的时间。
    • 后来我将这个函数改成 fputc()的输出方式,运行速度大大加快,对于1000000个数独只需 30左右,缩短了近四分之三的时间。
    • 对此,我特意百度了一下原因。感兴趣的伙伴可以看看。https://blog.csdn.net/slimfox/article/details/1092709

5、后期各种测试:

  • 性能分析如下:

    •   
  • CPU使用率如下:
    •   

6、项目收获:

  • 最大的收获当然是第一次基本独立完成了一个项目,虽然项目很小,做出来的东西很辣鸡。

  • 将该文一开始提到的各种知识盲区大致熟悉了一遍,为以后的学习提供了方便。
  • get到了一些小东西:
    • fputc()比fprintf()快
    • 在VS中scanf要写成scanf_s,为了更安全
    • 在VS中输入一个字符串应写成  scanf_s("%s",s1,sizeof(s1));
    • 在VS中打开一个文件应这样写  fopen_s(&fp, "sudoku.txt", "w");

附:PSP2.1表格

PSP2.1

Personal Software Process

Stages

预估耗时(分钟)  实际耗时(分钟) 
Planning  计划  60 120 
.Estimate  估计这个任务需要多少时间  2000  1500
Development  开发  200 300 
.Analysis  需求分析(包括学习新技术)  30 60 
.Design Spec  生成设计文档  60  40
.Design Review  设计复审(和同事审核设计文档)  60  30
.Coding Standard 代码规范(为目前的开发指定合适的规范)   120  100
.Design  具体设计 60 60 
.Coding  具体编码  200  300
.00Coed Review  代码复审  30 60 
.Test  测试(自我测试,修改代码,提交修改)  60 180 
Reporting  报告  60 120 
.Test Report  测试报告  30 60 
.Size Measurement  计算工作量 30  40 

.Postmortem & Process

Improvement Plan

事后总结,并提出过程改进计划  30  30
           合计    3030  3000

个人项目之数独的生成与数独残局求解——C语言实现的更多相关文章

  1. [2017BUAA软工]第一次个人项目 数独的生成与求解

    零.Github链接 https://github.com/xxr5566833/sudo 一.PSP表格 PSP2.1 Personal Software Process Stages 预估耗时(分 ...

  2. 聊聊 Web 项目二维码生成的最佳姿势

    在设计和实现的过程之后,你永远不知道部署上去的程序会已什么样的姿势运行. 本篇借一次生成二维码逻辑的不同实现,阐述 Web 项目中二维码生成的正确姿势. 文中如有批量,欢迎各位看客老爷拍砖.试运行前5 ...

  3. vue项目通过webpack打包生成的dist文件放到express环境里运行(vue+webpack+express)

    1.首先需要的原料肯定是vue打包生成的dist文件 在vue项目目录下运行:npm run build,等待运行结束,会在项目目录下生成一个dist文件夹,里面会生成一些文件(如下图示) 小的项目文 ...

  4. 在定制工作项时,把“团队项目”作为变量获取生成版本信息

    有用户最近提出这个需求: 通过工作项定制,新增一个字段用以保存项目Bug的"影响版本"信息,但是需要从当前团队项目的服务器生成纪录中获取版本的选项,类似默认模板中的"发现 ...

  5. GNU大型项目构建和覆盖率生成(第一篇)

    目录 0. 序言 1. 项目描述 2. 项目构建 2.1 编译规则 2.2 构建过程 3. 覆盖率分析 0. 序言 在开始正文之前,请允许我先说明一下本文的目的和写作的动机,好让读者不惑. 我们知道, ...

  6. ABP项目中使用Swagger生成动态WebAPI

    本文是根据角落的白板报的<使用ABP实现SwaggerUI,生成动态webapi>一文的学习总结,感谢原文作者角落的白板报. 1 安装Swashbuckle.core 1.1 选择WebA ...

  7. Android Studio] Gradle项目中添加JNI生成文件(.so文件)

    转:http://blog.csdn.net/qiujuer/article/details/24209457 为了适应潮流使用Android Studio还是有半年多了! 对于从Eclipse迁移项 ...

  8. 在VS项目中通过GIT生成版本号作为编译版本号

    上一篇博客写了如何在 .Net 项目使用 SVN 作为版本控制工具时生成与代码对应的组件版本号.虽然在公司一直使用 SVN ,但我却对 GIT 情有独钟(可能要归功于那段捣鼓 ROM 的时光),但少有 ...

  9. 米扑科技的开源项目:sitemap-php 自动生成网站地图

    米扑科技旗下的产品,近期正在做SEO网站优化,其中子需求之一是调研实现了网站地图(sitemap.xml) 封装简化了许多功能模块,现在分享出来,源代码可在Github上下载,有简单的示例. Gith ...

随机推荐

  1. Android 高仿微信支付键盘

    现在很多app的支付.输入密码功能,都已经开始使用自定义数字键盘,不仅更加方便.其效果着实精致. 下面带着大家学习下,如何高仿微信的数字键盘,可以拿来直接用在自身的项目中. 先看下效果图: 1. 自定 ...

  2. Uva 10446【递推,dp】

    UVa 10446 求(n,bcak)递归次数.自己推出来了一个式子: 其实就是这个式子,但是不知道该怎么写,怕递归写法超时.其实直接递推就好,边界条件易得C(0,back)=1.C(1,back)= ...

  3. ROS开发过程中遇到:Could not find a package configuration file provided by "qt_build" with any of the following names: qt_buildConfig.cmake qt_build-config.cmake........

    最近在搭建QT开发ROS 界面的环境,遇到了很多问题,参考了很多资料,最后发现有些问题其实没有那么复杂,只是我们对整体环境还不了解,熟悉了以后你会发现有些问题就迎刃而解了. 在这个过程中,我首先新建了 ...

  4. jmeter日期处理beanshell(2)

    import java.text.SimpleDateFormat;import java.util.Calendar;import java.util.Date;import java.text.P ...

  5. 解决移动端1px边框问题的几种方法

    1.边框粗细原因 在移动端下设置border为1px,在某些设备上看比1px粗. 这些由于不同的手机有不同的像素密度.在window对象中有一个devicePixelRatio属性,他可以反应css中 ...

  6. @总结 - 7@ 生成树计数 —— matrix - tree 定理(矩阵树定理)与 prüfer 序列

    目录 @0 - 参考资料@ @0.5 - 你所需要了解的线性代数知识@ @1 - 矩阵树定理主体@ @证明 part - 1@ @证明 part - 2@ @证明 part - 3@ @证明 part ...

  7. HZOJ 旋转子段

    作者的正解: 算法一:对于30%的数据: 直接枚举区间直接模拟,时间复杂度O(N3). 算法二:对于60%的数据:枚举旋转中心点,然后再枚举旋转的端点, 我们可以用O(n)的预处理求前缀和记录固定点, ...

  8. 5、nginx配置

    1.安装 sudo apt-get install nginx 2.启用 sudo service nginx start 3.若要将 Nginx 配置为转发请求向 ASP.NET Core 应用程序 ...

  9. Ant design在vue,react的引入

    文章地址: https://www.cnblogs.com/sandraryan/ 最近由于 一些不可描述的原因 要研究一下Ant design这个前端框架. 祭上官网: https://ant.de ...

  10. ubuntu14.04本地域名服务器配置

    dnsmasq 1 修改dnsmasq配置文件/etc/dnsmasq.conf # Change this line if you want dns to get its upstream serv ...