编程珠玑 笔记

整数排序

         1千万个数放在文件中,每个整数为7位正整数,最多出现一次,内存只有1M,运行时间10几秒

思考:

1.  如果使用32位Integer存储则需要40M存储空间,远超于内存,则只能使用外部排序。

2.  1M /4B=250K,为一次可在内存中排序的整数个数,则创建 9999999 / 250k 个临时文件,每个文件存储相应范围的整数,如[k*250KB, (k+1)*250KB ] 。

3.  扫描原始文件,将每个整数保存到相应文件中

4.  按顺序对每个文件在内存中做快速排序并写到对应结果文件

5.  按顺序合并结果文件

分析:

         按以上思路需要40读取和写入文件,原因是需要40MB的存储,是否可采用一种合适的表达方式,将10,000,000个数字使用更少的bit来表示,如使用位图或位向量(即n位的二进制序列表示最大值为n的数,当值为i的数存在时,第i位为1)来表示集合,则表示1千万需要1.25MB 存储。这种思路利用了排序数据中不常见的属性:输入数据在较小范围内;数据没有重复;对每条记录无关联数据

解法:

1.      将所有位置零,扫描文件对相应位置1

2.      按顺序校验每一位,如果该位为1则输出相应的整数

总结:

1.      位图数据结构表示有限定义域中的稠密集合,其中的每一个元素最多出现一次,且没有其他任何数据与该数据关联,即使有关联,也可将该值作为更复杂表格的索引。

2.      当需要同时减少空间和时间时,有两个方法:减少处理的数据;保存在内存中。当然了只有原始设计不是最佳方案时才能实现

3.      简单设计:设计不能再减少东西了

4.      如果限定在1M中,则2次遍历,第一次只处理0-4999999,第二次处理5000000-9999999.

5.      每个数字最多出现10次时?   对每个数字使用4bit存放

缺失的1个整数

问题:

         有 1000,000 个整数,每个整数在 0,3000,000之间,每个数只出现一次

解法:

         首先要遍历一遍数据,找出最大数M和最小数N,计算出中位数的大小,然后统计中位数以上和以下的数字个数,选择个数不到(M-N+1/2的一段重复上述的过程。

向量旋转

         N元字符串向左旋转i个位置,如abcdefgh向左旋转 3得到 defghabc。要求几十字节的额外空间,O(n)时间内。类似问题:交换相邻的不同大小的内存块,拖动交换两块内存中的文字。

解法1:

         Forj=0 to i  {

                   t=x[j];

                  for(h=0;i*h+j<n;h++) {

                            X[(h-1)*i+j]=x[i*h+j];  //将 a[3]->a[0]  a[6]->a[3]

                   }  

                   X[i*(h-1)+j]=t;  // t->a[6]

         }

解法2:

         将字符串分成 ab1b2三部分,其中a为前i个字符,b2和a长度相同。先将a和b2交换得到 b2b1a, 则a在正确位置,继续对b2和b1进行递归调用。

程序步骤

1.      问题定义:了解问题的背景,问题的陈述包含了问题的解法,但也别只停留在这种解法中;对问题抽象为通用问题,如3抽象为n

2.      研究输入、输出,选择合适的数据结构

3.      怎么办:针对问题采取哪些基本算法,如排序、二分搜索

4.      考虑尽可能的解法

5.      从多种解法中选择一种实现

6.      完成程序框架后,对性能进行初步估算

性能优化

优化内容

算法和数据结构(选择更高效算法,根据特定问题对算法优化,根据算法构造数据结构) 

代码调优(系统无关的:如实数使用float,系统相关的:如对hot pot使用汇编实现) 

系统软件:数据库(infobright代替mysql)、操作系统等

硬件;  

优化步骤

a) 明确对性能的具体要求

b) 了解当前程序的性能

c) 找到程序的性能瓶颈

d) 采取适当的措施来提高性能

e) 只进行某一方面的修改来提高性能

f) 返回到步骤c,继续作类似的工作,一直达到要求的性能为止。

算法设计技术

问题

         N个浮点数的向量,找出连续子向量中的最大和

思考:

1.      最简单三重循环,计算Aij的值,并记录最大值  ,为O(n^3)

2.      发现Aij的计算中有重复子结构,Aij=Ai(j-1)+aj  为O(n^2)

3.      Aij=A0j-A0i, 为O(n^2)

4.      n^2考虑了所有的子向量,因为存在O(n^2)的子向量,所以至少需要平方和的实现,通过想办法避免监测所有的子向量,获得更短时间的算法,使用分治法,将n分为大小类似的a和b两段,则最大向量为 Aa、Ab、起点在a,终点在b 三种情况的最值,前两种是递归,后一种对于a从 length[a]向前的最大值+b[0]向后的最大值,则F(n)=2F(n/2)+O(n) 为 O(nlgn)

