数据处理算法设计要点
Upcoming SlideShare
Loading in...5
×
 

数据处理算法设计要点

on

  • 1,860 views

 

Statistics

Views

Total Views
1,860
Views on SlideShare
1,745
Embed Views
115

Actions

Likes
0
Downloads
26
Comments
0

4 Embeds 115

http://blog.thinkinlamp.com 100
http://www.thinkinlamp.com 12
http://static.slidesharecdn.com 2
http://xianguo.com 1

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

数据处理算法设计要点 数据处理算法设计要点 Presentation Transcript

  • 数据处理算法设计要点 上海湃睿信息科技有限公司 祁宏 2010 年 6 月 7 日
  • 概要
    • 这是一个 “教您如何写代码” 的相当初级 TOPIC
    • 因为初级:
      • 比较好批判,拍砖!
        • 欢迎拍砖!
    • 具体讲什么?
    • 数据处理算法设计,也可称为数据转换算法设计。
    • 主要讲解:如何把各类原始的复杂类型的数据(如: HTML ),通过程序处理转换成程序中可用的目标数据形式( CLASS,TREE 等)的一些基本技巧。
  • 同构
    • 爱德华 · 洛仑兹
    • 混沌学
      • 分形几何——局部与整体相似
      • ( 本 PPT 封面——分形几何艺术图形 )
        • 同构
        • 周易八卦
        • 同构是数学的公设
        • 二进制位和——数本身就有同构
  • 同构——人工智能
    • 人工智能——框架结构
    • 代码中的类 class
    • 员工登记表 现实中的框架结构
    • —— 类的目标:是让数据类型与现实事物同构!!
    • 同构的更深的应用:
      • 设计模式
      • 代码重构
  • 信息论
    • 罗伯特 · 申农 信息论
      • —— 信息 = 负熵 = 能量
    • 信息处理的同构
        • 信息载体转换
        • 信息加工
        • 信息传输
    • 数据处理模块结构是普遍的规律
      • 计算器
      • 收音机
      • 计算机及其各部件
      • 印刷机
      • 烧开水( 与计算器一样吗?如何看此同构? )
      • 计算机程序
        • 整个程序
        • 函数
  • 数据处理算法
    • 定义:
      • 把原始数据,处理成程序中需要的目标数据形式或类型!
    • 同构
    • 分形
    • 基本结构:
      • 输入、 预处理
      • 处理
      • 后处理、输出
    • 用途:
      • 基本应用
        • 程序接收外部输入
        • 程序间通信
        • 程序内部函数与函数,类与类之间通信
        • 格式文件操作( HTML , XML ,图片文件二进制模式操作)
        • ……
      • 高级应用
        • 数学公式解析(工资管理,制造设计程序中常用)
        • 人工智能数据分析
        • 商业智能数据处理算法
        • ……
  • 数据处理模块最常见的问题
    • 代码跟着数据走
      • —— 盲目跟着数据走!!
      • 问题造成的后果:
      • 代码量大,算法复杂
      • 不易看懂,不易维护
      • 隐含的 BUG 很难发现
      • 需求不明, SWITHC CASE 的硬编码结构造成不易扩展
      • 非标准的算法,使得代码与程序员的相关性增高,造成程序员离开后,程序难以继续升级。
  • 实例: js 的 FormatNumber
    • 第一种写法, 40 多行代码
    • function adv_format(value,num) {// 四舍五入
    • var a_str = formatnumber(value,num);
    • var a_int = parseFloat(a_str);
    • if (value.toString().length>a_str.length) {
    • var b_str = value.toString().substring(a_str.length,a_str.length+1)
    • var b_int = parseFloat(b_str);
    • if (b_int<5){
    • return a_str
    • } else {
    • var bonus_str,bonus_int;
    • if (num==0) {
    • bonus_int = 1;
    • } else {
    • bonus_str = &quot;0.&quot;
    • for (var i=1; ibonus_str+=&quot;0&quot;;
    • bonus_str+=&quot;1&quot;;
    • bonus_int = parseFloat(bonus_str);
    • }
    • a_str = formatnumber(a_int + bonus_int, num)
    • }
    • }
    • return a_str
    • }
    • function formatnumber(value,num) {// 直接去尾
    • var a,b,c,i
    • a = value.toString();
    • b = a.indexOf('.');
    • c = a.length;
    • if (num==0) {
    • if (b!=-1)
    • a = a.substring(0,b);
    • } else{
    • if (b==-1) {
    • a = a + &quot;.&quot;;
    • for (i=1;i<=num;i++)
    • a = a + &quot;0&quot;;
    • } else{
    • a = a.substring(0,b+num+1);
    • for (i=c;i<=b+num;i++)
    • a = a + &quot;0&quot;;
    • }
    • }
    • return a
    • }
    • 第二种写法, 7 行代码
    • function formatNummber(strnum,digit){
    • if (strnum.indexOf(&quot;.&quot;)==-1)
    • strnum+=&quot;.&quot;;
    • var nil = ((Math.pow(10,digit+1)).toString()).substring(1,digit);
    • strnum += nil;
    • var numf=parseFloat(strnum)+parseFloat(&quot;0.0&quot;+nil+&quot;5&quot;);
    • var snum = numf.toString();
    • return snum.substring(0,snum.indexOf(&quot;.&quot;)+digit+1);
    • }
    • 第三种写法, 1 行代码
    • Js 代码
    • function formatNummber(src, pos){
    • return Math.round(src*Math.pow(10, pos))/Math.pow(10, pos);
    • }
    • 第一种写法 , 这个程序员一定是个学手 , 所以只会程序跟着数据走 .
    • 第二种写法 , 算是个高手 , 因为 , 已会让数据跟着程序走了 . 只用了一个 IF, 并且构建出 &quot;0000&quot; 的字串采用的是数学算法 , 想法独到 .
    • 第三种写法 , 应当是高手 , 则是完全数学的方法 , 因为 , 不必要更多的代码 , 主要是算法的巧妙 , 因为他了解 round 这个函数是化小数为整数的
    • 第二种与第三种均是非常好的算法,实现要求不同。第二种能实现“小数点对齐”!
    大于 5 进 1 ,逐位加过去 构造一个 0.000005,5 前面 0 的个数由程序决定,转成数字加起来。 直接使用 Math.round 函数
  • 原则错误 与 经典实例
    • 代码跟着数据走的原则错误
      • 违反了面向对象的一个重要原则:
      • 依赖倒置原则;
      • 抽象不能依赖于具体
      • 具体必须依赖于抽象
    • 代码跟着数据走的经典实例
      • Zend Framework 中的 DateTime
      • 各类开源的 HTML Parser
      • 各类山寨 PHP 框架的 Controller
      • ( 个人看法,仅供参考!! )
  • 代码跟着数据走错误的根源
    • 对数据预处理没有概念,不清楚数据需要预处理
    • 对数据结构分析不透,不能选择合适的数据类型或数据结构
    • 盲目追求效率,从而丢失了良好的结构。
    • 假如一开始就没有做出好的设计
    • 使用再高的代码重构技术也难以修改到理想的目标
    • 假如把“重构”改为“预构”,结果会如何?
  • 代码不跟着数据走的好处:
    • 代码量少,算法简单
    • 程序易懂,维护方便
    • 将 BUG 阻止到生成之前
    • 需求清析,减少大量的 SWITHC CASE 结构
    • 符合面向对象的依赖倒置原则。
    • 我们的目标,是把设计目标放在编码之前。
    • 先设计,再编码!!
  • 优秀的算法不是拍脑袋空想出来的
    • 为什么他的代码写得这么好?我怎么没想到用这个思路来呢?
    • 需要有科学的设计方法
    • 需要真正把握数据的结构
    • 需要不断总结设计经验
    • 如同武术功夫一样
    • 优秀编码功夫也是练出来的。
  • 让代码不再盲目跟着数据走
    • 数据处理模块实现步骤
      • 数据结构分析
      • 使用符合当前数据的数据类型和数据结构
      • 预处理模式选择
      • 使用合适的数据预处理模式
      • 使用标准的数据处理模块结构
      • 实现算法的编码
  • 数据处理模块结构:
    • 输入 + 处理 + 输出 三段法
      • 输入、数据预处理
      • 核心算法
      • 后续处理、数据输出
    • 以最小的单位结构实现耦合从而实现复杂的输入 + 处理 + 输出
    • 一个函数中,输入 + 处理 + 输出的组合,尽可能不要太多。 CodeIgniter 框架中的函数几乎是单一输入 + 处理 + 输出组合,这是一个好习惯,但也不要完全单一化!
    • 独立成函数的目的 :一是为了公用,二是为了算法替换!
  • 数据处理算法设计的目标
    • 面向对象的目的:
      • 使程序可以编码时配置,运行时配置
      • 使程序结构与现实同构,并使结构层次化
      • ……
    • 使用规范优化的算法的目的:
      • 代码可读性
        • CodeIgniter 中的例子:
        • If(! Is_array($param))
          • $param=array($param);
      • 代码可扩展性
      • 代码可配置性
      • ……
      • NETSCAPE 重生为 FIREFOX ,就是因为他学会了……?????
  • 实例训练:简单实例
    • DMS 转角度
      • DMS 表示方式是: ddd.mmss
      • 这是一个计算器通用表示法。程序接受到这个输入时,必须要进行转换。
      • 传统的方法:
        • 分析其中的情况:
        • ddd
        • ddd.m
        • ddd.mm
        • ddd.mms
        • ddd.mmss
      • 根据上面的情况,至少会用到 5 到 9 个 if 条件判断
      • 如果选择正确的数据类型,合适的预处理:
        • 预处理只要一行: $dms=sprintf(“%08.4f”,$dms);
        • 于是,这个算法只要 2 到 4 行代码即可完成。
  • 实例训练:简单实例
    • 要求:
      • 选择合适的数据类型,
      • 使用简单地格式化方式预处理
    • 1 、根据实际数值,选用 G , M , K , B 作为单位来表示文件的大小
      • 无预处理方法: 4 个 if ,
        • 大于 1G ,用 G
        • 大于 1M ,用 M
        • 大于 1K ,用 K
        • 大于 1B ,用 B
  • 实例:用不同单位表示文件的大小
    • function get_file_size ($file) {
    • if ( ! is_file ($file) ) return 0 ;
    • $file_short_size[ 0 ] = sprintf (&quot;%u&quot; , @ filesize ($file));
    • $unit= array ( &quot;B&quot; , &quot;K&quot; , &quot;M&quot; , &quot;G&quot; );
    • for ($i= 0 ;$i< 3 ;$i++){
    • if ($file_short_size[$i]< 1024 )
    • return $file_short_size[$i].$unit[$i];
    • else
    • $file_short_size[$i+ 1 ]
    • = number_format ($file_short_size[$i]/ 1024 , 2 );
    • }
    • return $file_short_size[ 3 ].$unit[ 3 ];
    • }
    • 这不同于前一实例,前一实例是简单预处理,这一实例也可是称为简单预处理,但内部结构则是由 FOR 循环构成的链式预处理。
  • 预处理程序结构
    • 简单预处理
    • 链式预处理
      • 单一函数
      • 多个函数相链,符合条件时输出
    • 复杂预处理
      • 对象树预处理
      • 函数树预处理
      • 对象树 + 函数树复杂结构
      • 利用设计模式的对象组合与 + 函数树复杂结构
  • 实例训练:复杂实例
    • HTML Parser 从单个函数到类
      • 开源 HTML Parser 现状:
        • domit ,可用的,但代码过于复杂。无法维护与自定义扩展
        • 不支持自定义 attribute ,而现在,无论 HTML4 ,还是 xhtml 均支持自定义 attribute
        • DOM 解析,无法支持中文,总是有乱码问题,并且,总需要文档,要有 charset 标记。
        • 容错性差, attribute 中如果有 <>= 等会出错,脚本中有 <> &quot;<script>&quot; 等会出错
        • 功能弱,解析到数组中,不支持 DOM 操作
        • 大都采用降噪法,即去除 script , style ,或去除 ,使得原有脚本不可读。
      • 总之,达不到浏览器解析的一致水平。
      • 数据本身的问题:引号中有转义引号,脚本中嵌入 <script> 标签
  • 数据结构分析
    • 数据结构分析是设计算法必不可少的一环
      • 前面三例,主要是不能选择正确的数据类型,导致不能找出正确的算法。
    • HTML 数据结构
      • 节点树
        • html 4.01 已是完全无开而不闭的节点,比如 <tr><td></td><tr><td></td></tr> ( 早期 HTML Parser, 主要是考虑兼容 )
        • 节点分类:
          • 有标签节点:自封闭节点,开闭节点
          • 无标签节点:
            • 文本节点,
            • DOM 碎片——将其看成外层有一个无标签节点
      • 节点结构:
      • < 标签 属性表 > 子节点 || 内容 </ 标签 >
  • 数据结构设计
    • class HtmoObject{
    • public $tag = '_frg';
    • private $attributes = array();
    • public $childNodes = array();
    • private $innerDATA = '';
    • public $parent = null;
    • public $hasClosing = TRUE;
    • public $optIndex = 0;
    • public $isClosed = false;
    • }
    • 类设计是构成良好预处理对象树的根本
    • 设计模式:组合模式 + 原型模式
    • 说明:
    • _frg 的妙用:使其对普通节点,文档,文本节点,任一 HTML 碎片均可用此同一类型。 并能方便实现 before after 功能。
    • parent 的妙用:每一条路径均是双向的。
    • private $innerDATA 在 __get __set 中处理访问 innerHTML innerTEXT ,均是对它操作。
    • $childNodes 使得程序可以实现对象方法的调用递归。
  • 预处理范式设计
    • 算法本身也是数据结构
    • 预处理设计方法:
      • 流程图——传统的程序设计方法
      • 伪代码——传统的程序设计方法
      • 预处理范式——适合当前数据结构的通用模式
    • 预处理范式设计方法比流程图更适用于数据处理算法模块
    • 预处理范式设计方法比伪代码更加抽象,更善于处理复杂算法。
    • 如何设计:
        • 分形
        • 同构
  • 预处理范式设计的基本设计步骤
    • 基本设计步骤
      • 数据结构分析
      • 数据流分析
      • 逻辑节点分类
      • 路径设计
      • 逻辑节点行为设计(子函数,子类调用)
      • 逻辑节点范式化 ( 节点模板化 ) (函数合并)
      • 将节点中,程序所用,变化的数据写入到配置文件中
    • 基本技巧:
      • 数据逻辑节点的处理仍是同构方式,即包括
        • 输入 处理 输出
  • 算法范式设计的优点
    • 算法范式设计过程中,能便于我们及时发现问题,使得程序结构调整能在编码之前处理
    • 算法范式设计的文档将是非常好的设计文档
    • 实际编码时,还可以进一步发现算法范式设计中的 BUG ,从而使代码更易测试
    • 算法范式设计的代码多数是软编码,即有大量可以通过配置参数改变的。因此,它就象是一个可控处理机。
      • 结合测试驱动模式( TTD ),则写出的代码质量更高。
      • 编写代码时,可能还要回过来再次修改预处理范式。
  • HTML Parser 数据节点算法范式(山寨版)
    • 图例:
    • T 顶层主函数
    • S 子函数
    • R 字符串读取
    • C 子节点调用
    • M 循环处理多个
    • 数字:
    • 十位表示层级
    • 个位表示处理顺序
    • 设计这一范式的思想是:同构,将不同解析规则的拆分到不同的子函数中。
    • What’s this? 函数树!!
    • - 01 T 节点开始
    • -10 S 前标签
    • 12 R 字符前空
    • 13 S innerText
    • 14 MC 子节点
    • 15 R 标签前空
    • -16 S 后标签
    • 02 T 节点结束
    • - 10 标签开始
    • -20 R/ 标记
    • -21 R 标签名
    • -22 R 后空格
    • -22 M 属性
    • -23 R 后空格
    • -24 R 注释文字
    • -25 R 后空格
    • -26 R/ 结束
    • 10 标签结束
  • HTML Parser 数据节点处理范式(山寨版)
    • - 22 属性开始
    • -31 R 属性名
    • -32 R 等号前空
    • -33 R 属性的 =
    • -32 R 后空格
    • -35 S 属性值
    • 22 属性结束
    • - 35 属性值
    • - 41 R 后空格
    • - 42 S 单双引号
    • - 43 R 属性值文本
    • 35 属性值结束
    • - 42 单双引号开始
    • -51 R 属性值文本
    • 42 单双引号结束
    • - 13 innerText 开始
    • R innerText
    • 13 innerText 结束
    • - 13 innerCode 开始
    • R innerCode
    • 13 innerCode 结束
    • - 24 注释文本开始
    • R 注释文本
    • 24 注释文本结束
  • 主函数—— 30 行代码的主函数,相当易懂
    • public function loadHtml($string, $level = 0 ){
    • for ($i = 0 ;; $i++) { // 解析每一个节点
    • $string = ltrim ($string, &quot; &quot; ); // 去除前面的空白字符
    • if ( strlen ($string) == 0 ) return ;
    • if (($ this ->isClosed == true )&&( substr ($string, 0 , 2 ) == '</' ))
    • return $string;
    • if (($i > 0 ) && ( strlen ($string) > 0 )) { // 如果有平行节点,则要下移,变成平行子节点
    • $newNode = $ this ->cloneObject();
    • $newNode->parent = $ this ;
    • $ this ->reset()->childNodes[] = $newNode;
    • $emptyNode = new wHtmlObject( '_frg' , $ this ->optIndex);
    • while ( true ) {
    • $string = ltrim ($string, &quot; &quot; ); // 去除前面的空白字符
    • if ( strlen ($string) == 0 ) return ;
    • if ( substr ($string, 0 , 2 ) == '</' ) return $string;
    • $newNode = $emptyNode->cloneObject();
    • $newNode->parent = $ this ;
    • $ this ->childNodes[] = $newNode;
    • $string = $newNode->parseNode($string, $level + 1 );
    • }
    • } else {
    • $string = $ this ->parseNode($string, $level);
    • }
    • }
    • return ;
    • }
  • 总结
    • 同构
    • 分形
    • 数据处理模块基本结构
      • 输入 + 处理 + 输出 三段法
        • 输入、数据预处理
        • 核心算法
        • 后续处理、数据输出
    • 数据预处理组合结构
      • 简单预处理
      • 链式预处理
        • 单一函数
        • 多个函数相链,符合条件时输出
      • 复杂预处理
        • 对象树预处理
        • 函数树预处理
        • 对象树 + 函数树复杂结构
    • 基本设计步骤
      • 数据类型分析
      • 数据流分析
      • 逻辑节点分类
      • 路径设计
      • 逻辑节点行为设计(子函数,子类调用)
      • 逻辑节点范式化 ( 节点模板化 ) (函数合并)
      • 将节点中,程序所用,变化的数据写入到配置文件中
  • 课后作业
    • 用 PHP 编写一个数学公式解析程序
      • 要求:
        • 使用逆波兰结构定义数据结构(可以为类、也可以是数组)
        • 支持四则混合运算,同时支持括号与括号嵌套
        • 必须支持所有 PHP 的数学函数
        • 代码行数(据说微软要求,每个函数或方法不得超过 140 行)
    • 为 php 开发框架的 MVC 架构设计控制器算法范式
      • 要求,有 host, uri, user_agent, request_method, ajax 和用户权限检测,有根据以上结果实现模块与视图加载的出口。
  • 并非结束
    • 算法范式是一种全新的设计方法,这里给出的仅是一些基础知识!
    • 我们需要记住的是:
      • 分形,同构是最根本的基础
      • 输入、处理、输出是最基本的结构
    • 开发团队成员数据处理算法设计的基本功直接影响团队开发的软件质量!所以,这也是项目管理的目标之一。
  • 澎湃进取,睿智从容! Contact information: Hot Line: 400-620-9980 Website: www.pisx.com