天天看点

《编程珠玑》读书笔记(三)

《编程珠玑》的第二部分讲的是性能,第三部分讲的是应用,所以我暂时跳过第二部分,直接看应用。

第十一章 排序

排序问题一直是面试的热点!本章首先介绍了插入排序,然后介绍了快速排序,并提出了快速排序的几种改进方法,例如双向划分、随机数划分、以及小范围结合插入排序,三种的性能递增。

排序免不了交换,书中特别指出将swap()函数写入循环中会加速。

插入排序: 稳定,时间复杂度O(n^2),主要代码如下                 [cpp]  view plain copy

  1. for ( i = 1 ; i < n ; i ++ )  
  2. {  
  3.     t = x[i];  
  4.     for( j = i ; j > 0 && x[j-1]>t;j--)  
  5.            x[j] = x[j-1];  
  6.     x[j] = t;  
  7. }  

快速排序: 不稳定;时间复杂度O(nlogn)。

当出现n个相同元素组成的数组时,插入排序性能非常好,总运行时间为O(n),但qsort性能非常糟糕,因此提出改进。

改进二:采用双向划分的方法,代入如下: [cpp]  view plain copy

  1. void qsort3( l , u )  
  2.   if l>=u  
  3.     return  
  4.   t = x[l];  i = l;  j = u + l;  
  5.   loop  
  6.       do  i++  while  i<=u && x[i]<t    //从左往右找到第一个大于等于t的数  
  7.       do  j--  while  x[j]>t           //从右往左找到第一风格小于等于t的数  
  8.       if  i > j  
  9.           break;  
  10.       swap( i , j )  
  11.   swap( l , j)  
  12.   qsort3( l , j-1 )  
  13.   qsort3( j+1 , u )  

改进三:随机元素划分

改进四:快排+插入排序

第十二章 取样问题

本章主要介绍了生成0~n-1区间内m个随机数的三种方法,假设bigrand()函数返回一个随机大整数,例如C库函数rand()返回15位整数。 方法一:bigrand()%remaining<select,时间复杂度O(n)

方法二:C++zhongSTL的set集合,随机生成一个数,插入set中,最后有序输出。用空间换取时间,O(mlogn)

方法三:随机打乱一个数组,输出前m个即可,O(n+mlogn)

第十三章 搜索

本章介绍了5中表示随机整数集合的数据结构:有序数组、有序链表、二叉树、箱、位向量。各自性能如下:

集合表示 初始化操作 insert操作 输出操作 总时间 空 间
有序数组 1 m m O(m^2) m
有序链表 1 m m O(m^2) 2m
二叉树 1 logm m O(mlogm) 3m
m 1 m O(m) 3m
位向量 n 1 n O(n) n/b

有序数组 IntSetArr类 实现于 P129; 有序链表 IntSetList类 实现于 P130; 二叉树    IntSetBST类 实现于 P132; 位向量   IntSetBitVec类 实现于 P134; 箱         IntSetBins类   实现于  P135; 详细代码见《附录E》

本章的边栏介绍了“拼写检查器”的实现。

第十四章 堆

本章首先介绍了堆的性质:一是有序,二是形状,以及用数组来表示堆。

堆的两个关键函数是:siftup()自底向上,siftdown()自顶向下,代码分别实现于P144、P145。

优先级队列(插入和删除操作很频繁)是一种常见的数据结构,主要有三种实现方法:有序序列、无序序列、堆(介于前两者之间的折中方法),三者性能比较如下:

数据结构 一次insert时间 一次extract时间 两种操作各n次时间
有序序列 O(n) O(1) O(n^2)
O(logn) O(logn) O(nlogn)
无序序列 O(1) O(n) O(n^2)

用堆实现优先级队列的代码在P147,建议动手实践!

最后介绍了堆排序算法,分两步进行:建堆+排序,O(nlogn),习题2,3对堆排序进行了改进,暂未明白。 堆排序代码: [cpp]  view plain copy

  1. for i = [2 , n)  
  2.   siftup(i)  
  3. for( i = n ; i >= 2 ; i-- )  
  4.   swap( l , i )  
  5.   siftdown(i-1);  
  6. //x[l]是前i个元素中最大的,将它和x[i]交换使得有序序列多一个元素,因此下移保持堆平衡  

第十五章 字符串

本章主要介绍了三种字符串的应用:

1、生成词典,统计单词的个数,分别用C++和C实现。      C++实现使用了STL的set和map,其实本质是平衡搜索树。      C实现使用的是散列表,比C++速度更快。

2、最长重复字串,用后缀数组实现,O(nlogn),需要额外的n个指针空间。

3、生成随机文本,主要了解k阶文本-->k接马尔科夫链。