blog of sx.manesking.bread

C/C++,全文搜索,语意分类,图象处理,索引,算法,数据库设计,系统设计

用户操作
[即时聊天] [发私信] [加为好友]
sx.manesking.breadID:manesking
19697次访问,排名6077好友0人,关注者6
没有做不到,只有想不到!
manesking的文章
原创 21 篇
翻译 0 篇
转载 0 篇
评论 58 篇
sx.manesking.bread的公告
好的程序员,就像魔术师。
最近评论
xeranic:有一些不正确:

"B+ Tree" 与 "B-Tree" 的主要区别是是否将数据放在内部节点中,“B+ Tree" 的数据都放在叶子节点中,占用更多空间,但是便于线性访问。"链表指针"也不是"B* Tree"的特色。

"B* Tree" 的主要不同是对于非根节点必须要有2/3m个元素而不是1/2m个元素。另外"B* Tree"的split方式有一些特别。
YGHBIY:的确是这样,我不知道为什么要学C++,只是因为喜欢。
Jackieyd:除了数模,个人认为还有程序设计竞赛,也是非常有挑战性的。有条件的,尽可能都可以去试试
看了博主的文章,回忆起自己参加时候的情景,确实蛮开心的。
Jackieyd:除了数模,个人认为还有程序设计竞赛,也是非常有挑战性的。有条件的,尽可能都可以去试试
看了博主的文章,回忆起自己参加时候的情景,确实蛮开心的。
Jackieyd:除了数模,个人认为还有程序设计竞赛,也是非常有挑战性的。有条件的,尽可能都可以去试试
看了博主的文章,回忆起自己参加时候的情景,确实蛮开心的。
文章分类
收藏
    相册
    08阿里年会
    08口碑年会
    08口碑年会2
    08年元旦
    婚纱照
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky

    原创 三年算法总结收藏

    新一篇: static的全部用法 | 旧一篇: 关于内联函数有时候反而影响性能的说法

    (2006-07-21)

    三年算法总结

     

    1.图象去噪

           描述:祛除由扫描仪获得的文字图象的噪声,不能破坏文字,对扫描不清晰的文字还要做加强;

           难点:没有特别难的,关键是要了解图象处理的知识,数学形态学的算法,这些原理和算法到处都有,如果不知道这些,那就是很难很没有头绪的问题;唯一有点难度的,是对一类面积较大的斑点噪声做处理时,如果选择区域填充的方法,那么就要考虑函数递归会导致栈逸出的问题,所以实际的代码不可能象书上写的伪代码那么简单;

           方法:在多数为了节约代码和使程序看起来简单的情况下,我们都不能使用递归,宁愿选择过程的复杂和代码的难看,自己在堆上写个堆栈、链表、队列这些数据结构来缓存算法的中间过程,否则你会吃苦头的!无法保证有限深度的递归都不能用,这是我的经验!

     

    2.数字图象的水印

           描述:不是给图象打LOGO,而是在图象中添加“看不见”的隐藏信息,要求图象经过多次变换、复制、传递后仍能保持这些信息,具有防篡改和不可抵赖性;有两个用途:一是鉴别这个图象是否被篡改了,甚至可以知道是在图象的哪个区域被篡改了;二是识别这个图象的版权信息,引用这个图象的机构或人无法在不破坏图象的情况驱除版权的信息;这就是与图象生死帮定的一个烙印,我测试过,直到把图象变成一张白纸,这个信息才能被完全破坏;

           难点:原理没有什么难的,都是大家知道的,利用DCT或小波变换,我实际使用的是DCT变换,这和JPEG的压缩算法本质是一样的;难点是里面包含对俘点数矩阵的乘法,这是主要的计算量,如果是批量处理图象,就会很影响性能;因为通常对一幅图象加水印,也是要做个进度条的;

           方法:我没有采用JPEG经典的蝶型算法,还是老老实实做了乘法,只不过是把俘点数矩阵乘法变成了整数矩阵乘法,完全是技巧,里面要通过移位来保证数值不逸出,在外部看来仍然是浮点数乘法;

           还有值得一提的是,要将水印数据写在图象最敏感的区域,比如轮廓的边界上;而不是那些肉眼感觉较弱的区域,如平滑区域;

     

    3.在图象中画多边形,然后显示出来;

           描述:给报纸的扫描图象,在鼠标点击其中一篇文章后,将这篇文章的范围用多边形围起来;如果点了另一篇文章,就要将前一篇的多边形洗掉,再画下一篇的;(多边形的坐标是由外部传入的)

           难点:最简单的思路是,每次在内存中复制一份原始图象的副本,在副本上画多边形,然后将副本显示出来;但是当图象很大时候,复制副本变成了不可能,实际的报纸扫描图象在转为位图后>200MB(它的分辨率太高了),如果再复制一份,那你一个图象显示控件就要占用>400MB的内存;而且在鼠标改变点击区域后,总是要做一次内存复制;

           方法:方法一,实现了一种缓存图象,将图象同时保存在内存和磁盘中,对要处理的局部进行交换,这个可以有效地控制内存使用,但由于在滚屏的时候要做磁盘和内存的交换,浏览图象还是会有所停顿,所以还是放弃了;方法二,直接在原图上画多边形,最关键的是原图还可以从修改后的图象原样恢复,而且运算量极小,这是秘密!

     

    4.文本自动分类

           描述:通过让计算机对一批已由人工分类的语料进行学习,来对更多的文本内容进行自动分类;

           难点:算法是现成的,采用向量机和统计学原理,难度是如何在分类层次增加的情况下保持准确性,相信这是多数基于树型结构的算法都会遇到的问题;还有就是如何支持让一个文本能同时属于多个分类;

           方法:将原来的一个向量展开为多个向量,道理其实很简单,你的分类结构是树型的,那么你的向量结构也应该是树型的;要支持多个分类,只要增加求解分支,把第23解也求出来就可以了,但是绝不能到最后把所有子类的权重去排序一把,那个时候最靠前的一组解,极大的可能是属于同一个父类的,没有实际意义;

     

    5.基于词集的文本自动分类

           描述:利用预先定义的分类词典来做文本的语意分类;

           难点:关键是速度;

           方法:比基于机器学习的算法简单,关键是采用什么样的词查询算法,达到整体上词匹配比较的最快;

     

    6.文本摘要提取

           描述:不是基于语意的;就是根据关键字,截取若干内容形成一段摘要,显示在检索命中的页面上,就象Google里那样的;

           难度:尽可能多地包含关键字;如果命中多个不同的关键字,尽可能多地出现不同的关键字;文字尽可能连贯;还是希望能体现一些语意;祛除正文中的HTML标签,祛除广告和没有意义的文字;

           方法:小算法,有耐心都可以做好;

     

    7.全文检索中的相关度计算与排序

           描述:在全文检索中增加相关度的测量,并要让结果集按照相关度值排序;

           难点:在已经成熟的算法中增加一个属性,代码的修改是要贯穿整个算法过程的;其次是相关度值的计算公式,它必须是满足一定的封闭性的;

           方法:主要是看前人写的代码比较难,通过这个任务我完全掌握了全文检索的原理;

     

    8.数据库服务进程

           描述:将原来的多进程服务模式改为多线程;

           难点:程序进入多线程,就象物体进入纳米世界一样,是具有另一种特性,遵循另一种原则的世界,这是我的感受;很多危险的问题浮现了出来,内存的泄露,句柄的泄露,死锁、冲突、异常,还有内存的非法访问;

           方法:你必须要允许你的程序出错,对于整体代码>10万行的系统,企图DEBUG所有的错误是幼稚的,往往在发生错误的情况下,如何恢复,如何继续运行,如果自己牺牲了而不拖累其它模块,这些问题比真正去解决所有的BUG更现实,也更难;调试BUG是技术上的难度,错误处理是设计上的难度;而且,错误处理往往可以以较少的代码屏蔽较多的错误,解决问题的时间也比调试一个深层BUG要少;调试的难度是于代码的总量成正比的,但错误处理的机制可能是不依赖代码量的,或者相对于复杂系统,它甚至是很简单的;

           所以,解决多线程的问题只是一套有效合理的错误处理机制而已;至于它具体是什么,我不会告诉你的!

     

    9.在数据库服务器重起后恢复前次超级用户的状态

           描述:如果服务程序由于某些原因挂了,或者退出了,那么要求在下次启动后恢复在线超级用户客户端的状态(如果那个时候它们还在的话);

           难点:如何去保存这些要被恢复的用户的状态信息;

           方法:用一张共享内存表去保存就可以了;这件事我学会了使用WINDOWS的共享内存和信号灯;现在UNIX的我也会用了;

     

    10.数值与日期类型字段排序

           描述:非常奇怪的事,原来的排序算法竟然没有利用索引,而是使用最原始的方法,把所有命中记录的该字段的值都取出来,然后qsort

           难点:如何利用索引来排序,索引是根据键值排序的记录号全集,而待排序结果集是已按照记录号排序的子集;归纳为一个数学模型就是:序列A是按照P顺序的,序列B是按照Q顺序的,BA的子集,采用一种算法,使得B也是P顺序的;

           方法:秘密;

     

    11.数值与日期类型字段检索

           描述:也没有能够充分利用索引,从表面上看,原来的算法并没有错,但是在合并结果集上却存在很大的冗余,这直接影响了性能;

           难点:这是一个一般人很难看出来的问题,我开始也以为瓶颈在另一个地方,最后还是发现了:要将多个已经排序的小序列,合并成一个按照同样顺序的大序列,你会怎么做呢?如果想到两两合并,而将它做成一个树的归并结构,然后你会用递归,那你就大错特错了!一是不能用递归,虽然它的规模是N*log(N) 的,但当小序列很多的时候,递归的层数仍然是无法控制的;二是增加了冗余的内存分配与复制,这种冗余是以几何级增长的!

           方法:怎么办?这个时候用qsort在一组内存中排序就可以了,绝对比合并树快(事实证明)!还有一种算法,在这种情况下它肯定比qsort快,qsort的快是偶然(也就是说是依赖具体排序数据的,我们不能保证使用qsort总是那么快的,它提供的是一种平均性能),但是由于太过复杂了,时间原因我最后没有写,当然我也不能告诉你它是什么;

     

    12.多数据库结果合并排序

           描述:在一个结果集中包含多个数据库的命中结果,然后要按照关键字段对整个结果集排序,这是以前没有的功能,原来只能支持到各个数据库的子结果集有序;

           难度:这个包含多库的结果集可能很大,难道要改变>100万的数据集的整体顺序?

           方法:往往第一个想到的方法绝不是什么好方法,不要象傻瓜一样把整个结果集的排序字段值读出来,然后放在一片内存里qsort;那不叫算法!

           我受到了一位同事的启发,他是用Java做前台的,他实现了将分布在不同服务器上的结果集合并排序的方法,由于他无法修改服务器上的结果集,也没有蠢到把上百万的字段值取到客户端去排序,所以他做了一个“假”的合并,也就是保证游标的移动是有序的:先对各个服务器上的结果先排序,然后当需要取这个合并序列的第N条记录时,那就让一组游标从各个服务器的第一条开始,逐个比较,逐个向后进步,比较N次后就是这个序列的第N条记录;而第N+1条是可以在前条基础上垒进的,所以取开始的几页没有问题;但是如果要定位到中间的第50万条,那这个算法就不行了,他必须从各个服务器的第一条开始,逐个比较,逐个移动,说白了,他还是取了50万条数据的字段值;

           而我从他所获得的思想是,合并未必要对整个序列做真实的排序;

           这种合并算法的关键,是在定位所要获得的一组记录的起始位置时,应追求尽可能少的比较次数,即尽可能少的与服务器通信次数;然后对这个算法做分析(我想现在很多程序员都不会去做算法分析,他们只会依靠偶尔的聪明才智去想一些鬼点子,但这些都只是小聪明,而不是大智慧),对完全乱序的序列排序的时间复杂度是N*log(N),在完全乱序的序列中找到第N大的元素的时间复杂度也是N*log(N),而要首先完成对各个数据库各自结果集的排序,时间复杂度已经是N*log(N),虽然O(N*log(N)+N) = O(N*log(N)),但是你相信对一个基本完成排序的序列,取其第N大的元素,还需要线性时间的复杂度吗?想到这里我就有一种感觉,一定有一个低于O(N)的算法,虽然这个时候我还不知道它是什么,但我知道它存在的可能性很大;比O(N)小的也只有O(log(N))!然后向这个方向去想,很快就想出来了(但我还是不会告诉你);

           所以,有的时候你想出一个以为很快的算法,但其实存在着更快的算法,如果你的算法的计算性能你还能接受的话,那么你就永远也不知道还有更好的方法;有的时候你想出一个算法,但是却不知道它到底是不是最快的,如果它的性能尚未令你满意,那你就还会去拼命想别的算法,其实你是在浪费时间;此外,以为可以依靠人的聪明才智或硬件的性能无限提高程序的性能,这种想法也是及其愚昧的!所以,“知道”和“不知道”有的时候是有天壤之别的!要尊重科学!

     

    13.检索缓存

           描述:将最近一次或几次的检索命令与命中结果缓存在全局的内存中,供后续具有相同检索命令的请求使用(省去了后续请求的实际检索开销);

           难点:没有太难的,主要是要找准代码插入位置,大块地跳跃代码,确保使用缓存的请求与正常请求最后的状态完全一致;

           方法:全世界人民都知道的方法;

     

    14.一个键值索引算法

           描述:依靠自己在检索领域的丰富经验,已经可以独立设计一个索引-检索算法;所谓键值,指的是具有比较传递性的关键值,比如:数值、时间日期、短字符串等等;

           难点:针对记录数在千万(以上)乃至亿级的数据库;

           方法:理论上已成形;没有使用B树,因为平衡的缘故;在千万级,>99%的插入、更新、删除在常数时间内完成,磁盘吞吐量与次数也是常数,<1%的情况是前者的两倍(还是常数);空间膨胀率<=2.0;支持设计者无法了解的压缩和加密算法,但嵌入压缩和加密算法的人也无法了解索引的秘密;

     

     

    发表于 @ 2007年02月08日 15:41:00|评论(loading...)|编辑

    新一篇: static的全部用法 | 旧一篇: 关于内联函数有时候反而影响性能的说法

    评论

    #xingfu9966 发表于2007-09-27 12:06:51  IP: 61.185.246.*
    还是好多算法没有研究过,好好学习呀!
    #heromanji 发表于2007-10-25 23:10:14  IP: 61.150.43.*
    好像我们学校计算机系的研究生做这方面比较多一些。我们学校还就是图形图像方面做的不错!Northwestern Polytechnical University~~
    发表评论  


    登录
    Csdn Blog version 3.1a
    Copyright © sx.manesking.bread