菜鸟谈算法和数学对写程序的影响

  首先声明,本人在数学和算法上没什么造诣,只是发表一下自己的观点吧,最近一段时间在学习算法。引用一下我大学的时候的一位老师(刘伟)的一篇文章,这是他在CSDN上的一篇文章,他也一直是我人生中的偶像。http://blog.csdn.net/lovelion/article/details/1350127

  因为自己进公司的以来,一直从事的是C#和JAVA方面的开发,而且框架都是调用公司的框架,所以一直感觉数学在编程当中不起到什么作用。PS:不是数学的作用不大,而是自己确实对这方便很菜,所以才会有这么短浅的认识。直到自己看到了某位大神写的破解游戏源文件的代码居然是用C#写的,才意识到无论是什么语言,数学,算法,逻辑,都是非常重要的。先贴一段让我觉得头晕的代码吧,当然我现在看好一些了,没那么头晕了,不过C#代码居然可以这么写,当时我是震惊了。

  具体的思路我给大家介绍一下,下面的方法其实就是重新建立文件的一个方法,也就是说,这个程序想要实现一个给游戏文件打补丁的功能,比如游戏更新了,你不可能重新下载客户端,肯定是打补丁,而下面方法,建立临时的文件,把临时文件里的内容填充。

   private string RebuildFile(BinaryReader reader, string fileName, string tempDir, string msDir)
        {
            string tempFileName = Path.Combine(tempDir, fileName);
            EnsureDirExists(tempFileName);
            uint oldCheckSum0 = reader.ReadUInt32(); //旧版本文件hash
            uint newCheckSum0 = reader.ReadUInt32(); //新版本文件hash

            FileStream oldWzFile = new FileStream(Path.Combine(msDir, fileName), FileMode.Open, FileAccess.Read);
            uint oldCheckSum1 = CheckSum.ComputeHash(oldWzFile, (int)oldWzFile.Length); //旧版本文件实际hash

            PrintMsg("正在检查旧文件版本 " + oldCheckSum1);

            long curPos = reader.BaseStream.Position;
            int newFileLength = CalcNewFileLength(reader);

            PrintMsg("检测新文件长度 " + newFileLength + " bytes");

            try
            {
                VerifyCheckSum(oldCheckSum0, oldCheckSum1, fileName + "[old]");
            }
            catch
            {
                if (oldWzFile.Length == newFileLength && oldCheckSum1 == newCheckSum0) //文件已更新的场合
                {
                    oldWzFile.Close();
                    PrintMsg("文件已经为最新 补丁跳过");
                    return null;
                }
                throw;
            }

            int cmd;
            int blockLength;
            FileStream tempFileStream = new FileStream(tempFileName, FileMode.Create, FileAccess.ReadWrite);
            reader.BaseStream.Seek(curPos, SeekOrigin.Begin);

            PrintMsg("正在重构文件");

            while ((cmd = reader.ReadInt32()) != 0)
            {
                switch ((uint)cmd >> 0x1C)
                {
                    case 0x08:
                        blockLength = cmd & 0x0fffffff;
                        MoveStream(reader.BaseStream, tempFileStream, blockLength);
                        break;
                    case 0x0c:
                        blockLength = (cmd & 0x0fffff00) >> 8;
                        byte byteData = (byte)(cmd & 0xff);
                        FillStream(tempFileStream, blockLength, byteData);
                        break;
                    default:
                        blockLength = cmd;
                        int startPos = reader.ReadInt32();
                        oldWzFile.Seek(startPos, SeekOrigin.Begin);
                        MoveStream(oldWzFile, tempFileStream, blockLength);
                        break;
                }
            }

            PrintMsg("正在检查新文件版本");

            tempFileStream.Seek(0, SeekOrigin.Begin);
            uint newCheckSum1 = CheckSum.ComputeHash(tempFileStream, (int)tempFileStream.Length); //新生成文件的hash
            VerifyCheckSum(newCheckSum0, newCheckSum1, fileName + "[new]");

            oldWzFile.Close();
            tempFileStream.Flush();
            tempFileStream.Close();

            PrintMsg("创建临时文件 " + tempFileName + ",文件长度 " + newFileLength + " bytes");
            return tempFileName;
        }

  

