点击获取项目文件

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. 在浏览器中打开php文件时,是Linux中的哪个用户执行的?

    https://segmentfault.com/q/1010000002541340 如题,这样我就可以针对这个用户设置权限了.而且这个用户是怎么关联上的,怎么查看? 解答一: .是执行 PHP 指 ...

  2. 自定义属性 —— data-*

    一.基本概念 在HTML5中添加了data-*的方式来自定义属性,所谓data-*实际上上就是data-前缀加上自定义的属性名,使用这样的结构可以进行数据存放.使用data-*可以解决自定义属性混乱无 ...

  3. poj 1085 Triangle War (状压+记忆化搜索)

    Triangle War Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 2685   Accepted: 1061 Desc ...

  4. oralce函数 STDDEV([distinct|all]x)

    [功能]统计数据表选中行x列的标准误差. [参数]all表示对所有的值求标准误差,distinct只对不同的值求标准误差,默认为all 如果有参数distinct或all,需有空格与x(列)隔开. [ ...

  5. 模板—BSGS

    #include<iostream> #include<cstdio> #include<cmath> #include<map> #define LL ...

  6. android学习——android 常见的错误 和 解决方法

    1. Application does not specify an API level requirement! 解决方法:AndroidManifest.xml中 加入: <uses-sdk ...

  7. thinkphp3.2配置redis缓存和文件缓存

    如果把一些常用但又不容易变的数据存缓存,而不是每次查数据库,这样能很大减轻数据库压力 最近由于项目需要,就尝试了一把redis,但是后面又用了tp3.2的文件缓存,直接进入主题: 在config.ph ...

  8. E - D Tree HDU - 4812 点分治+逆元

    这道题非常巧妙!!! 我们进行点分治的时候,算出当前子节点的所有子树中的节点,到当前节点节点的儿子节点的距离,如下图意思就是 当前节点的红色节点,我们要求出红色节点的儿子节点绿色节点,所有绿色的子树节 ...

  9. 关于心跳ajax请求pending状态(被挂起),stalled时间过长的问题。涉及tcp连接异常。

    环境:景安快云服务器(听说很垃圾,但是公司买的,我也刚来),CentOS-6.8-x86_64,Apache,MySQL5.1,PHP5.3. 问题:现公司有一个php系统,需要重复向后台发送ajax ...

  10. tp5 select出来数据集(对象)转成数组

    1.先在数据库配置文件中 //数据集返回类型 'resultset_type' => 'collection', 2.在使用时, 使用 toArray() 方法 //查询数据库 $news = ...