5.      扫描算法:I 0 to n-1 计算从0到i的最大值,该值有两种可能(0, i-1)间和以i结尾, A0(i-1)已经存在,以i结尾的最值 max( maxending+a[i] ) 为 O(n)

技术:

         保存状态,避免重复计算

         将信息预处理到数据结构,如算法3

         分治算法:有可能达到nlgn

         扫描算法:与数组相关的算法一般可通过思考如何将 a[0,i-1]扩展到a[0,i]来实现。

         累积:范围问题,如 3到10月销售额,可通过至10月销售额-至2月销售额

         下界:证明本问题的算法下界

代码调优

代码调优的最重要原理就是尽量少用它,原因如下

         效率的角色:其他特性也很重要,不要轻易优化

         度量工具:找到hotpot进行优化,其他先不动

         设计层面:如果效率重要,在设计时考虑

         双刃剑:是否影响到其他部分

节省空间

简化

         通过仔细研究原始问题,使用一个简单问题替换原始问题,选择另一种数据结构,或者表达方式,如使用稀疏矩阵。

数据空间技术:减少数据所需的存储空间

  不存储,重新计算

  稀疏数据结构

  数据压缩

  分配策略:有时候如何使用空间比使用多少空间更重要,如动态分配,将两个对称矩阵共享同一二维数组

  垃圾回收

代码空间技术: 减少程序本身的规模

     函数定义: 从重复代码中重构出函数

    解释程序: 如海龟图的实现

    翻译成机器语言:用于内存宝贵的系统,如数字信号处理器

原理

    空间开销: 节省空间还是有意义滴,如使用的内存增加10%,则在内存非常小的系统中就不能用了;通过网络传输的时间将增加10%。

    空间热点: 有些格式的数据将占用大部分的内存,应该针对这种格式专门优化

    空间度量: 使用查看内存使用的工具,如profile

    折中:有时候需要牺牲 功能、性能和可维护性,这是最后的办法

    与环境协作:包括编译器、运行时表示方式、内存分配策略以及分页策略

    使用正确的工具: 从 简化、四种数据策略、三种代码策略中选择正确的方法

 

取样问题

N个[0,k]之间随机数

for i =[0, n)

    x[i]= n%k

for i =[0,n)

   swap(i, randint(i, n-1))

   print x[i]

 

三种创新的方法

原创性,

新发现,

用低技术含量的答案来解决高技术含量的问题

 

字符串

最长重复字串

    问题:查找一个文本文件中,出现的最长重复子字符串,要求O(nlgn)时间内

    解法: 使用“后缀数组”的数据结构(字符指针数组 a,a[0]指向整个,a[1]指向第二位开始的,a[2]为第三位到结束),如果某个字符串出现两次,则a[i]和a[j]的前面几位都是该字符串。步骤如下:1. 构造后缀数组;2. 使用qsort进行排序;3.for i 0 to n 从开始比较 a[i] 和a[i+1] 得到重复子字符串,求得其最长值

 

生成文本

生成看起来更像英文的文本

    先读取样本,统计每个字母之后出现的次数;在写随机文本时,使用当前字母的一个随机函数生成下一个字母,这是一节文本,如果使用前面四个字母生成下一个字母就非常类似于英文单词了

在单词级别生成随机文本

    读取样本,对每个单词计数,根据概率选择下一个输出的单词,如果生成下一个单词时考虑前面几个单词的马尔科夫链,则会等到更感兴趣的文本

    

    

算法分类

    排序,应用于:有序输出, 收集相同的项,有 插入排序,快速排序, 基数排序,位图排序(见第一章)

    搜索,应用于:拼写检查器、搜索棋盘得到最优解,有散列、二分搜索树、

    字符串算法

    向量和矩阵算法

    随机对象

 

代码调优法则

空间换时间法则:

        修改数据结构: 根据操作选择数据结构,对数据结构进行扩展和修改

        存储中间结果

        高速缓存

        懒加载

时间换空间法则:

        堆积: 密集存储和压缩通过增加检索时间来减少存储开销

        解释程序: 操作系列以一种紧凑方式表示

循环法则:

        删除赋值: 如果很多开销来自于赋值

        循环合并:两个相邻循环作用于同一组元素

逻辑法则

        等价的代数表达式:如果逻辑表达式开销太大

        测试条件排序: 低开销,经常成功的放前面

        预先计算逻辑函数: 

过程法则

        使用inline或宏替代函数

        高效处理常见情况

        递归函数转换

        并行性

        

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值