其中上面的方法有一部分我是醉了。就是上的那个WHILE循环里面的东西,反正我是很难看懂。下面的是上面WHILE循环中要用到的方法。或许看到这里,我说的话还不具有说服力,不过以我的理解也就只能到这里了,大家还请见谅哈。

        private void MoveStream(Stream src, Stream dest, int length)
        {
            byte[] buffer = new byte[0x8000];
            while (length > 0)
            {
                int count = src.Read(buffer, 0, Math.Min(buffer.Length, length));
                if (count == 0)
                    break;
                dest.Write(buffer, 0, count);
                length -= count;
            }
        }

        private void FillStream(Stream stream, int length, byte data)
        {
            byte[] buffer = new byte[length];
            for (int i = 0; i < length; i++)
            {
                buffer[i] = data;
            }
            stream.Write(buffer, 0, length);
        }

  于是在这之后。。。我买了大量的数学书,比如微积分,离散数学,还有2本没到的(路上),分别是线性代数和概率论与数理统计。当然了,我自己个人也挺喜欢学数学的,只是看的时间不长而已,总共才3个月吧,满打满算,还是在工作之余才看的。

  不过对我触动最大的,还是那本《算法导论》,如果没有算法导论,估计我对编程的认识只会停留在调用别人(公司的大神)写的方法那么简单了吧?!其实很想写一些算法的总结出来,但是心里面一想,觉得自己肚子里没什么货,还是算了。不过打个比方吧,以前在写C#代码的时候,不是经常要用到递归算法吗?相信大家对递归算法应该不陌生吧,其实我以前对递归的认识只有一句话:自己调用自己。

  好吧,自己调用自己确实是对的,但是怎么才能写好递归算法呢?其实递归属于一种“分治策略”,分解,解决,合并,递归算法必须要有一个递推公式,不说复杂的,大家中学应该都学过等比数列或者等差数列吧,这当然是一种最简单的数列了,而递归其实就是应用了一个类似通项公式的东西,只是每次给出的形参不同而已,而我们就是要寻找这个通项公式,说白了,就是数学,哈哈。书中还提到了一个很特殊的东西 - 最坏运行时间或者最好运行时间,我们其实从名字可以听出一点端倪,不同的算法决定了这个程序,这段代码的执行效率,可见算法的重要性显露无疑。当然,这次我不太想去解释某些算法的重要性(原因是自己也才看这本书,只是个人觉得很重要而已)。

  上面举了递归算法,那么下面我们再来说一下排序,不拿指针说事,就拿最简单的线性存储结构:数组来说吧,如果我们想要明白各种排序的优缺点,我们需要算法的支持,需要对数学的了解,比如插入排序,冒泡排序,堆排序,归并排序,当然这里具体的方法大家如果有兴趣的话可以上网查,我自己也学得半拉子水吧,不过我觉得这些东西想当的重要,有些人说这是些很简单的,我不这么认为。因为自己大学的时候,老师没教过,也没有重视过这些东西。

  下面是一个讨论的话题,也是我自己想到的,就是:计算机培训学校是不是应该重视数学修养的培养?可能大家看到我这篇文章有点疑惑,这些东西你们大学没学过吗,老师没要求吗?我可以告诉你,我真的没学过这些东西,原因就是我大学上的是一个类似培训学校(北大青鸟)之类的学习出来的,我感觉这些学校和正规的本科院校有一点差别,就是培训学校比较注重人的动手能力,所以很多人,只要认真学了,都可以把一样东西做得很好,但是我们没有(或者说是不列入毕业考核)数学这门课,甚至连算法这门课都没有,我现在已经工作了,好多算法方面的东西还是很差的,虽然暂时也看不出来有什么不好,在我住的旁边,新开了一个IT培训学校,我有时候在想(勿喷),有时候计算机行业在20年前,基本上都是用C,汇编,那时候的程序员也很少,计算机技术也不发达,而现在计算机的从业人员已经突飞猛进了,但是门槛却越来越低,很多人可以不用学,甚至一辈子可以不用学习那些20年前程序员们的必修课(数学,算法)等等,这究竟是一种进步,还是退步呢?

  好吧,本文只是一个工作一年的小菜鸟,在一个不如流的软件公司的一个边缘化的部门里工作的人写出的一篇不怎么好的文章,如果有错,还请批评指正。

时间: 2024-10-12 13:55:22

菜鸟谈算法和数学对写程序的影响的相关文章

讨论:写程序到底需不需要懂数学?

数学系所学的数学,跟一般人所会用到的数学不太一样.研究所顺利考上的向往已久的资工所,成为名符其实的本科系学生,本以为可以不用再玩数学了,但我发现我错了,是不用再玩那些抽久的高等数学没错,但线性代数.机率统计.离散数学等...用了更多的数学,我想不出来有哪门资工研究所的课没用到数学的.写程序需要数学吗?  写程序到底需不需要懂数学? piggy | 08 Jun, 2007 17:26 数学对于程序设计师来说到底重不重要?!类似这样标题的讨论,在网络上已经不知道被讨论多少次了.前两天又在老同事小白

数学知识对写程序有用吗?

对于这个标题,答案我是持肯定态度的,有的人可能说数学一般用于解决一些高端算法,我们测试脚本,哪用得上啊,其实也不然,适当的思考,适当的运用一些数学知识,可以使我们的测试脚本更加的有档次,效率也会更高,或者说也会更加易懂,我们来看一下下面这个方法: 计算从1加到100的值. 估计我们做测试的,很多人第一眼想到的就是用一个for循环,然后sum +=i; 这样就可以得出值了,有的人还可以再加以改善后,搞成一个通用的方法,可以计算任何连续块的值.这些都是OK的,都可以得出结论,但是,换个思路,如果用到

算法浅谈——人人皆知却很多人写不对的二分法

本文始发于个人公众号:TechFlow   1  二分法可以说是鼎鼎大名,哪怕是没有学过编程的同学,也许说不上来二分法这个名字,但是对于其中的精髓应该都是有所了解的.不了解的同学也没关系,我一句话就能交代清楚:我们每次将一个集合一分为二,每次舍弃其中一半.早在两千多年前,庄子就搞清楚了二分法的精髓,他说:一尺之棰,日取其半,万世不竭.从这个角度来说,二分法可能是这个世界上最古老的算法之一了.二分法不仅古老,而且在计算机系统当中非常常见,许多系统当中都用到了二分法的思想.除此之外,在面试的时候,二

《逆袭大学》文摘——9.5 用算法和数学奠定专业基础

有不少读者给我来信,咨询的是关于数学和算法对学习计算机的意义.这样的话题,在我的专栏中很多文章里都提到过.在拙作<逆袭大学--传给IT学子正能量>中,在这方面写了不少文字,现将其中的9.5节全文摘录在此文中,以供参考. 更多话题,见<逆袭大学--传给IT学子正能量>全书目录. 9.5 用算法和数学奠定专业基础 一个程序设计的初学者,在刚刚开始学习时,会认为编程中语言是最重要的.没有语言,没有掌握好编程语言,写不出程序来.而后又知道熟练运用语言仅仅是学会了一种表达的方式而已,如同一个

思考程序与写程序的关系

首先引用孔夫子的一句话:学而不思则罔,思而不学则殆. 首先,学而不思者罔这句话的意思就是如果做一件事情,我们只是为了完成任务才去做这件事情,如果我们不对问题进行思考,那么我们就会感觉知其然而不知其所以然. 思而不学则殆这句话就是,如果我们不动手去做,而一味的去思考结果,那么就会在一个点停滞不前. 其实我很赞成孔夫子的话,我个人认为这2句话很适合编程的人,当然“学而不思者罔”这句话,我个人觉得更适合于我们程序员. 其中造成学习而不去理解它的原理有几点原因. 任务本身的进度很赶,没时间去研究那么深刻

浅谈算法和数据结构

: 一 栈和队列 http://www.cnblogs.com/yangecnu/p/Introduction-Stack-and-Queue.html 最近晚上在家里看Algorithems,4th Edition,我买的英文版,觉得这本书写的比较浅显易懂,而且“图码并茂”,趁着这次机会打算好好学习做做笔记,这样也会印象深刻,这也是写这一系列文章的原因.另外普林斯顿大学在Coursera 上也有这本书同步的公开课,还有另外一门算法分析课,这门课程的作者也是这本书的作者,两门课都挺不错的. 计算

浅谈算法和数据结构(1):栈和队列

浅谈算法和数据结构(1):栈和队列 2014/11/03 ·  IT技术                                         · 2 评论                                      ·  数据结构, 栈, 算法, 队列 分享到: 60 SegmentFault D-Day 2015 北京:iOS 站 JDBC之“对岸的女孩走过来” CSS深入理解之relative HTML5+CSS3实现春节贺卡 原文出处: 寒江独钓   欢迎分享原创

浅谈算法和数据结构: 十 平衡查找树之B树

转载自 http://www.cnblogs.com/yangecnu/p/3632027.html 浅谈算法和数据结构: 十 平衡查找树之B树 前面讲解了平衡查找树中的2-3树以及其实现红黑树.2-3树种,一个节点最多有2个key,而红黑树则使用染色的方式来标识这两个key. 维基百科对B树的定义为“在计算机科学中,B树(B-tree)是一种树状数据结构,它能够存储数据.对其进行排序并允许以O(log n)的时间复杂度运行进行查找.顺序读取.插入和删除的数据结构.B树,概括来说是一个节点可以拥

[歪谈]经理该不该写代码?

这个话题我在好几个地方看到过,基本上大家的意见有几种: 1.小公司别说经理,老板都得写(这是在说我吗?) 2.一般到100或200人以上的公司,经理很少会直接参与代码的编写. 3.大公司(BAT?这个就不说了)一般经理级别以上不写代码 4.还有个观点支持率比较多:那就是要看公司是做产品的还就是做项目的.如果是做项目的一来公司肯定不会大,二来做项目的公司经理和员工一起写代码是很正常的:如果是做产品的,那么除了直系部门的经理会适当写些代码,大部分核心模块. 好吧,我先放出一些自己的观点,然后我们再做