master 7fafa61cabdc cached
228 files
11.1 MB
361.5k tokens
417 symbols
1 requests
Download .txt
Showing preview only (818K chars total). Download the full file or copy to clipboard to get everything.
Repository: julycoding/The-Art-Of-Programming-By-July-2nd
Branch: master
Commit: 7fafa61cabdc
Files: 228
Total size: 11.1 MB

Directory structure:
gitextract_a78wrx3g/

├── .gitignore
├── Readme.md
└── ebook/
    ├── build/
    │   ├── Makefile
    │   ├── README.md
    │   ├── book.json
    │   ├── metadata.yaml
    │   └── style.css
    ├── code/
    │   ├── c/
    │   │   ├── 1.1:左旋转字符串.c
    │   │   ├── 1.2:字符串是否包含问题.c
    │   │   ├── 1.3:带通配符的字符串匹配问题.c
    │   │   ├── 1.4:字符串转换成整数.c
    │   │   ├── 1.7:字符串的全排列.c
    │   │   ├── 10.1.3:教你一步一步用c语言实现sift算法、下.c
    │   │   ├── 2.1:寻找最小的 k 个数.c
    │   │   ├── 2.2:求给定区间的第K小元素.c
    │   │   ├── 2.3:求解500万以内的亲和数.c
    │   │   ├── 2.4:寻找和为定值的两个数.c
    │   │   ├── 2.5:寻找和为定值的多个数.c
    │   │   ├── 2.6:求连续子数组的最大和.c
    │   │   ├── 2.7:奇偶排序.c
    │   │   ├── 2.7:荷兰国旗问题.c
    │   │   ├── 2.8:矩阵相乘之Strassen算法.c
    │   │   ├── 3.1:二分查找实现.c
    │   │   ├── 3.2:杨氏矩阵查找.c
    │   │   ├── 4.1:木块砌墙.c
    │   │   ├── 4.2:格子取数问题.c
    │   │   ├── 4.3:出现次数超过一半的数字.c
    │   │   ├── 4.3:完美洗牌算法.c
    │   │   ├── 4.4:最近公共祖先LCA问题.LCAProblem.c
    │   │   ├── 4.5:打印螺旋矩阵.SpiralMatrix.c
    │   │   ├── 5.1:最长公共子序列(LCS)问题.c
    │   │   ├── 5.2:最大连续乘积子串.c
    │   │   ├── 5.3:字符串编辑距离.c
    │   │   ├── 5.4:交替字符串.c
    │   │   ├── 6.11:最小操作数.c
    │   │   ├── 6.4:回文判断.c
    │   │   ├── 6.6:跳台阶问题.c
    │   │   ├── 6.8:第一个只出现一次的字符.c
    │   │   ├── 6.9:Trie树.c
    │   │   ├── 7.1:搜索引擎热门查询统计.c
    │   │   ├── 7.2:最短摘要的生成.c
    │   │   ├── 7.3:倒排索引关键词不重复Hash编码.c
    │   │   ├── 7.4:倒排索引关键词 Hash 不重复编码实践.c
    │   │   └── makefile
    │   ├── cpp/
    │   │   ├── 1.1:左旋转字符串.cpp
    │   │   ├── 2.1:寻找最小的 k 个数.cpp
    │   │   ├── 3.1:二分查找实现(Jon Bentley
    │   │   ├── 4.2:完美洗牌算法.cpp
    │   │   ├── 7.4:倒排索引关键词 Hash 不重复编码实践.cpp
    │   │   ├── 9.2:海量数据处理之Bit-map详解.cpp
    │   │   ├── chapter04.cpp
    │   │   ├── chapter06.cpp
    │   │   └── makefile
    │   ├── erlang/
    │   │   ├── 1.1:左旋转字符串.erl
    │   │   ├── 3.1:二分查找实现.erl
    │   │   └── 6.4:回文判断.erl
    │   ├── go/
    │   │   ├── 1.1-左旋转字符串.go
    │   │   ├── 1.2-字符串是否包含问题.go
    │   │   ├── 1.5-回文判断.go
    │   │   ├── 2.1-寻找最小的k个数.go
    │   │   ├── 2.2-求数组中给定下标区间内的第K小元素.go
    │   │   ├── 3.2-杨氏矩阵查找.go
    │   │   └── 3.3:出现次数超过一半的数字.go
    │   ├── java/
    │   │   ├── chapter1/
    │   │   │   ├── 1.1:左旋转字符串.java
    │   │   │   ├── 1.2:字符串包含.java
    │   │   │   ├── Chapter1.java
    │   │   │   ├── Palindrome.java
    │   │   │   └── StringToInt
    │   │   ├── chapter2/
    │   │   │   ├── Chapter2.java
    │   │   │   ├── CountAndCompare.java
    │   │   │   ├── HashTableCompare.java
    │   │   │   ├── ICompare.java
    │   │   │   ├── PrimeCompare.java
    │   │   │   ├── SortAndCompare.java
    │   │   │   └── TopK.java
    │   │   ├── chapter3/
    │   │   │   ├── Chapter3.java
    │   │   │   ├── HeapSolution.java
    │   │   │   ├── IFindMinK.java
    │   │   │   └── MaxHeap.java
    │   │   ├── chapter4/
    │   │   │   └── Chapter4.java
    │   │   └── chapter6/
    │   │       └── Chapter6.java
    │   ├── js/
    │   │   ├── 1.1:左旋转字符串/
    │   │   │   ├── 1.1:左旋转字符串.js
    │   │   │   ├── test.html
    │   │   │   └── tests.js
    │   │   ├── 1.2:字符串是否包含问题/
    │   │   │   ├── 1.2:字符串是否包含问题.js
    │   │   │   ├── test.html
    │   │   │   └── tests.js
    │   │   └── 2.4:寻找和为定值的两个数/
    │   │       ├── 2.4:寻找和为定值的两个数.js
    │   │       ├── test.html
    │   │       └── tests.js
    │   ├── php/
    │   │   ├── chapter1.php
    │   │   ├── chapter2.php
    │   │   └── chapter3.php
    │   ├── python/
    │   │   ├── 1.1:字符的移动.py
    │   │   ├── 1.2:字符串是否包含问题.py
    │   │   ├── 1.5:回文判断.py
    │   │   ├── 1.6:最长回文子串.py
    │   │   ├── 2.1:寻找最小的k个数.py
    │   │   ├── 2.1:寻找最小的k个数_2.py
    │   │   ├── 2.3:求解500万以内的亲和数.py
    │   │   ├── 2.3:求解500万以内的亲和数_2.py
    │   │   ├── 2.4:寻找和为定值的两个数.py
    │   │   ├── 2.6:求连续子数组的最大和.py
    │   │   ├── 3.1:二分查找实现.py
    │   │   ├── 3.2:杨氏矩阵查找.py
    │   │   ├── 3.3:出现次数超过一半的数字.py
    │   │   ├── 6.5:全排列.py
    │   │   ├── 6.6:跳台阶.py
    │   │   ├── 6.8:第一个只出现一次等问题.py
    │   │   ├── 6.9:Trie树.py
    │   │   ├── chapter04.py
    │   │   └── rcdtype.py
    │   ├── rebol/
    │   │   ├── 1.1:左旋转字符串.reb
    │   │   └── 1.2:字符串是否包含问题.reb
    │   ├── ruby/
    │   │   ├── chapter01.rb
    │   │   ├── chapter02.rb
    │   │   ├── chapter03.rb
    │   │   ├── chapter0301.searchTrend.rb
    │   │   ├── chapter0302.quickSort.rb
    │   │   ├── chapter04.rb
    │   │   ├── chapter05.findSum.rb
    │   │   ├── chapter06.amicableNumber.rb
    │   │   ├── chapter07.findMaxSum.rb
    │   │   ├── chapter16.permutation.rb
    │   │   ├── chapter17.rb
    │   │   ├── chapter18.rb
    │   │   └── chapter19.rb
    │   └── scheme/
    │       ├── chapter01.scm
    │       ├── chapter06.scm
    │       ├── chapter06v2.scm
    │       ├── chapter17.scm
    │       └── chapter25.scm
    ├── en/
    │   ├── 01.0.md
    │   ├── 03.0.md
    │   ├── 07.0.md
    │   ├── 11.0.md
    │   ├── 25.0.md
    │   ├── 28.0.md
    │   ├── 35.0.md
    │   └── Readme.md
    ├── epub/
    │   └── TAOP_July.epub
    ├── images/
    │   ├── .directory
    │   ├── 1/
    │   │   ├── 1.1.tex
    │   │   ├── 1.2.tex
    │   │   ├── 1.3.tex
    │   │   ├── 1.4.tex
    │   │   ├── 2.1.tex
    │   │   ├── 2.2.tex
    │   │   ├── 2.3.tex
    │   │   └── include.tex
    │   └── 3/
    │       └── 3.1/
    │           └── .directory
    └── zh/
        ├── 00.01.md
        ├── 01.00.md
        ├── 01.01.md
        ├── 01.02.md
        ├── 01.03.md
        ├── 01.04.md
        ├── 01.05.md
        ├── 01.06.md
        ├── 01.10.md
        ├── 02.00.md
        ├── 02.01.md
        ├── 02.02.md
        ├── 02.03.md
        ├── 02.04.md
        ├── 02.05.md
        ├── 02.06.md
        ├── 02.07.md
        ├── 02.08.md
        ├── 02.09.md
        ├── 02.10.md
        ├── 02.15.md
        ├── 03.00.md
        ├── 03.01.md
        ├── 03.02.md
        ├── 03.03.md
        ├── 03.05.md
        ├── 03.10.md
        ├── 04.01.md
        ├── 04.02.md
        ├── 04.03.md
        ├── 05.00.md
        ├── 05.01.md
        ├── 05.02.md
        ├── 05.03.md
        ├── 05.04.md
        ├── 05.06.md
        ├── 05.10.md
        ├── 06.00.md
        ├── 06.01.md
        ├── 06.02.md
        ├── 06.03.md
        ├── 06.04.md
        ├── 06.05.md
        ├── 06.06.md
        ├── 06.07.md
        ├── 06.08.md
        ├── 06.09.md
        ├── 06.10.md
        ├── 06.11.md
        ├── 06.15.md
        ├── 07.01.md
        ├── 07.02.svm.md
        ├── 08.00.md
        ├── 08.01.md
        ├── 08.02.md
        ├── 08.03.md
        ├── 08.04.md
        ├── 08.05.md
        ├── 10.01.01.md
        ├── 10.01.02.md
        ├── 10.01.03.md
        ├── 40亿个数中快速查找.md
        ├── Readme.md
        ├── hash表算法.md
        ├── 一致性哈希算法.md
        ├── 倒排索引关键词不重复Hash编码.md
        ├── 傅里叶变换算法、上.md
        ├── 傅里叶变换算法、下.md
        ├── 后缀树.md
        ├── 基于给定的文档生成倒排索引的编码与实践.md
        ├── 搜索关键词智能提示suggestion.md
        ├── 最小操作数.md
        ├── 最短摘要的生成.md
        ├── 最长公共子序列.md
        ├── 木块砌墙原稿.md
        ├── 附近地点搜索.md
        └── 随机取出其中之一元素.md

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# Compiled source #
###################
*.com
*.class
*.dll
*.exe
*.o
*.so
ebook/build/build

# Packages #
############
# it's better to unpack these files and commit the raw source
# git has its own built in compression methods
*.7z
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip

# Logs and databases #
######################
*.log
*.sqlite

# OS generated files #
######################
.DS_Store*
ehthumbs.db
Icon?
Thumbs.db

# Vim
*~
*.sw[a-z]
._*

# PhpStorm (IDE) project files
.idea/*

# python compiled binary
*.pyc
ebook/build/build/


================================================
FILE: Readme.md
================================================
## 程序员编程技艺(原编程艺术系列,脱胎于微软面试100题系列,后成书为编程之法)

看过[结构之法算法之道blog](http://blog.csdn.net/v_july_v)的朋友可能知道,从2010年10月起,[July](http://weibo.com/julyweibo) 开始整理一个微软面试100题的系列,他在整理这个系列的过程当中,越来越强烈的感觉到,可以从那100题中精选一些更为典型的题,每一题详细阐述成章,不断优化,于此,便成了程序员编程艺术系列。

原编程艺术系列从2011年4月至今,写了42个编程问题,在创作的过程当中,得到了很多朋友的支持,特别是博客上随时都会有朋友不断留言,或提出改进建议,或show出自己的思路、代码,或指正bug。为更好的改进、优化、增补编程艺术系列,特把博客上的这个**程序员编程艺术系列和博客内其它部分经典文章**同步到此,成立本项目,最后成书为:《编程之法:面试和算法心得》。

若发现任何问题、错误、bug,或可以优化的每一段代码,欢迎随时pull request或发issue反馈,thanks。

update

2023年2.4日July更新:这本编程之法,17-19年就特别想出修订版,但奈何当时各种事情实在是太多,顾不上来,是个遗憾,今年要弥补此前遗憾,出第二版,相比第一版将:
- 1 重写1/3的内容,且再度review所有代码、所有公式全部用LaTeX重新编辑一遍、删减个别内容
- 2 新增1/3的新题,从七月在线于2021年Q2至2023年Q2整理的过去两年的最新大厂面试题中精选20道数据结构/算法和AI相关的新题
- 3 新增部分机器学习技术,比如xgboost CNN RNN LSTM等

有意参与读者审阅的欢迎随时联系我

另,还在谋划4本新书,类似:
- ChatGPT背后技术拆解,包括且不限于:1 微积分/概率统计基础、2 ML与最优化基础损失函数/梯度上升、3 RL/RLHF与TRPO/PPO算法、4 transformer/自注意力机制、5 GPT-N/prompt学习、6 chatgpt训练三阶段及多轮对话等工程细节、7 chatgpt在各行各业的应用
- 机器学习通俗笔记
- RL极简入门
- AI数学基础入门

未来三年逐一出版

## Contact me
July个人微博:https://weibo.com/julyweibo ,并于2015年正式创业,任七月在线创始人兼CEO,公司官网为:https://www.julyedu.com/ ,致力于培养100万AI人才

## Start Reading
 * [中文目录](ebook/zh/Readme.md) Enhancement in progress
 * [English Contents](ebook/en/Readme.md) Translation in progress

## How To Contribute
 * 邀请大家帮忙把github上的文章导出到word上,欢迎到这里认领:https://github.com/julycoding/The-Art-Of-Programming-By-July/issues/337 」
 * 一章一章的测试所有代码,指正 bug,修正错误。 「必选,可到这里认领:https://github.com/julycoding/The-Art-Of-Programming-By-July/issues/210 」
 * 优化原文章上的C/C++ 代码,优化后的代码可以放到[ebook/code](ebook/code/)文件夹内,并注意代码命名规范的问题:https://github.com/julycoding/The-Art-Of-Programming-By-July/issues/234 。 「必选」
 * 添加其它语言如Java、python、go 的代码,放在[ebook/code](ebook/code/)文件夹内,同样如上,注意代码命名规范的问题。 「可选」
 * 重绘所有的图片:https://github.com/julycoding/The-Art-Of-Programming-by-July/issues/80
 * 翻译成英文版,参考[中文目录](ebook/zh/Readme.md),把翻译后的文章编辑到这[English Version](ebook/en/Readme.md),注:不必逐字翻译,精简大气即可(如有兴趣翻译,请到这里领取感兴趣的章节翻译:https://github.com/julycoding/The-Art-Of-Programming-by-July/issues/84 )
 * 自己主导续写新的章节;
 * 任何你想做的事情,包括痛批你觉得写的烂的章节,所有你的意见都将改进此系列。

你可以做以上任何一件或几件事情,如遇到任何问题或疑惑,咱们可以随时讨论:
<https://github.com/julycoding/The-Art-Of-Programming-by-July/issues?state=open>。
「如不知如何在github上提交及同步作者的更新,可参考此文:http://www.cnblogs.com/rubylouvre/archive/2013/01/24/2874694.html 」

## Code Style
本项目暂约定以下代码风格(不断逐条添加中):
关于空格
- 所有代码使用4个空格缩进
- 运算符后使用一个空格
- "," 和for循环语句中的";" 后面跟上一个空格
- 条件、分支保留字,如 if for while else switch 后留出一个空格
- "[]", "."和"->" 前后不留空格
 - 用空行把大块代码分成逻辑上的“段落
 
关于括号 
- 大括号另起一行
- 即便只有一行代码也加大括号
 - C 指针中的指针符靠近类型名,如写成int* p,而不写成int *p
 
关于标点
- 中文表述,使用中文全角的标点符号,如:()、。,?
- 数学公式(包括文中混排的公式)和英文代码,使用英文半角的标点符号,如:(),.?…

关于注释
- 注释统一用中文
- 尽量统一用"//",一般不用"/\*...\*/"

关于命名
- 类名为大写字母开头的单词组合
- 函数名比较长,由多个单词组成的,每个单词的首字母大写,如int MaxSubArray();函数名很短,由一个单词组成,首字母小写,比如int swap()
- 变量名比较长,由多个单词组成的,首个单词的首字母小写,后面紧跟单词的首字母大写,如maxEnd;变量名很短,由一个单词组成,首字母小写,如left
- 变量尽量使用全名,能够描述所要实现的功能,如 highestTemprature;对于已经公认了的写法才使用缩写,如 tmp mid prev next
- 变量名能“望文生义”,如v1, v2不如area, height
- 常量的命名都是大写字母的单词,之间用下划线隔开,比如MY_CONSTANT
- il < 4384 和 inputLength < MAX_INPUT_LENGTH,后一种写法更好

 - 一个函数只专注做一件事
 - 时间复杂度小写表示,如O(nlogn),而不写成O(N*logN)
 - 正文中绝大部分采用C实现,少量C++代码,即以C为主,但不去刻意排斥回避C++;
 
关于的地得
- 形容词(代词) + 的 + 名词,例如:我的小苹果
- 副词 + 地 + 动词,例如:慢慢地走
- 动词 + 得 + 副词,例如:走得很快

关于参考文献
- 格式:主要责任者.书名〔文献类型标识 ] .其他责任者.版本.出版地:出版者,出版年.文献数量.丛编项.附注项.文献标准编号。例子:1 刘少奇.论共产党员的修养.修订 2 版.北京:人民出版社,1962.76 页.
 - 专业术语
- 统一一律用“树结点”,而不是“树节点”。
- 用左子树、右子树表示树的左右子树没问题,但是否用左孩子、右孩子表示树或子树的左右结点?
 - ..
 - 此外,更多C++ 部分可参考Google C++ Style Guide,中文版见:http://zh-google-styleguide.readthedocs.org/en/latest/contents/ ;

有何问题或补充意见,咱们可以随时到这里讨论:https://github.com/julycoding/The-Art-Of-Programming-By-July/issues/81 。

## Ver Note
 - 2010年10月11日,在CSDN上正式开博,感谢博客上所有读者的访问、浏览、关注、支持、留言、评论、批评、指正;
 - 2011年1月,在学校的时候,第一家出版社联系出书,因“时机未到,尚需积累”的原因婉拒,随后第二家、第三家出版社陆续联系,因总感觉写书的时机还没到,一律婉拒;
 - 2011年10月, 当时在图灵教育的杨海玲老师(现在人民邮电信息技术分社)再度联系出书,再度认为“时机未到”;
 - 2013年12月30日,本项目在众多朋友的努力之下,冲到github流行趋势排行榜全球第一,自己也在众人助推下冲到全球开发者第一。
 - 2014年1月18日,想通了一件事:如果什么都不去尝试,那么将年年一事无成,所以元旦一过,便正式确认今2014年之内要把拖了近3年之久的书出版出来;
 - 2013年12月-2014年3月,本github的Contributors 转移结构之法算法之道blog的部分经典文章到本github上,感谢这近100位Contributors,包括但不限于:
- Boshen(除我之外,贡献本github的次数最多)
- sallen450
- marchtea(专门为本github书稿弄了一个HTML网页)
- nateriver520(劝我把书稿放在github上,才有了本github)
 - 2014年3月,通读全部文章,修正明显错误,并邀请部分朋友review本github上的全部文章,包括cherry、王威扬、邬勇、高增琪、武博文、杨忠宝等;
 
2014年4月
- 整个4月,精简篇幅,调整目录,Contributors 贡献其它语言代码,并翻译部分文章;
- 4月25日,跟人民邮电出版社信息技术分社签订合同,书名暂定《程序员编程艺术:面试和算法心得》,有更好的名字再替换。
 - 2014年5月,逐章逐节逐行逐字优化文字描述,测试重写优化每一段每一行每一个代码,确定代码基本风格;
 
2014年6月
- 第一周,压缩篇幅,宁愿量少,但求质精;
- 第二周,全面 review;
- 第三周,本github的部分Contributors 把全部文章从github转到word上,这部分contributors 包括包括:zhou1989、qiwsir、DogK、x140yu、ericxk、zhanglin0129、idouba.net、gaohua、kelvinkuo等;
- 第四周,继续在Word 上做出最后彻底的改进,若未发现bug或pull request,本github将暂不再改动;
- 6月30日,与出版社约定的交稿日期延期,理由:目前版本不是所能做到的最好的版本。
2014年7月,邀请部分好友进行第一轮审稿,包括曹鹏、邹伟、林奔、王婷、何欢,其中,曹鹏重写优化了部分代码。此外,葛立娜对书稿中的语言描述做了不少改进;
 
2014年8月
- 8月上旬,新增KMP一节内容;
- 8月下旬,重点修改SVM一节内容;

2014年9月
- 9月上旬,和一些朋友一起重绘稿件中的部分图和公式,这部分朋友包括顾运(@陈笙)、mastermay、在山东大学读研二的丰俊丙、厦门大学电子工程系陈友和等等;
- 9月下旬,再度邀请另一部分好友进行第二轮审稿,包括许利杰、王亮、陈赢、李祥老师、litaoye等,并在微博上公开征集部分读者审稿,包括李元超、刘琪等等;

2014年10月
- 10月8日起,开始一章一章陆续交Word 稿给出版社初审
- 10月9日,第一章、字符串完成修改;
- 10月10日,第二章、数组完成修改;
- 10月22日,第三章、树完成修改;

2014年11月
- 11月5日,第三章、树完成第二版修改,主要修正部分图片、公式、语言描述的错误;

2014年12月
- 12月1日,第四章、查找完成修改。至此,前4 章的修改稿交付出版社。 
- 12月8日,第五章、动态规划完成修改,等出版社反馈中。一个人坚持有点枯燥。
- 12月31日,第六章仍未修改完。

2015年1月
- 1月12日凌晨,第六章、海量数据处理完成修改,交付出版社。

2015年4月
- 4月27日凌晨,交完第七章初稿,接下来编辑老师反馈,我修改审阅反馈稿。且书名由原来的《程序员编程艺术:面试和算法心得》暂时改为《编程之法:面试和算法心得》。

2015年5月
- 5月2日,开始写书的前言,大致是:为何要写这本书,写的过程是怎样的;这是本什么书,有何特色,内容是什么,为什么这么写;写给谁看,怎么看更好。当然我还会加一些自己觉得比较个性化的内容。
- 5月5日,审阅完编辑老师的第一章反馈,并合并。
- 5月6日,审阅完第二章的一半。海玲姐两位老师给出了大量细致、详尽的修改建议,包括文字表述、语言表达、标点符号、字体格式、出版规范,尤其是正斜体、大小写、上下角。
- 5月15日,和海玲姐审完第一、二章,标点、术语、表述、逻辑、图片、代码等一切细节。书稿进入一审阶段。

2015年6月
- 6月28日,经过反复修改、确认,书稿第一、二、三章基本定稿。 

2015年7月
- 7月10日,书稿全部七章基本定稿,即将进入二审。
- 7月23日,补齐前言、封底、内容提要、邀请曹鹏、邹伟两位博士写推荐序,书稿进入二审,出版社重绘全部图片和公式。

2015年8月
- 8月6日,三审结束。书稿取得阶段性的胜利。 
- 8月下旬,发稿审批。

2015年9月
- 9月上旬,排版校对,出胶片、印刷、装订成书 
- 9月21日,几经易稿,终于敲定新书封面。
- 9月22日,开始印刷。

2015年10月
- 进入10月份,万众期待的《编程之法》,终于终于要来了!
- 10月13日晚,终于拿到第一批样书。
- 10月14日下午三点半,我的新书《编程之法》终于在异步社区上首发开卖!
- 10月28日,新书正式上架京东。目前京东、当当、亚马逊等各大网店均已有现货销售。

## Contributors
感谢所有贡献的朋友:https://github.com/julycoding/The-Art-Of-Programming-by-July/graphs/contributors ,因为有各位之力,本项目才能于13年年底冲到github流行趋势排行榜全球第一。非常期待你的加入,thanks。

同时,欢迎加入《编程之法》讨论交流QQ群:74631723,需要写验证信息。

孤军奋战的时代早已远去,我们只有团结起来,才能帮助到更多人。[@研究者July](http://weibo.com/julyweibo),始于二零一三年十二月十四日。

## Expressing Thanks

- 感谢我博客上所有读者的访问、浏览、关注、支持、留言、评论、批评、指正,仅以本书献给我博客的所有读者。
- 感谢Boshen、sallen450、marchtea、nateriver520等朋友帮我把博客上的部分经典文章移到GitHub上。
- 感谢zhou1989、qiwsir、DogK、x140yu、ericxk、zhanglin0129、idouba.net、gaohua、kelvinkuo等朋友帮我把GitHub上的文章转为Word文件。
- 感谢顾运、mastermay、丰俊丙、陈友和等朋友帮忙重绘书中的部分图和重录书中的部分公式。
- 感谢cherry、王威扬、邬勇、高增琪、武博文、杨忠宝、葛立娜、林奔、王婷、何欢、许利杰JerryLead、王亮、陈赢、李祥老师、litaoye、李元超、刘琪、weedge、Frankie等众多朋友帮忙审校书稿。
- 特别感谢曹鹏、邹伟两位博士。感谢他们非常认真细致地看完了全部书稿,给出了非常多的建设性意见,并为本书作序。
- 最后,再次感谢杨海玲老师以及出版社的编辑们。感谢杨海玲老师给出了大量细致的修改建议,并且非常耐心地与我一轮一轮讨论和修改书稿。

感谢以上诸位,正因为他们的帮助,纸书《编程之法:面试和算法心得》的质量才不断提升,从而给广大读者呈现的是更好的作品。

声明:本电子书的版权属于July 本人,严禁他人出版或用于商业用途,违者必究法律责任。July、二零一四年五月十一日晚。

## 干货集锦
July’ PDF
 - 《支持向量机通俗导论(理解SVM的三层境界)》Latex排版精细版:http://vdisk.weibo.com/s/zrFL6OXKgnlcp ;Latex版本②:https://raw.githubusercontent.com/liuzheng712/Intro2SVM/master/Intro2SVM.pdf 。
 - 《微软面试100题系列之PDF》:http://download.csdn.net/detail/v_july_v/4583815
 - 编程艺术HTML网页版:http://taop.marchtea.com/
 - 截止到2014年12.9日,结构之法算法之道blog所有155篇博文集锦CHM文件下载地址:http://pan.baidu.com/s/1gdrJndp
 
July团队高校讲座PPT
 - 2014年4月29日《武汉华科大第5次面试&算法讲座PPT》:http://pan.baidu.com/s/1hqh1E9e ;
 - 2014年9月3日西电第8次面试&算法讲座视频:http://v.youku.com/v_show/id_XNzc2MDYzNDg4.html ;PPT:http://pan.baidu.com/s/1pJ9HFqb ;
 - 北京10月机器学习班的所有上课PPT:http://yun.baidu.com/share/home?uk=4214456744&view=share#category/type=0;
- July新书初稿的4个PDF
 - B树的PDF:http://yun.baidu.com/s/1jGwup5k ;
 - 海量数据处理的PDF:http://yun.baidu.com/s/1dDreICL ;
 - 支持向量机的PDF:http://yun.baidu.com/s/1ntwof7j ;
 - KMP的PDF:http://yun.baidu.com/s/1eQel3PK ;

面试题集锦
 - 国内首个AI题库陆续发布,「BAT机器学习面试1000题」:https://www.julyedu.com/questions/interview 
 - 2021大厂最新AI面试题 [含答案和解析, 更新到前105题]:https://www.julyedu.com/course/getDetail/369
 
机器学习十大算法系列

July在CSDN上有写一个「机器学习十大算法系列」(链接:https://blog.csdn.net/v_july_v/category_9261611.html ),后远不止十大,现30篇,总阅读量500万,平均一篇16万多阅读,同事整理成PDF,竞达800页!其中最经典的十篇文章分别是:
- SVM http://blog.csdn.net/v_july_v/article/details/7624837
- xgboost:https://www.julyedu.com/questions/interview-detail?kp_id=23&cate=%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0&quesId=2590 
- CNN笔记:通俗理解卷积神经网络 http://blog.csdn.net/v_july_v/article/details/51812459
- RNN/LSTM https://www.julyedu.com/question/big/kp_id/26/ques_id/1851 
- 一文掌握目标检测:https://www.julyedu.com/question/big/kp_id/26/ques_id/2103
- 通俗理解kaggle比赛大杀器xgboost,2018年8月:https://blog.csdn.net/v_JULY_v/article/details/81410574
- 如何从RNN起步,一步一步通俗理解LSTM,2019年5月:https://blog.csdn.net/v_JULY_v/article/details/89894058
- BERT通俗笔记:从Word2Vec/Transformer逐步理解到BERT,2022年10月:https://blog.csdn.net/v_JULY_v/article/details/127411638
- ChatGPT通俗笔记:从GPT-N、RL之PPO算法到instructGPT、ChatGPT,2023年1月:https://blog.csdn.net/v_JULY_v/article/details/128579457

持续更新..

## AI课程
  - 七月在线「机器学习集训营」,http://www.julyedu.com/weekend/train18 ,一站式掌握大数据、机器学习、深度学习和CV/N LP/推荐项目实战,已帮助2000多人成功就业/转型
 - 《CV高级小班 第十二期》:http://www.julyedu.com/Employment/cv12 ,在Facebook已年薪百万的都来学的CV高级班,不止精讲Vision Transformer 更实战6大企业级项目
 - 《NLP高级小班 第十一期》:http://www.julyedu.com/weekend/nlp11 ,不止精讲HMM/CRF/Transformer/BERT且不止四大企业级项目,和在百度、字节、华为的同学共同提升
 - 《推荐高级班 第十三期》:https://www.julyedu.com/employment/rs13 ,不止购买预测、文本推荐、行为预测、电商推荐,与已在大厂做推荐的同学共同提升


================================================
FILE: ebook/build/Makefile
================================================
BUILD = build
BOOKNAME = TAOP_July
METADATA = metadata.yaml
SRC_DIR = ../zh/
TOC = --toc --toc-depth=1
LATEX_CLASS = report
GHUSER = 
GHPASS = 

all: book

book: epub mobi html

epub: $(BUILD)/epub/$(BOOKNAME).epub

html: $(BUILD)/html/$(BOOKNAME).html

pdf: $(BUILD)/pdf/$(BOOKNAME).pdf

mobi: $(BUILD)/mobi/$(BOOKNAME).mobi

clean:
	rm -r $(BUILD)

#pandoc generate great TOC for epub, html, pdf
#so In this makefile, we will omit Readme.md
$(BUILD)/epub/$(BOOKNAME).epub: $(TITLE) 
	mkdir -p $(BUILD)/epub
	pandoc $(TOC) -S -o $@ $(METADATA) `ls $(SRC_DIR)*.md | grep "$(SRC_DIR)[0-9]"`

$(BUILD)/html/$(BOOKNAME).html:
	mkdir -p $(BUILD)/html
	cp -r ../images/ $(BUILD)/images
	cp TAOP.png $(BUILD)/html
	@tmpdir=`pwd`;\
		cd $(BUILD)/html;\
		mdtogh --css --user=$(GHUSER) --pass=$(GHPASS) --toc --toc_file=$$tmpdir/$(SRC_DIR)Readme.md --book=$$tmpdir/book.json --file_reg='^\d.+\.md$$' $$tmpdir/$(SRC_DIR);

$(BUILD)/pdf/$(BOOKNAME).pdf: $(TITLE)
	mkdir -p $(BUILD)/pdf
	pandoc $(TOC) --latex-engine=xelatex -V documentclass=$(LATEX_CLASS) -o $@ `ls $(SRC_DIR)*.md | grep "$(SRC_DIR)[0-9]"`

$(BUILD)/mobi/$(BOOKNAME).mobi: $(TITLE)
	mkdir -p build/mobi
	@if [ ! -e $(BUILD)/epub/$(BOOKNAME).epub ];\
		then \
		echo "make epub first"; \
		make epub ;\
		fi;
	@echo "generating mobi now"
	@ebook_convert_cmd=`which ebook-convert`; \
		if [ -z $$ebook_convert_cmd ]; \
		then \
		mac_osx_path='Applications/calibre.app/Contents/MacOS/ebook-convert';\
		ebook_convert_cmd=$$mac_osx_path;\
		fi;\
		if [ ! -e $$ebook_convert_cmd ];\
		then \
		echo "You need install calibre first!";\
		exit 1;\
		fi; \
		$$ebook_convert_cmd "$(BUILD)/epub/$(BOOKNAME).epub" "$(BUILD)/mobi/$(BOOKNAME).mobi" \
		--cover TAOP.png \
		--authors July \
		--level1-toc 'h1'\
		--language zh_CN ;

.PHONY: all book clean epub html pdf mobi


================================================
FILE: ebook/build/README.md
================================================
#Build Ebooks

##Requirement
*	[pandoc](http://johnmacfarlane.net/pandoc/)
*	[mdtogh](https://github.com/marchtea/mdtogh)
*	git
*	make(OS X users should install XCode command line tools(xcode-select --install)
*	latex (OS X users can use [MacTex](http://www.tug.org/mactex/morepackages.html).)
*	[calibre](http://calibre-ebook.com)(For mobi)

##Usage

Now scripts support three format generation:

*	epub
*	html
*	mobi([calibre](http://www.calibre-ebook.com/) is needed with its command line tools installed)

To make all three format, use `make`.

To make specific format, use `make (format)`, e: `make epub`
	
##TODO

*	pdf support

================================================
FILE: ebook/build/book.json
================================================
{
    "title": "The Art of Programming By July",
    "description": "本书是July和他伙伴们的《程序员编程艺术》的电子书",
    "coverimage": "TAOP.png"
}


================================================
FILE: ebook/build/metadata.yaml
================================================
---
title:
- type: main
  text: The Art of Programming By July
- type: subtitle
  text: somestuff
creator:
- role: author
  text: July
contributor:
- role: author
  text: co sdfds
date: 2014
language: zh_CN
description: 
cover-image: TAOP.png
stylesheet: style.css
...


================================================
FILE: ebook/build/style.css
================================================
/* This defines styles and classes used in the book */
body { margin: 5%; text-align: justify; font-size: medium; }
code { font-family: monospace; font-size: small;}
h1 { text-align: left; }
h2 { text-align: left; }
h3 { text-align: left; }
h4 { text-align: left; }
h5 { text-align: left; }
h6 { text-align: left; }
h1.title { }
h2.author { }
h3.date { }
ol.toc { padding: 0; margin-left: 1em; }
ol.toc li { list-style-type: none; margin: 0; padding: 0; }


================================================
FILE: ebook/code/c/1.1:左旋转字符串.c
================================================
/*
 * Zaks Wang
 * ultimate010@gmail.com
 * ultimate010.tk
 * 2013-12-31
 */
#include <stdio.h>
#include <string.h>
//字符串旋转问题,例如abcdef 左旋2位 变成 cdefab

//暴力移位法
void leftShift1(char * arr, int n)
{
    size_t tmpLen = strlen(arr);
    char tmpChar;
    int i, j;
    if (n >= 0)
    {
        for (i = 0; i < n; i++)
        {
            tmpChar = *arr;
            for (j = 0; j < tmpLen - 1; j++)
            {
                *(arr + j) = *(arr + j + 1);
            }
            *(arr + tmpLen - 1) = tmpChar;
        }
    }
    else
    {
        for (i = 0; i < -n; i++)
        {
            tmpChar = *(arr + tmpLen - 1);
            for (j = tmpLen - 1; j > 0; j--)
            {
                *(arr + j) = *(arr + j - 1);
            }
            *arr = tmpChar;
        }
    }
}
//指针移位法
void leftShift2(char * arr, int len, int n)
{
    int i;
    size_t tmpLen = len;
    int p0 = 0;
    int p1 = n;
    char tmpChar;
    /*  O(m - n - k)  k is the last section*/
    while (p1 + n - 1 < tmpLen)
    {
        tmpChar = *(arr + p0);
        *(arr + p0) = *(arr + p1);
        *(arr + p1) = tmpChar;
        p0++;
        p1++;
    }
    /*
     *  not good O(k * (n + k)) k = tmpLen - p1
     for(i = 0;i < tmpLen - p1;i++){ //移动后面剩下的
     tmpChar = *(arr + tmpLen - 1);
     for(j = tmpLen - 1;j > p0;j--){
     *(arr + j) = *(arr + j -1);
     }
     *(arr + p0) = tmpChar;
     }
     */
    /* good O(k * n) */
    while (p1 < tmpLen)
    {
        tmpChar = *(arr + p1);
        for (i = p1; i > p0; i--)
        {
            *(arr + i) = *(arr + i - 1);
        }
        *(arr + p0) = tmpChar;
        p0++;
        p1++;
    }
}
//指针移位法,尾部处理用递归
void leftShift3(char * arr, int len, int n)
{
    size_t tmpLen = len;
    int p0 = 0;
    int p1 = n;
    char tmpChar;
    /*  O(m - n - k)  k is the last section*/
    while (p1 + n - 1 < tmpLen)
    {
        tmpChar = *(arr + p0);
        *(arr + p0) = *(arr + p1);
        *(arr + p1) = tmpChar;
        p0++;
        p1++;
    }
    if (p1 < tmpLen)
    {
        leftShift2(arr + p0, len - p0, n);
    }
}
//指针移位法,递归
void leftShift4(char * arr, int len, int n)
{
    size_t tmpLen = len;
    int p0 = 0;
    int p1 = n;
    char tmpChar;
    /*  O(m - n - k)  k is the last section*/
    while (p1 < tmpLen)
    {
        tmpChar = *(arr + p0);
        *(arr + p0) = *(arr + p1);
        *(arr + p1) = tmpChar;
        p0++;
        p1++;
    }
    int i = n - tmpLen % n;
    if (i != 0 && p0 != tmpLen - 1) // p0 can not be the tmpLen - 1
    {
        leftShift4((arr + p0), n, i);
    }
}

void myinvert(char * start, char * end)
{
    char tmpChar;
    while (start < end)
    {
        tmpChar = *start;
        *start = *end;
        *end = tmpChar;
        start++;
        end--;
    }
}

//翻转法
void leftShift5(char * arr, int len, int n)
{
    myinvert(arr, arr + n - 1);
    myinvert(arr + n, arr + len - 1);
    myinvert(arr, arr + len - 1);
}
int gcd(int m, int n)
{
    int r;
    while ((r = m % n))
    {
        m = n;
        n = r;
    }
    return n;
}
//循环移位法
void leftShift6(char * arr, int len, int n)
{
    int group = gcd(len, n);
    char tmpChar;
    int x = len / group;
    int i, j;
    for (i = 0; i < group; i++)
    {
        tmpChar = *(arr + i);
        for (j = 0; j < x - 1; j++)
        {
            *(arr + (i + (j * n)) % len) = *(arr + (i + (j * n) + n) % len);
        }
        *(arr + (i + (j * n)) % len) = tmpChar;
    }
}
int main()
{
    char str[50];
    sprintf(str, "abcdefghijk");
    printf("The origin str is :%s\tlen is :%zu\n", str, strlen(str));
    printf("\n");
    leftShift1(str, 2);
    printf("The leftShift1 str is :%s\n", str);
    leftShift1(str, -2);
    printf("The leftShift1 str is :%s\n", str);
    leftShift1(str, 3);
    printf("The leftShift1 str is :%s\n", str);
    leftShift1(str, strlen(str) - 3);
    printf("The leftShift1 str is :%s\n", str);
    printf("\n");

    leftShift2(str, strlen(str), 3);
    printf("The leftShift2 str is :%s\n", str);
    leftShift2(str, strlen(str), strlen(str) - 3);
    printf("The leftShift2 str is :%s\n", str);
    leftShift2(str + 2, strlen(str) - 2, 2);
    printf("The leftShift2 str is :%s\n", str);
    leftShift2(str + 2, strlen(str) - 2, strlen(str) - 2 - 2);
    printf("The leftShift2 str is :%s\n", str);
    printf("\n");


    leftShift3(str, strlen(str), 3);
    printf("The leftShift3 str is :%s\n", str);
    leftShift3(str, strlen(str), strlen(str) - 3);
    printf("The leftShift3 str is :%s\n", str);
    leftShift3(str + 2, strlen(str) - 2, 2);
    printf("The leftShift3 str is :%s\n", str);
    leftShift3(str + 2, strlen(str) - 2, strlen(str) - 2 - 2);
    printf("The leftShift3 str is :%s\n", str);
    printf("\n");

    leftShift4(str, strlen(str), 3);
    printf("The leftShift4 str is :%s\n", str);
    leftShift4(str, strlen(str), strlen(str) - 3);
    printf("The leftShift4 str is :%s\n", str);
    leftShift4(str + 2, strlen(str) - 2, 2);
    printf("The leftShift4 str is :%s\n", str);
    leftShift4(str + 2, strlen(str) - 2, strlen(str) - 2 - 2);
    printf("The leftShift4 str is :%s\n", str);
    printf("\n");

    leftShift5(str, strlen(str), 3);
    printf("The leftShift5 str is :%s\n", str);
    leftShift5(str, strlen(str), strlen(str) - 3);
    printf("The leftShift5 str is :%s\n", str);
    leftShift5(str + 2, strlen(str) - 2, 2);
    printf("The leftShift5 str is :%s\n", str);
    leftShift5(str + 2, strlen(str) - 2, strlen(str) - 2 - 2);
    printf("The leftShift5 str is :%s\n", str);
    printf("\n");

    leftShift6(str, strlen(str), 3);
    printf("The leftShift6 str is :%s\n", str);
    leftShift6(str, strlen(str), strlen(str) - 3);
    printf("The leftShift6 str is :%s\n", str);
    leftShift6(str + 2, strlen(str) - 2, 2);
    printf("The leftShift6 str is :%s\n", str);
    leftShift6(str + 2, strlen(str) - 2, strlen(str) - 2 - 2);
    printf("The leftShift6 str is :%s\n", str);
    printf("\n");

    return 0;
}


================================================
FILE: ebook/code/c/1.2:字符串是否包含问题.c
================================================
/*
 * Zaks Wang
 * ultimate010@gmail.com
 * ultimate010.tk
 * 2014-1-2
 */
//判断a字符串是否包含b字符串的字母,假定都没有重复字符出现
#include <stdio.h>
#include <string.h>
#define bool    _Bool
#define TRUE    1
#define false   0

//冒泡法
int partion1(char * arr, int start, int end)
{
    char tmpChar;
    int i;
    while (*(arr + start) <= *(arr + end) && start < end)
    {
        start++; //start 指向第一个大的数据
    }
    if (start == end)
    {
        return start; //已经有序
    }
    for (i = start + 1; i < end; i++)
    {
        if (*(arr + i) < * (arr + end)) //交换
        {
            tmpChar = *(arr + start);
            *(arr + start) = *(arr + i);
            *(arr + i) = tmpChar;
            start++;
        }
    }
    tmpChar = *(arr + start);
    *(arr + start) = *(arr + i);
    *(arr + i) = tmpChar;
    return start;
}

//挖坑法
int partion(char * arr, int start, int end)
{
    char tmpChar = *(arr + start);
    while (start < end)
    {
        while (*(arr + end) >= tmpChar && end > start)
        {
            end--;
        }
        if (start < end)
        {
            *(arr + start) = *(arr + end); //小的往左走
            start++;
        }
        else
        {
            break;
        }
        while (*(arr + start) <= tmpChar && end > start)
        {
            start++;
        }
        if (start < end)
        {
            *(arr + end) = *(arr + start);
            end--;
        }
        else
        {
            break;
        }
    }
    *(arr + start) = tmpChar;
    return start;
}
//快排
void quickSort(char * arr, int start, int end)
{
    if (start < end)
    {
        int mid = partion1(arr, start, end);
        quickSort(arr, start, mid - 1);
        quickSort(arr, mid + 1, end);
    }
}
//计数排序,只针对大写字母
void countSort(char * oldArr, char * newArr)
{
    int count[26] = {0};
    int i;
    int lenOld = strlen(oldArr);
    memset(newArr, 0, lenOld); //clear
    int pos;
    for (i = 0; i < lenOld; i++)
    {
        pos = *(oldArr + i) - 'A';
        count[pos]++;
    }
    for (i = 0; i < 25; i++)
    {
        count[i + 1] += count[i];
    }
    for (i = 0; i < lenOld; i++)
    {
        pos = count[*(oldArr + i) - 'A'];
        while (newArr[pos - 1] != 0)
        {
            pos++;
        }
        newArr[pos - 1] = *(oldArr + i);
    }
}

//暴力求解法
bool contain1(char * stra, char * strb)
{
    int lena = strlen(stra);
    int lenb = strlen(strb);
    int i, j;
    for (i = 0; i < lenb; i++)
    {
        for (j = 0; j < lena; j++)
        {
            if (*(stra + j) == *(strb + i))
            {
                break;
            }
        }
        if (j == lena)
        {
            return false;
        }
    }
    return TRUE;
}

//排序比较法
bool contain2(char * stra, char * strb)
{
    char tmpA[100] = {0};
    char tmpB[100] = {0};
    /*    use quickSort
      sprintf(tmpA,"%s",stra);
      sprintf(tmpB,"%s",strb);
      quickSort(tmpA,0,strlen(tmpA) - 1);
      quickSort(tmpB,0,strlen(tmpB) - 1);
      */
    countSort(stra, tmpA);
    countSort(strb, tmpB);
    //printf("After sort:\n%s\n%s\n",tmpA,tmpB);
    int lena = strlen(tmpA);
    int lenb = strlen(tmpB);
    int i, j;
    for (i = 0, j = 0; j < lena && i < lenb; j++)
    {
        if (tmpA[j] == tmpB[i])
        {
            i++;
        }
        else if (tmpA[j] > tmpB[i])
        {
            return false;
        }
    }
    if (i == lenb)
    {
        return TRUE;
    }
    else
    {
        return false;
    }
}
//hash测试法
bool contain3(char * stra, char * strb)
{
    int hashTable[26] = {0};
    int i, count = 0;
    int lena = strlen(stra);
    int lenb = strlen(strb);
    for (i = 0; i < lenb; i++)
    {
        hashTable[*(strb + i) - 'A'] = 1;
        count++;
    }
    for (i = 0; i < lena && count > 0; i++)
    {
        if (hashTable[*(stra + i) - 'A']) //no need to make the hashTable to be 0
        {
            count--;
        }
    }
    if (count == 0)
    {
        return TRUE;
    }
    else
    {
        return false;
    }
}
//bit法,区分大小写
bool contain4(char * stra, char * strb)
{
    unsigned long long bitA = 0, bitB = 0; //必须用long long,64位才不会溢出
    while (*stra)
    {
        bitA |= (unsigned long long)(1l << (*stra++ & 0x3f)); //取8位中的后6位,a:97:01100001b A:65:01000001b 0x3f:00111111b;
    }
    while (*strb)
    {
        bitB |= (unsigned long long)(1l << (*strb++ & 0x3f));
    }
    return !((bitA ^ bitB) & bitB); //bitA ^ bitB 之后的结果,对于bitB中非0位,为1的话表示A中与B中某位不同,所以不包含
}
//素数方法,不能处理大量字符串,因为使用的unsigned long long溢出
bool contain5(char * stra, char * strb)
{
    int primeNumber[26] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59,
                           61, 67, 71, 73, 79, 83, 89, 97, 101
                          };
    unsigned long long bigNumber = 1; //too small for use.
    while (*stra)
    {
        bigNumber *= primeNumber[*stra - 'A'];
        stra++;
    }
    while (*strb)
    {
        if (0 != (bigNumber % primeNumber[*strb - 'A']))
        {
            break;
        }
        strb++;
    }
    if (*strb)
    {
        return false;
    }
    else
    {
        return TRUE;
    }
}


int main()
{
    char stra[50];
    char strb[50];
    char strc[50];
    sprintf(stra, "ABCDEFGHLMNOPQRS");
    sprintf(strb, "DCGSRQPO");
    sprintf(strc, "DCGSRQPZ");

    if (contain1(stra, strb))
        printf("%s contain %s\n", stra, strb);
    else
        printf("%s not contain %s\n", stra, strb);

    if (contain1(stra, strc))
        printf("%s contain %s\n", stra, strc);
    else
        printf("%s not contain %s\n", stra, strc);

    printf("\n");

    if (contain2(stra, strb))
        printf("%s contain %s\n", stra, strb);
    else
        printf("%s not contain %s\n", stra, strb);

    if (contain2(stra, strc))
        printf("%s contain %s\n", stra, strc);
    else
        printf("%s not contain %s\n", stra, strc);

    printf("\n");

    if (contain3(stra, strb))
        printf("%s contain %s\n", stra, strb);
    else
        printf("%s not contain %s\n", stra, strb);

    if (contain3(stra, strc))
        printf("%s contain %s\n", stra, strc);
    else
        printf("%s not contain %s\n", stra, strc);

    printf("\n");

    if (contain4(stra, strb))
        printf("%s contain %s\n", stra, strb);
    else
        printf("%s not contain %s\n", stra, strb);

    if (contain4(stra, strc))
        printf("%s contain %s\n", stra, strc);
    else
        printf("%s not contain %s\n", stra, strc);

    printf("\n");

    if (contain4("a", "A"))
        printf("a contain A in bit hack method\n");

    /*
     if(contain5("Ab","b")){
     printf("%s contain %s\n",stra,strb);
     }else{
     printf("%s not contain %s\n",stra,strb);
     }
     printf("\n");
     */
    return 0;
}



================================================
FILE: ebook/code/c/1.3:带通配符的字符串匹配问题.c
================================================
//解法一
//copyright@cao_peng 2013/4/23
int str_len(char *a)
{
	//字符串长度
	if (a == 0)
	{
		return 0;
	}
	char *t = a;
	for (; *t; ++t)
		;
	return (int) (t - a);
}

void str_copy(char *a, const char *b, int len)
{
	//拷贝字符串 a = b
	for (; len > 0; --len, ++b, ++a)
	{
		*a = *b;
	}
	*a = 0;
}

char *str_join(char *a, const char *b, int lenb)
{
	//连接字符串 第一个字符串被回收
	char *t;
	if (a == 0)
	{
		t = (char *) malloc(sizeof(char) * (lenb + 1));
		str_copy(t, b, lenb);
		return t;
	}
	else
	{
		int lena = str_len(a);
		t = (char *) malloc(sizeof(char) * (lena + lenb + 2));
		str_copy(t, a, lena);
		*(t + lena) = ' ';
		str_copy(t + lena + 1, b, lenb);
		free(a);
		return t;
	}
}

int canMatch(char *input, char *rule)
{
	// 返回最长匹配长度 -1表示不匹配
	if (*rule == 0)
	{
		//已经到rule尾端
		return 0;
	}
	int r = -1 , may;
	if (*rule == '*')
	{
		r = canMatch(input, rule + 1);  // *匹配0个字符
		if (*input)
		{
			may = canMatch(input + 1, rule);  // *匹配非0个字符
			if ((may >= 0) && (++may > r))
			{
				r = may;
			}
		}
	}
	if (*input == 0)
	{
		//到尾端
		return r;
	}
	if ((*rule == '?') || (*rule == *input))
	{
		may = canMatch(input + 1, rule + 1);
		if ((may >= 0) && (++may > r))
		{
			r = may;
		}
	}
	return r;
}

char * my_find(char input[], char rule[])
{
	int len = str_len(input);
	int *match = (int *) malloc(sizeof(int) * len);  //input第i位最多能匹配多少位 匹配不上是-1
	int i, max_pos = - 1;
	char *output = 0;

	for (i = 0; i < len; ++i)
	{
		match[i] = canMatch(input + i, rule);
		if ((max_pos < 0) || (match[i] > match[max_pos]))
		{
			max_pos = i;
		}
	}
	if ((max_pos < 0) || (match[max_pos] <= 0))
	{
		//不匹配
		output = (char *) malloc(sizeof(char));
		*output = 0;   // \0
		return output;
	}
	for (i = 0; i < len;)
	{
		if (match[i] == match[max_pos])
		{
			//找到匹配
			output = str_join(output, input + i, match[i]);
			i += match[i];
		}
		else
		{
			++i;
		}
	}
	free(match);
	return output;
}


//解法二
//copyright@chpeih 2013/4/23
char* my_find(char input[], char rule[])
{
	//write your code here
	int len1, len2;
	for (len1 = 0; input[len1]; len1++);
	for (len2 = 0; rule[len2]; len2++);
	int MAXN = len1 > len2 ? (len1 + 1) : (len2 + 1);
	int  **dp;

	//dp[i][j]表示字符串1和字符串2分别以i j结尾匹配的最大长度
	//记录dp[i][j]是由之前那个节点推算过来  i*MAXN+j
	dp = new int *[len1 + 1];
	for (int i = 0; i <= len1; i++)
	{
		dp[i] = new int[len2 + 1];

	}

	dp[0][0] = 0;
	for (int i = 1; i <= len2; i++)
		dp[0][i] = -1;
	for (int i = 1; i <= len1; i++)
		dp[i][0] = 0;

	for (int i = 1; i <= len1; i++)
	{
		for (int j = 1; j <= len2; j++)
		{
			if (rule[j - 1] == '*')
			{
				dp[i][j] = -1;
				if (dp[i - 1][j - 1] != -1)
				{
					dp[i][j] = dp[i - 1][j - 1] + 1;

				}
				if (dp[i - 1][j] != -1 && dp[i][j] < dp[i - 1][j] + 1)
				{
					dp[i][j] = dp[i - 1][j] + 1;
				}
			}
			else if (rule[j - 1] == '?')
			{
				if (dp[i - 1][j - 1] != -1)
				{
					dp[i][j] = dp[i - 1][j - 1] + 1;

				}
				else dp[i][j] = -1;
			}
			else
			{
				if (dp[i - 1][j - 1] != -1 && input[i - 1] == rule[j - 1])
				{
					dp[i][j] = dp[i - 1][j - 1] + 1;
				}
				else dp[i][j] = -1;
			}
		}
	}

	int m = -1;//记录最大字符串长度
	int *ans = new int[len1];
	int count_ans = 0;//记录答案个数
	char *returnans = new char[len1 + 1];
	int count = 0;
	for (int i = 1; i <= len1; i++)
		if (dp[i][len2] > m)
		{
			m = dp[i][len2];
			count_ans = 0;
			ans[count_ans++] = i - m;
		}
		else if (dp[i][len2] != -1 && dp[i][len2] == m)
		{
			ans[count_ans++] = i - m;
		}

		if (count_ans != 0)
		{
			int len = ans[0];
			for (int i = 0; i < m; i++)
			{
				printf("%c", input[i + ans[0]]);
				returnans[count++] = input[i + ans[0]];
			}
			for (int j = 1; j < count_ans; j++)
			{
				printf(" ");
				returnans[count++] = ' ';
				len = ans[j];
				for (int i = 0; i < m; i++)
				{
					printf("%c", input[i + ans[j]]);
					returnans[count++] = input[i + ans[j]];
				}
			}
			printf("\n");
			returnans[count++] = '\0';
		}

		return returnans;
}


================================================
FILE: ebook/code/c/1.4:字符串转换成整数.c
================================================
int StrToInt(const char* str)
{
	static const int MAX_INT = (int)((unsigned)~0 >> 1);
	static const int MIN_INT = -(int)((unsigned)~0 >> 1) - 1;
	unsigned int n = 0;

	//判断是否输入为空
	if (str == 0)
	{
		return 0;
	}

	//处理空格
	while (isspace(*str))
		++str;

	//处理正负
	int sign = 1;
	if (*str == '+' || *str == '-')
	{
		if (*str == '-')
			sign = -1;
		++str;
	}

	//确定是数字后才执行循环
	while (isdigit(*str))
	{
		//处理溢出
		int c = *str - '0';
		if (sign > 0 && (n > MAX_INT / 10 || (n == MAX_INT / 10 && c > MAX_INT % 10)))
		{
			n = MAX_INT;
			break;
		}
		else if (sign < 0 && (n >(unsigned)MIN_INT / 10 || (n == (unsigned)MIN_INT / 10 && c > (unsigned)MIN_INT % 10)))
		{
			n = MIN_INT;
			break;
		}

		//把之前得到的数字乘以10,再加上当前字符表示的数字。
		n = n * 10 + c;
		++str;
	}
	return sign > 0 ? n : -n;
}


================================================
FILE: ebook/code/c/1.7:字符串的全排列.c
================================================
//解法一、代码①
#include "stdafx.h"
#include <algorithm>
#include <iostream>
using namespace std;

void calcAllPermutation(char* perm, int from, int to)
{
	if (to <= 1)
	{
		return;
	}

	if (from == to)
	{
		for (int i = 0; i <= to; i++)
			cout << perm[i];
		cout << endl;
	}
	else
	{
		for (int j = from; j <= to; j++)
		{
			swap(perm[j], perm[from]);
			calcAllPermutation(perm, from + 1, to);
			swap(perm[j], perm[from]);
		}
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	char a[] = "abc";
	cout << a << "所有全排列的结果为:" << endl;
	calcAllPermutation(a, 0, 2);
	system("pause");
	return 0;
}


//解法二 代码一
#include "stdafx.h"
#include <algorithm>
#include <iostream>
using namespace std;

void calcAllPermutation(char* perm, int num)
{
	if (num < 1)
		return;

	for (int i = 0; i < num; i++)
	{
		cout << perm[i];
	}
	cout << endl;

	while (true)
	{
		int i;
		for (i = num - 2; i >= 0; --i)
		{
			if (perm[i] < perm[i + 1])
				break;
		}
		if (i < 0)
		{
			break;  // 已经找到所有排列
		}
		int k;
		for (k = num - 1; k > i; --k)
		{
			if (perm[k] > perm[i])
				break;
		}
		swap(perm[i], perm[k]);
		//reverse 左闭右开
		reverse(perm + i + 1, perm + num);
		for (int i = 0; i < num; i++)
		{
			cout <<perm[i];
		}
		cout << endl;
	}
}

int main()
{
	char a[] = "123";
	calcAllPermutation(a, 3);
	return 0;
}



//解法二 代码二
// 1.7 字符串的全排列.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#include <algorithm>
#include <iostream>
using namespace std;

bool CalcAllPermutation(char* perm, int num){
	int i;

	//①找到排列中最后(最右)一个升序的首位位置i,x = ai
	for (i = num - 2; (i >= 0) && (perm[i] >= perm[i + 1]); --i){
		;
	}
	// 已经找到所有排列
	if (i < 0){
		return false;
	}

	int k;
	//②找到排列中第i位右边最后一个比ai 大的位置j,y = aj
	for (k = num - 1; (k > i) && (perm[k] <= perm[i]); --k){
		;
	}

	//③交换x,y
	swap(perm[i], perm[k]);
	//④把第(i+ 1)位到最后的部分翻转
	reverse(perm + i + 1, perm + num);
	return true;
}

int main()
{
	char a[] = "123";
	do{
		for (int i = 0; i < 3; ++i)
			cout << a[i];
		cout << endl;
	} while (CalcAllPermutation(a, 3));
	return 0;
}


//类似问题
//假设str已经有序,from 一直很安静  
void perm(char *str, int size, int resPos)  
{  
	if(resPos == size)  
		print(result);  
	else  
	{  
		for(int i = 0; i < size; ++i)  
		{  
			result[resPos] = str[i];  
			perm(str, size, resPos + 1);  
		}  
	}  
}  


================================================
FILE: ebook/code/c/10.1.3:教你一步一步用c语言实现sift算法、下.c
================================================
//下采样原来的图像,返回缩小2倍尺寸的图像  
CvMat * halfSizeImage(CvMat * im)   
{  
	unsigned int i,j;  
	int w = im->cols/2;  
	int h = im->rows/2;   
	CvMat *imnew = cvCreateMat(h, w, CV_32FC1);  

#define Im(ROW,COL) ((float *)(im->data.fl + im->step/sizeof(float) *(ROW)))[(COL)]  
#define Imnew(ROW,COL) ((float *)(imnew->data.fl + imnew->step/sizeof(float) *(ROW)))[(COL)]  
	for ( j = 0; j < h; j++)   
		for ( i = 0; i < w; i++)   
			Imnew(j,i)=Im(j*2, i*2);  
	return imnew;  
}  

//上采样原来的图像,返回放大2倍尺寸的图像  
CvMat * doubleSizeImage(CvMat * im)   
{  
	unsigned int i,j;  
	int w = im->cols*2;  
	int h = im->rows*2;   
	CvMat *imnew = cvCreateMat(h, w, CV_32FC1);  

#define Im(ROW,COL) ((float *)(im->data.fl + im->step/sizeof(float) *(ROW)))[(COL)]  
#define Imnew(ROW,COL) ((float *)(imnew->data.fl + imnew->step/sizeof(float) *(ROW)))[(COL)]  

	for ( j = 0; j < h; j++)   
		for ( i = 0; i < w; i++)   
			Imnew(j,i)=Im(j/2, i/2);  

	return imnew;  
}  

//上采样原来的图像,返回放大2倍尺寸的线性插值图像  
CvMat * doubleSizeImage2(CvMat * im)   
{  
	unsigned int i,j;  
	int w = im->cols*2;  
	int h = im->rows*2;   
	CvMat *imnew = cvCreateMat(h, w, CV_32FC1);  

#define Im(ROW,COL) ((float *)(im->data.fl + im->step/sizeof(float) *(ROW)))[(COL)]  
#define Imnew(ROW,COL) ((float *)(imnew->data.fl + imnew->step/sizeof(float) *(ROW)))[(COL)]  

	// fill every pixel so we don't have to worry about skipping pixels later  
	for ( j = 0; j < h; j++)   
	{  
		for ( i = 0; i < w; i++)   
		{  
			Imnew(j,i)=Im(j/2, i/2);  
		}  
	}  
	/* 
	A B C 
	E F G 
	H I J 
	pixels A C H J are pixels from original image 
	pixels B E G I F are interpolated pixels 
	*/  
	// interpolate pixels B and I  
	for ( j = 0; j < h; j += 2)  
		for ( i = 1; i < w - 1; i += 2)  
			Imnew(j,i)=0.5*(Im(j/2, i/2)+Im(j/2, i/2+1));  
	// interpolate pixels E and G  
	for ( j = 1; j < h - 1; j += 2)  
		for ( i = 0; i < w; i += 2)  
			Imnew(j,i)=0.5*(Im(j/2, i/2)+Im(j/2+1, i/2));  
	// interpolate pixel F  
	for ( j = 1; j < h - 1; j += 2)  
		for ( i = 1; i < w - 1; i += 2)  
			Imnew(j,i)=0.25*(Im(j/2, i/2)+Im(j/2+1, i/2)+Im(j/2, i/2+1)+Im(j/2+1, i/2+1));  
	return imnew;  
}  

//双线性插值,返回像素间的灰度值  
float getPixelBI(CvMat * im, float col, float row)   
{  
	int irow, icol;  
	float rfrac, cfrac;  
	float row1 = 0, row2 = 0;  
	int width=im->cols;  
	int height=im->rows;  
#define ImMat(ROW,COL) ((float *)(im->data.fl + im->step/sizeof(float) *(ROW)))[(COL)]  

	irow = (int) row;  
	icol = (int) col;  

	if (irow < 0 || irow >= height  
		|| icol < 0 || icol >= width)  
		return 0;  
	if (row > height - 1)  
		row = height - 1;  
	if (col > width - 1)  
		col = width - 1;  
	rfrac = 1.0 - (row - (float) irow);  
	cfrac = 1.0 - (col - (float) icol);  
	if (cfrac < 1)   
	{  
		row1 = cfrac * ImMat(irow,icol) + (1.0 - cfrac) * ImMat(irow,icol+1);  
	}   
	else   
	{  
		row1 = ImMat(irow,icol);  
	}  
	if (rfrac < 1)   
	{  
		if (cfrac < 1)   
		{  
			row2 = cfrac * ImMat(irow+1,icol) + (1.0 - cfrac) * ImMat(irow+1,icol+1);  
		} else   
		{  
			row2 = ImMat(irow+1,icol);  
		}  
	}  
	return rfrac * row1 + (1.0 - rfrac) * row2;  
}  

//矩阵归一化  
void normalizeMat(CvMat* mat)   
{  
#define Mat(ROW,COL) ((float *)(mat->data.fl + mat->step/sizeof(float) *(ROW)))[(COL)]  
	float sum = 0;  

	for (unsigned int j = 0; j < mat->rows; j++)   
		for (unsigned int i = 0; i < mat->cols; i++)   
			sum += Mat(j,i);  
	for ( j = 0; j < mat->rows; j++)   
		for (unsigned int i = 0; i < mat->rows; i++)   
			Mat(j,i) /= sum;  
}  

//向量归一化  
void normalizeVec(float* vec, int dim)   
{  
	unsigned int i;  
	float sum = 0;  
	for ( i = 0; i < dim; i++)  
		sum += vec[i];  
	for ( i = 0; i < dim; i++)  
		vec[i] /= sum;  
}  

//得到向量的欧式长度,2-范数  
float GetVecNorm( float* vec, int dim )  
{  
	float sum=0.0;  
	for (unsigned int i=0;i<dim;i++)  
		sum+=vec[i]*vec[i];  
	return sqrt(sum);  
}  

//产生1D高斯核  
float* GaussianKernel1D(float sigma, int dim)   
{  

	unsigned int i;  
	//printf("GaussianKernel1D(): Creating 1x%d vector for sigma=%.3f gaussian kernel/n", dim, sigma);  

	float *kern=(float*)malloc( dim*sizeof(float) );  
	float s2 = sigma * sigma;  
	int c = dim / 2;  
	float m= 1.0/(sqrt(2.0 * CV_PI) * sigma);  
	double v;   
	for ( i = 0; i < (dim + 1) / 2; i++)   
	{  
		v = m * exp(-(1.0*i*i)/(2.0 * s2)) ;  
		kern[c+i] = v;  
		kern[c-i] = v;  
	}  
	//   normalizeVec(kern, dim);  
	// for ( i = 0; i < dim; i++)  
	//  printf("%f  ", kern[i]);  
	//  printf("/n");  
	return kern;  
}  

//产生2D高斯核矩阵  
CvMat* GaussianKernel2D(float sigma)   
{  
	// int dim = (int) max(3.0f, GAUSSKERN * sigma);  
	int dim = (int) max(3.0f, 2.0 * GAUSSKERN *sigma + 1.0f);  
	// make dim odd  
	if (dim % 2 == 0)  
		dim++;  
	//printf("GaussianKernel(): Creating %dx%d matrix for sigma=%.3f gaussian/n", dim, dim, sigma);  
	CvMat* mat=cvCreateMat(dim, dim, CV_32FC1);  
#define Mat(ROW,COL) ((float *)(mat->data.fl + mat->step/sizeof(float) *(ROW)))[(COL)]  
	float s2 = sigma * sigma;  
	int c = dim / 2;  
	//printf("%d %d/n", mat.size(), mat[0].size());  
	float m= 1.0/(sqrt(2.0 * CV_PI) * sigma);  
	for (int i = 0; i < (dim + 1) / 2; i++)   
	{  
		for (int j = 0; j < (dim + 1) / 2; j++)   
		{  
			//printf("%d %d %d/n", c, i, j);  
			float v = m * exp(-(1.0*i*i + 1.0*j*j) / (2.0 * s2));  
			Mat(c+i,c+j) =v;  
			Mat(c-i,c+j) =v;  
			Mat(c+i,c-j) =v;  
			Mat(c-i,c-j) =v;  
		}  
	}  
	// normalizeMat(mat);  
	return mat;  
}  

//x方向像素处作卷积  
float ConvolveLocWidth(float* kernel, int dim, CvMat * src, int x, int y)   
{  
#define Src(ROW,COL) ((float *)(src->data.fl + src->step/sizeof(float) *(ROW)))[(COL)]  
	unsigned int i;  
	float pixel = 0;  
	int col;  
	int cen = dim / 2;  
	//printf("ConvolveLoc(): Applying convoluation at location (%d, %d)/n", x, y);  
	for ( i = 0; i < dim; i++)   
	{  
		col = x + (i - cen);  
		if (col < 0)  
			col = 0;  
		if (col >= src->cols)  
			col = src->cols - 1;  
		pixel += kernel[i] * Src(y,col);  
	}  
	if (pixel > 1)  
		pixel = 1;  
	return pixel;  
}  

//x方向作卷积  
void Convolve1DWidth(float* kern, int dim, CvMat * src, CvMat * dst)   
{  
#define DST(ROW,COL) ((float *)(dst->data.fl + dst->step/sizeof(float) *(ROW)))[(COL)]  
	unsigned int i,j;  

	for ( j = 0; j < src->rows; j++)   
	{  
		for ( i = 0; i < src->cols; i++)   
		{  
			//printf("%d, %d/n", i, j);  
			DST(j,i) = ConvolveLocWidth(kern, dim, src, i, j);  
		}  
	}  
}  

//y方向像素处作卷积  
float ConvolveLocHeight(float* kernel, int dim, CvMat * src, int x, int y)   
{  
#define Src(ROW,COL) ((float *)(src->data.fl + src->step/sizeof(float) *(ROW)))[(COL)]  
	unsigned int j;  
	float pixel = 0;  
	int cen = dim / 2;  
	//printf("ConvolveLoc(): Applying convoluation at location (%d, %d)/n", x, y);  
	for ( j = 0; j < dim; j++)   
	{  
		int row = y + (j - cen);  
		if (row < 0)  
			row = 0;  
		if (row >= src->rows)  
			row = src->rows - 1;  
		pixel += kernel[j] * Src(row,x);  
	}  
	if (pixel > 1)  
		pixel = 1;  
	return pixel;  
}  

//y方向作卷积  
void Convolve1DHeight(float* kern, int dim, CvMat * src, CvMat * dst)   
{  
#define Dst(ROW,COL) ((float *)(dst->data.fl + dst->step/sizeof(float) *(ROW)))[(COL)]  
	unsigned int i,j;  
	for ( j = 0; j < src->rows; j++)   
	{  
		for ( i = 0; i < src->cols; i++)   
		{  
			//printf("%d, %d/n", i, j);  
			Dst(j,i) = ConvolveLocHeight(kern, dim, src, i, j);  
		}  
	}  
}  

//卷积模糊图像  
int BlurImage(CvMat * src, CvMat * dst, float sigma)   
{  
	float* convkernel;  
	int dim = (int) max(3.0f, 2.0 * GAUSSKERN * sigma + 1.0f);  
	CvMat *tempMat;  
	// make dim odd  
	if (dim % 2 == 0)  
		dim++;  
	tempMat = cvCreateMat(src->rows, src->cols, CV_32FC1);  
	convkernel = GaussianKernel1D(sigma, dim);  

	Convolve1DWidth(convkernel, dim, src, tempMat);  
	Convolve1DHeight(convkernel, dim, tempMat, dst);  
	cvReleaseMat(&tempMat);  
	return dim;  
}

//SIFT算法第一步 
CvMat *ScaleInitImage(CvMat * im)   
{  
	double sigma,preblur_sigma;  
	CvMat *imMat;  
	CvMat * dst;  
	CvMat *tempMat;  
	//首先对图像进行平滑滤波,抑制噪声  
	imMat = cvCreateMat(im->rows, im->cols, CV_32FC1);  
	BlurImage(im, imMat, INITSIGMA);  
	//针对两种情况分别进行处理:初始化放大原始图像或者在原图像基础上进行后续操作  
	//建立金字塔的最底层  
	if (DOUBLE_BASE_IMAGE_SIZE)   
	{  
		tempMat = doubleSizeImage2(imMat);//对扩大两倍的图像进行二次采样,采样率为0.5,采用线性插值  
#define TEMPMAT(ROW,COL) ((float *)(tempMat->data.fl + tempMat->step/sizeof(float) * (ROW)))[(COL)]  

		dst = cvCreateMat(tempMat->rows, tempMat->cols, CV_32FC1);  
		preblur_sigma = 1.0;//sqrt(2 - 4*INITSIGMA*INITSIGMA);  
		BlurImage(tempMat, dst, preblur_sigma);   

		// The initial blurring for the first image of the first octave of the pyramid.  
		sigma = sqrt( (4*INITSIGMA*INITSIGMA) + preblur_sigma * preblur_sigma );  
		//  sigma = sqrt(SIGMA * SIGMA - INITSIGMA * INITSIGMA * 4);  
		//printf("Init Sigma: %f/n", sigma);  
		BlurImage(dst, tempMat, sigma);       //得到金字塔的最底层-放大2倍的图像  
		cvReleaseMat( &dst );   
		return tempMat;  
	}   
	else   
	{  
		dst = cvCreateMat(im->rows, im->cols, CV_32FC1);  
		//sigma = sqrt(SIGMA * SIGMA - INITSIGMA * INITSIGMA);  
		preblur_sigma = 1.0;//sqrt(2 - 4*INITSIGMA*INITSIGMA);  
		sigma = sqrt( (4*INITSIGMA*INITSIGMA) + preblur_sigma * preblur_sigma );  
		//printf("Init Sigma: %f/n", sigma);  
		BlurImage(imMat, dst, sigma);        //得到金字塔的最底层:原始图像大小  
		return dst;  
	}   
}

//SIFT算法第二步  
ImageOctaves* BuildGaussianOctaves(CvMat * image)   
{  
	ImageOctaves *octaves;  
	CvMat *tempMat;  
	CvMat *dst;  
	CvMat *temp;  

	int i,j;  
	double k = pow(2, 1.0/((float)SCALESPEROCTAVE));  //方差倍数  
	float preblur_sigma, initial_sigma , sigma1,sigma2,sigma,absolute_sigma,sigma_f;  
	//计算金字塔的阶梯数目  
	int dim = min(image->rows, image->cols);  
	int numoctaves = (int) (log((double) dim) / log(2.0)) - 2;    //金字塔阶数  
	//限定金字塔的阶梯数  
	numoctaves = min(numoctaves, MAXOCTAVES);  
	//为高斯金塔和DOG金字塔分配内存  
	octaves=(ImageOctaves*) malloc( numoctaves * sizeof(ImageOctaves) );  
	DOGoctaves=(ImageOctaves*) malloc( numoctaves * sizeof(ImageOctaves) );  

	printf("BuildGaussianOctaves(): Base image dimension is %dx%d/n", (int)(0.5*(image->cols)), (int)(0.5*(image->rows)) );  
	printf("BuildGaussianOctaves(): Building %d octaves/n", numoctaves);  

	// start with initial source image  
	tempMat=cvCloneMat( image );  
	// preblur_sigma = 1.0;//sqrt(2 - 4*INITSIGMA*INITSIGMA);  
	initial_sigma = sqrt(2);//sqrt( (4*INITSIGMA*INITSIGMA) + preblur_sigma * preblur_sigma );  
	//   initial_sigma = sqrt(SIGMA * SIGMA - INITSIGMA * INITSIGMA * 4);  

	//在每一阶金字塔图像中建立不同的尺度图像  
	for ( i = 0; i < numoctaves; i++)   
	{     
		//首先建立金字塔每一阶梯的最底层,其中0阶梯的最底层已经建立好  
		printf("Building octave %d of dimesion (%d, %d)/n", i, tempMat->cols,tempMat->rows);  
		//为各个阶梯分配内存  
		octaves[i].Octave= (ImageLevels*) malloc( (SCALESPEROCTAVE + 3) * sizeof(ImageLevels) );  
		DOGoctaves[i].Octave= (ImageLevels*) malloc( (SCALESPEROCTAVE + 2) * sizeof(ImageLevels) );  
		//存储各个阶梯的最底层  
		(octaves[i].Octave)[0].Level=tempMat;  

		octaves[i].col=tempMat->cols;  
		octaves[i].row=tempMat->rows;  
		DOGoctaves[i].col=tempMat->cols;  
		DOGoctaves[i].row=tempMat->rows;  
		if (DOUBLE_BASE_IMAGE_SIZE)  
			octaves[i].subsample=pow(2,i)*0.5;  
		else  
			octaves[i].subsample=pow(2,i);  

		if(i==0)       
		{  
			(octaves[0].Octave)[0].levelsigma = initial_sigma;  
			(octaves[0].Octave)[0].absolute_sigma = initial_sigma;  
			printf("0 scale and blur sigma : %f /n", (octaves[0].subsample) * ((octaves[0].Octave)[0].absolute_sigma));  
		}  
		else  
		{  
			(octaves[i].Octave)[0].levelsigma = (octaves[i-1].Octave)[SCALESPEROCTAVE].levelsigma;  
			(octaves[i].Octave)[0].absolute_sigma = (octaves[i-1].Octave)[SCALESPEROCTAVE].absolute_sigma;  
			printf( "0 scale and blur sigma : %f /n", ((octaves[i].Octave)[0].absolute_sigma) );  
		}  
		sigma = initial_sigma;  
		//建立本阶梯其他层的图像  
		for ( j =  1; j < SCALESPEROCTAVE + 3; j++)   
		{  
			dst = cvCreateMat(tempMat->rows, tempMat->cols, CV_32FC1);//用于存储高斯层  
			temp = cvCreateMat(tempMat->rows, tempMat->cols, CV_32FC1);//用于存储DOG层  
			// 2 passes of 1D on original  
			//   if(i!=0)  
			//   {  
			//       sigma1 = pow(k, j - 1) * ((octaves[i-1].Octave)[j-1].levelsigma);  
			//          sigma2 = pow(k, j) * ((octaves[i].Octave)[j-1].levelsigma);  
			//       sigma = sqrt(sigma2*sigma2 - sigma1*sigma1);  
			sigma_f= sqrt(k*k-1)*sigma;  
			//   }  
			//   else  
			//   {  
			//       sigma = sqrt(SIGMA * SIGMA - INITSIGMA * INITSIGMA * 4)*pow(k,j);  
			//   }    
			sigma = k*sigma;  
			absolute_sigma = sigma * (octaves[i].subsample);  
			printf("%d scale and Blur sigma: %f  /n", j, absolute_sigma);  

			(octaves[i].Octave)[j].levelsigma = sigma;  
			(octaves[i].Octave)[j].absolute_sigma = absolute_sigma;  
			//产生高斯层  
			int length=BlurImage((octaves[i].Octave)[j-1].Level, dst, sigma_f);//相应尺度  
			(octaves[i].Octave)[j].levelsigmalength = length;  
			(octaves[i].Octave)[j].Level=dst;  
			//产生DOG层  
			cvSub( ((octaves[i].Octave)[j]).Level, ((octaves[i].Octave)[j-1]).Level, temp, 0 );  
			//         cvAbsDiff( ((octaves[i].Octave)[j]).Level, ((octaves[i].Octave)[j-1]).Level, temp );  
			((DOGoctaves[i].Octave)[j-1]).Level=temp;  
		}  
		// halve the image size for next iteration  
		tempMat  = halfSizeImage( ( (octaves[i].Octave)[SCALESPEROCTAVE].Level ) );  
	}  
	return octaves;  
}

//SIFT算法第三步,特征点位置检测,  
int DetectKeypoint(int numoctaves, ImageOctaves *GaussianPyr)  
{  
	//计算用于DOG极值点检测的主曲率比的阈值  
	double curvature_threshold;  
	curvature_threshold= ((CURVATURE_THRESHOLD + 1)*(CURVATURE_THRESHOLD + 1))/CURVATURE_THRESHOLD;  
#define ImLevels(OCTAVE,LEVEL,ROW,COL) ((float *)(DOGoctaves[(OCTAVE)].Octave[(LEVEL)].Level->data.fl + DOGoctaves[(OCTAVE)].Octave[(LEVEL)].Level->step/sizeof(float) *(ROW)))[(COL)]  

	int   keypoint_count = 0;     
	for (int i=0; i<numoctaves; i++)    
	{          
		for(int j=1;j<SCALESPEROCTAVE+1;j++)//取中间的scaleperoctave个层  
		{    
			//在图像的有效区域内寻找具有显著性特征的局部最大值  
			//float sigma=(GaussianPyr[i].Octave)[j].levelsigma;  
			//int dim = (int) (max(3.0f, 2.0*GAUSSKERN *sigma + 1.0f)*0.5);  
			int dim = (int)(0.5*((GaussianPyr[i].Octave)[j].levelsigmalength)+0.5);  
			for (int m=dim;m<((DOGoctaves[i].row)-dim);m++)   
				for(int n=dim;n<((DOGoctaves[i].col)-dim);n++)  
				{       
					if ( fabs(ImLevels(i,j,m,n))>= CONTRAST_THRESHOLD )  
					{  

						if ( ImLevels(i,j,m,n)!=0.0 )  //1、首先是非零  
						{  
							float inf_val=ImLevels(i,j,m,n);  
							if(( (inf_val <= ImLevels(i,j-1,m-1,n-1))&&  
								(inf_val <= ImLevels(i,j-1,m  ,n-1))&&  
								(inf_val <= ImLevels(i,j-1,m+1,n-1))&&  
								(inf_val <= ImLevels(i,j-1,m-1,n  ))&&  
								(inf_val <= ImLevels(i,j-1,m  ,n  ))&&  
								(inf_val <= ImLevels(i,j-1,m+1,n  ))&&  
								(inf_val <= ImLevels(i,j-1,m-1,n+1))&&  
								(inf_val <= ImLevels(i,j-1,m  ,n+1))&&  
								(inf_val <= ImLevels(i,j-1,m+1,n+1))&&    //底层的小尺度9  

								(inf_val <= ImLevels(i,j,m-1,n-1))&&  
								(inf_val <= ImLevels(i,j,m  ,n-1))&&  
								(inf_val <= ImLevels(i,j,m+1,n-1))&&  
								(inf_val <= ImLevels(i,j,m-1,n  ))&&  
								(inf_val <= ImLevels(i,j,m+1,n  ))&&  
								(inf_val <= ImLevels(i,j,m-1,n+1))&&  
								(inf_val <= ImLevels(i,j,m  ,n+1))&&  
								(inf_val <= ImLevels(i,j,m+1,n+1))&&     //当前层8  

								(inf_val <= ImLevels(i,j+1,m-1,n-1))&&  
								(inf_val <= ImLevels(i,j+1,m  ,n-1))&&  
								(inf_val <= ImLevels(i,j+1,m+1,n-1))&&  
								(inf_val <= ImLevels(i,j+1,m-1,n  ))&&  
								(inf_val <= ImLevels(i,j+1,m  ,n  ))&&  
								(inf_val <= ImLevels(i,j+1,m+1,n  ))&&  
								(inf_val <= ImLevels(i,j+1,m-1,n+1))&&  
								(inf_val <= ImLevels(i,j+1,m  ,n+1))&&  
								(inf_val <= ImLevels(i,j+1,m+1,n+1))     //下一层大尺度9          
								) ||   
								( (inf_val >= ImLevels(i,j-1,m-1,n-1))&&  
								(inf_val >= ImLevels(i,j-1,m  ,n-1))&&  
								(inf_val >= ImLevels(i,j-1,m+1,n-1))&&  
								(inf_val >= ImLevels(i,j-1,m-1,n  ))&&  
								(inf_val >= ImLevels(i,j-1,m  ,n  ))&&  
								(inf_val >= ImLevels(i,j-1,m+1,n  ))&&  
								(inf_val >= ImLevels(i,j-1,m-1,n+1))&&  
								(inf_val >= ImLevels(i,j-1,m  ,n+1))&&  
								(inf_val >= ImLevels(i,j-1,m+1,n+1))&&  

								(inf_val >= ImLevels(i,j,m-1,n-1))&&  
								(inf_val >= ImLevels(i,j,m  ,n-1))&&  
								(inf_val >= ImLevels(i,j,m+1,n-1))&&  
								(inf_val >= ImLevels(i,j,m-1,n  ))&&  
								(inf_val >= ImLevels(i,j,m+1,n  ))&&  
								(inf_val >= ImLevels(i,j,m-1,n+1))&&  
								(inf_val >= ImLevels(i,j,m  ,n+1))&&  
								(inf_val >= ImLevels(i,j,m+1,n+1))&&   

								(inf_val >= ImLevels(i,j+1,m-1,n-1))&&  
								(inf_val >= ImLevels(i,j+1,m  ,n-1))&&  
								(inf_val >= ImLevels(i,j+1,m+1,n-1))&&  
								(inf_val >= ImLevels(i,j+1,m-1,n  ))&&  
								(inf_val >= ImLevels(i,j+1,m  ,n  ))&&  
								(inf_val >= ImLevels(i,j+1,m+1,n  ))&&  
								(inf_val >= ImLevels(i,j+1,m-1,n+1))&&  
								(inf_val >= ImLevels(i,j+1,m  ,n+1))&&  
								(inf_val >= ImLevels(i,j+1,m+1,n+1))   
								) )      //2、满足26个中极值点  
							{     
								//此处可存储  
								//然后必须具有明显的显著性,即必须大于CONTRAST_THRESHOLD=0.02  
								if ( fabs(ImLevels(i,j,m,n))>= CONTRAST_THRESHOLD )  
								{  
									//最后显著处的特征点必须具有足够的曲率比,CURVATURE_THRESHOLD=10.0,首先计算Hessian矩阵  
									// Compute the entries of the Hessian matrix at the extrema location.  
									/* 
									1   0   -1 
									0   0   0 
									-1   0   1         *0.25 
									*/  
									// Compute the trace and the determinant of the Hessian.  
									//Tr_H = Dxx + Dyy;  
									//Det_H = Dxx*Dyy - Dxy^2;  
									float Dxx,Dyy,Dxy,Tr_H,Det_H,curvature_ratio;  
									Dxx = ImLevels(i,j,m,n-1) + ImLevels(i,j,m,n+1)-2.0*ImLevels(i,j,m,n);  
									Dyy = ImLevels(i,j,m-1,n) + ImLevels(i,j,m+1,n)-2.0*ImLevels(i,j,m,n);  
									Dxy = ImLevels(i,j,m-1,n-1) + ImLevels(i,j,m+1,n+1) - ImLevels(i,j,m+1,n-1) - ImLevels(i,j,m-1,n+1);  
									Tr_H = Dxx + Dyy;  
									Det_H = Dxx*Dyy - Dxy*Dxy;  
									// Compute the ratio of the principal curvatures.  
									curvature_ratio = (1.0*Tr_H*Tr_H)/Det_H;  
									if ( (Det_H>=0.0) && (curvature_ratio <= curvature_threshold) )  //最后得到最具有显著性特征的特征点  
									{  
										//将其存储起来,以计算后面的特征描述字  
										keypoint_count++;  
										Keypoint k;  
										/* Allocate memory for the keypoint. */  
										k = (Keypoint) malloc(sizeof(struct KeypointSt));  
										k->next = keypoints;  
										keypoints = k;  
										k->row = m*(GaussianPyr[i].subsample);  
										k->col =n*(GaussianPyr[i].subsample);  
										k->sy = m;    //行  
										k->sx = n;    //列  
										k->octave=i;  
										k->level=j;  
										k->scale = (GaussianPyr[i].Octave)[j].absolute_sigma;        
									}//if >curvature_thresh  
								}//if >contrast  
							}//if inf value  
						}//if non zero  
					}//if >contrast  
				}  //for concrete image level col  
		}//for levels  
	}//for octaves  
	return keypoint_count;  
}  

//在图像中,显示SIFT特征点的位置  
void DisplayKeypointLocation(IplImage* image, ImageOctaves *GaussianPyr)  
{  

	Keypoint p = keypoints; // p指向第一个结点  
	while(p) // 没到表尾  
	{     
		cvLine( image, cvPoint((int)((p->col)-3),(int)(p->row)),   
			cvPoint((int)((p->col)+3),(int)(p->row)), CV_RGB(255,255,0),  
			1, 8, 0 );  
		cvLine( image, cvPoint((int)(p->col),(int)((p->row)-3)),   
			cvPoint((int)(p->col),(int)((p->row)+3)), CV_RGB(255,255,0),  
			1, 8, 0 );  
		//  cvCircle(image,cvPoint((uchar)(p->col),(uchar)(p->row)),  
		//   (int)((GaussianPyr[p->octave].Octave)[p->level].absolute_sigma),  
		//   CV_RGB(255,0,0),1,8,0);  
		p=p->next;  
	}   
}  

// Compute the gradient direction and magnitude of the gaussian pyramid images  
void ComputeGrad_DirecandMag(int numoctaves, ImageOctaves *GaussianPyr)  
{  
	// ImageOctaves *mag_thresh ;  
	mag_pyr=(ImageOctaves*) malloc( numoctaves * sizeof(ImageOctaves) );  
	grad_pyr=(ImageOctaves*) malloc( numoctaves * sizeof(ImageOctaves) );  
	// float sigma=( (GaussianPyr[0].Octave)[SCALESPEROCTAVE+2].absolute_sigma ) / GaussianPyr[0].subsample;  
	// int dim = (int) (max(3.0f, 2 * GAUSSKERN *sigma + 1.0f)*0.5+0.5);  
#define ImLevels(OCTAVE,LEVEL,ROW,COL) ((float *)(GaussianPyr[(OCTAVE)].Octave[(LEVEL)].Level->data.fl + GaussianPyr[(OCTAVE)].Octave[(LEVEL)].Level->step/sizeof(float) *(ROW)))[(COL)]  
	for (int i=0; i<numoctaves; i++)    
	{          
		mag_pyr[i].Octave= (ImageLevels*) malloc( (SCALESPEROCTAVE) * sizeof(ImageLevels) );  
		grad_pyr[i].Octave= (ImageLevels*) malloc( (SCALESPEROCTAVE) * sizeof(ImageLevels) );  
		for(int j=1;j<SCALESPEROCTAVE+1;j++)//取中间的scaleperoctave个层  
		{    
			CvMat *Mag = cvCreateMat(GaussianPyr[i].row, GaussianPyr[i].col, CV_32FC1);  
			CvMat *Ori = cvCreateMat(GaussianPyr[i].row, GaussianPyr[i].col, CV_32FC1);  
			CvMat *tempMat1 = cvCreateMat(GaussianPyr[i].row, GaussianPyr[i].col, CV_32FC1);  
			CvMat *tempMat2 = cvCreateMat(GaussianPyr[i].row, GaussianPyr[i].col, CV_32FC1);  
			cvZero(Mag);  
			cvZero(Ori);  
			cvZero(tempMat1);  
			cvZero(tempMat2);   
#define MAG(ROW,COL) ((float *)(Mag->data.fl + Mag->step/sizeof(float) *(ROW)))[(COL)]     
#define ORI(ROW,COL) ((float *)(Ori->data.fl + Ori->step/sizeof(float) *(ROW)))[(COL)]    
#define TEMPMAT1(ROW,COL) ((float *)(tempMat1->data.fl + tempMat1->step/sizeof(float) *(ROW)))[(COL)]  
#define TEMPMAT2(ROW,COL) ((float *)(tempMat2->data.fl + tempMat2->step/sizeof(float) *(ROW)))[(COL)]  
			for (int m=1;m<(GaussianPyr[i].row-1);m++)   
				for(int n=1;n<(GaussianPyr[i].col-1);n++)  
				{  
					//计算幅值  
					TEMPMAT1(m,n) = 0.5*( ImLevels(i,j,m,n+1)-ImLevels(i,j,m,n-1) );  //dx  
					TEMPMAT2(m,n) = 0.5*( ImLevels(i,j,m+1,n)-ImLevels(i,j,m-1,n) );  //dy  
					MAG(m,n) = sqrt(TEMPMAT1(m,n)*TEMPMAT1(m,n)+TEMPMAT2(m,n)*TEMPMAT2(m,n));  //mag  
					//计算方向  
					ORI(m,n) =atan( TEMPMAT2(m,n)/TEMPMAT1(m,n) );  
					if (ORI(m,n)==CV_PI)  
						ORI(m,n)=-CV_PI;  
				}  
				((mag_pyr[i].Octave)[j-1]).Level=Mag;  
				((grad_pyr[i].Octave)[j-1]).Level=Ori;  
				cvReleaseMat(&tempMat1);  
				cvReleaseMat(&tempMat2);  
		}//for levels  
	}//for octaves  
}

//SIFT算法第四步:计算各个特征点的主方向,确定主方向  
void AssignTheMainOrientation(int numoctaves, ImageOctaves *GaussianPyr,ImageOctaves *mag_pyr,ImageOctaves *grad_pyr)  
{  
	// Set up the histogram bin centers for a 36 bin histogram.  
	int num_bins = 36;  
	float hist_step = 2.0*PI/num_bins;  
	float hist_orient[36];  
	for (int i=0;i<36;i++)  
		hist_orient[i]=-PI+i*hist_step;  
	float sigma1=( ((GaussianPyr[0].Octave)[SCALESPEROCTAVE].absolute_sigma) ) / (GaussianPyr[0].subsample);//SCALESPEROCTAVE+2  
	int zero_pad = (int) (max(3.0f, 2 * GAUSSKERN *sigma1 + 1.0f)*0.5+0.5);  
	//Assign orientations to the keypoints.  
#define ImLevels(OCTAVES,LEVELS,ROW,COL) ((float *)((GaussianPyr[(OCTAVES)].Octave[(LEVELS)].Level)->data.fl + (GaussianPyr[(OCTAVES)].Octave[(LEVELS)].Level)->step/sizeof(float) *(ROW)))[(COL)]  

	int keypoint_count = 0;  
	Keypoint p = keypoints; // p指向第一个结点  

	while(p) // 没到表尾  
	{  
		int i=p->octave;  
		int j=p->level;  
		int m=p->sy;   //行  
		int n=p->sx;   //列  
		if ((m>=zero_pad)&&(m<GaussianPyr[i].row-zero_pad)&&  
			(n>=zero_pad)&&(n<GaussianPyr[i].col-zero_pad) )  
		{  
			float sigma=( ((GaussianPyr[i].Octave)[j].absolute_sigma) ) / (GaussianPyr[i].subsample);  
			//产生二维高斯模板  
			CvMat* mat = GaussianKernel2D( sigma );           
			int dim=(int)(0.5 * (mat->rows));  
			//分配用于存储Patch幅值和方向的空间  
#define MAT(ROW,COL) ((float *)(mat->data.fl + mat->step/sizeof(float) *(ROW)))[(COL)]  

			//声明方向直方图变量  
			double* orienthist = (double *) malloc(36 * sizeof(double));  
			for ( int sw = 0 ; sw < 36 ; ++sw)   
			{  
				orienthist[sw]=0.0;    
			}  
			//在特征点的周围统计梯度方向  
			for (int x=m-dim,mm=0;x<=(m+dim);x++,mm++)   
				for(int y=n-dim,nn=0;y<=(n+dim);y++,nn++)  
				{       
					//计算特征点处的幅值  
					double dx = 0.5*(ImLevels(i,j,x,y+1)-ImLevels(i,j,x,y-1));  //dx  
					double dy = 0.5*(ImLevels(i,j,x+1,y)-ImLevels(i,j,x-1,y));  //dy  
					double mag = sqrt(dx*dx+dy*dy);  //mag  
					//计算方向  
					double Ori =atan( 1.0*dy/dx );  
					int binIdx = FindClosestRotationBin(36, Ori);                   //得到离现有方向最近的直方块  
					orienthist[binIdx] = orienthist[binIdx] + 1.0* mag * MAT(mm,nn);//利用高斯加权累加进直方图相应的块  
				}  
				// Find peaks in the orientation histogram using nonmax suppression.  
				AverageWeakBins (orienthist, 36);  
				// find the maximum peak in gradient orientation  
				double maxGrad = 0.0;  
				int maxBin = 0;  
				for (int b = 0 ; b < 36 ; ++b)   
				{  
					if (orienthist[b] > maxGrad)   
					{  
						maxGrad = orienthist[b];  
						maxBin = b;  
					}  
				}  
				// First determine the real interpolated peak high at the maximum bin  
				// position, which is guaranteed to be an absolute peak.  
				double maxPeakValue=0.0;  
				double maxDegreeCorrection=0.0;  
				if ( (InterpolateOrientation ( orienthist[maxBin == 0 ? (36 - 1) : (maxBin - 1)],  
					orienthist[maxBin], orienthist[(maxBin + 1) % 36],  
					&maxDegreeCorrection, &maxPeakValue)) == false)  
					printf("BUG: Parabola fitting broken");  

				// Now that we know the maximum peak value, we can find other keypoint  
				// orientations, which have to fulfill two criterias:  
				//  
				//  1. They must be a local peak themselves. Else we might add a very  
				//     similar keypoint orientation twice (imagine for example the  
				//     values: 0.4 1.0 0.8, if 1.0 is maximum peak, 0.8 is still added  
				//     with the default threshhold, but the maximum peak orientation  
				//     was already added).  
				//  2. They must have at least peakRelThresh times the maximum peak  
				//     value.  
				bool binIsKeypoint[36];  
				for ( b = 0 ; b < 36 ; ++b)   
				{  
					binIsKeypoint[b] = false;  
					// The maximum peak of course is  
					if (b == maxBin)   
					{  
						binIsKeypoint[b] = true;  
						continue;  
					}  
					// Local peaks are, too, in case they fulfill the threshhold  
					if (orienthist[b] < (peakRelThresh * maxPeakValue))  
						continue;  
					int leftI = (b == 0) ? (36 - 1) : (b - 1);  
					int rightI = (b + 1) % 36;  
					if (orienthist[b] <= orienthist[leftI] || orienthist[b] <= orienthist[rightI])  
						continue; // no local peak  
					binIsKeypoint[b] = true;  
				}  
				// find other possible locations  
				double oneBinRad = (2.0 * PI) / 36;  
				for ( b = 0 ; b < 36 ; ++b)   
				{  
					if (binIsKeypoint[b] == false)  
						continue;  
					int bLeft = (b == 0) ? (36 - 1) : (b - 1);  
					int bRight = (b + 1) % 36;  
					// Get an interpolated peak direction and value guess.  
					double peakValue;  
					double degreeCorrection;  

					double maxPeakValue, maxDegreeCorrection;                
					if (InterpolateOrientation ( orienthist[maxBin == 0 ? (36 - 1) : (maxBin - 1)],  
						orienthist[maxBin], orienthist[(maxBin + 1) % 36],  
						°reeCorrection, &peakValue) == false)  
					{  
						printf("BUG: Parabola fitting broken");  
					}  

					double degree = (b + degreeCorrection) * oneBinRad - PI;  
					if (degree < -PI)  
						degree += 2.0 * PI;  
					else if (degree > PI)  
						degree -= 2.0 * PI;  
					//存储方向,可以直接利用检测到的链表进行该步主方向的指定;  
					//分配内存重新存储特征点  
					Keypoint k;  
					/* Allocate memory for the keypoint Descriptor. */  
					k = (Keypoint) malloc(sizeof(struct KeypointSt));  
					k->next = keyDescriptors;  
					keyDescriptors = k;  
					k->descrip = (float*)malloc(LEN * sizeof(float));  
					k->row = p->row;  
					k->col = p->col;  
					k->sy = p->sy;    //行  
					k->sx = p->sx;    //列  
					k->octave = p->octave;  
					k->level = p->level;  
					k->scale = p->scale;        
					k->ori = degree;  
					k->mag = peakValue;    
				}//for  
				free(orienthist);  
		}  
		p=p->next;  
	}   
}  

//寻找与方向直方图最近的柱,确定其index   
int FindClosestRotationBin (int binCount, float angle)  
{  
	angle += CV_PI;  
	angle /= 2.0 * CV_PI;  
	// calculate the aligned bin  
	angle *= binCount;  
	int idx = (int) angle;  
	if (idx == binCount)  
		idx = 0;  
	return (idx);  
}  

// Average the content of the direction bins.  
void AverageWeakBins (double* hist, int binCount)  
{  
	// TODO: make some tests what number of passes is the best. (its clear  
	// one is not enough, as we may have something like  
	// ( 0.4, 0.4, 0.3, 0.4, 0.4 ))  
	for (int sn = 0 ; sn < 2 ; ++sn)   
	{  
		double firstE = hist[0];  
		double last = hist[binCount-1];  
		for (int sw = 0 ; sw < binCount ; ++sw)   
		{  
			double cur = hist[sw];  
			double next = (sw == (binCount - 1)) ? firstE : hist[(sw + 1) % binCount];  
			hist[sw] = (last + cur + next) / 3.0;  
			last = cur;  
		}  
	}  
}  

// Fit a parabol to the three points (-1.0 ; left), (0.0 ; middle) and  
// (1.0 ; right).  
// Formulas:  
// f(x) = a (x - c)^2 + b  
// c is the peak offset (where f'(x) is zero), b is the peak value.  
// In case there is an error false is returned, otherwise a correction  
// value between [-1 ; 1] is returned in 'degreeCorrection', where -1  
// means the peak is located completely at the left vector, and -0.5 just  
// in the middle between left and middle and > 0 to the right side. In  
// 'peakValue' the maximum estimated peak value is stored.  
bool InterpolateOrientation (double left, double middle,double right, double *degreeCorrection, double *peakValue)  
{  
	double a = ((left + right) - 2.0 * middle) / 2.0;   //抛物线捏合系数a  
	// degreeCorrection = peakValue = Double.NaN;  

	// Not a parabol  
	if (a == 0.0)  
		return false;  
	double c = (((left - middle) / a) - 1.0) / 2.0;  
	double b = middle - c * c * a;  
	if (c < -0.5 || c > 0.5)  
		return false;  
	*degreeCorrection = c;  
	*peakValue = b;  
	return true;  
}  

//显示特征点处的主方向  
void DisplayOrientation (IplImage* image, ImageOctaves *GaussianPyr)  
{  
	Keypoint p = keyDescriptors; // p指向第一个结点  
	while(p) // 没到表尾  
	{  
		float scale=(GaussianPyr[p->octave].Octave)[p->level].absolute_sigma;  
		float autoscale = 3.0;   
		float uu=autoscale*scale*cos(p->ori);  
		float vv=autoscale*scale*sin(p->ori);  
		float x=(p->col)+uu;  
		float y=(p->row)+vv;  
		cvLine( image, cvPoint((int)(p->col),(int)(p->row)),   
			cvPoint((int)x,(int)y), CV_RGB(255,255,0),  
			1, 8, 0 );  
		// Arrow head parameters  
		float alpha = 0.33; // Size of arrow head relative to the length of the vector  
		float beta = 0.33;  // Width of the base of the arrow head relative to the length  

		float xx0= (p->col)+uu-alpha*(uu+beta*vv);  
		float yy0= (p->row)+vv-alpha*(vv-beta*uu);  
		float xx1= (p->col)+uu-alpha*(uu-beta*vv);  
		float yy1= (p->row)+vv-alpha*(vv+beta*uu);  
		cvLine( image, cvPoint((int)xx0,(int)yy0),   
			cvPoint((int)x,(int)y), CV_RGB(255,255,0),  
			1, 8, 0 );  
		cvLine( image, cvPoint((int)xx1,(int)yy1),   
			cvPoint((int)x,(int)y), CV_RGB(255,255,0),  
			1, 8, 0 );  
		p=p->next;  
	}   
}

//SIFT算法第五步
void ExtractFeatureDescriptors(int numoctaves, ImageOctaves *GaussianPyr)  
{  
	// The orientation histograms have 8 bins  
	float orient_bin_spacing = PI/4;  
	float orient_angles[8]={-PI,-PI+orient_bin_spacing,-PI*0.5, -orient_bin_spacing,  
		0.0, orient_bin_spacing, PI*0.5,  PI+orient_bin_spacing};  
	//产生描述字中心各点坐标  
	float *feat_grid=(float *) malloc( 2*16 * sizeof(float));  
	for (int i=0;i<GridSpacing;i++)  
	{  
		for (int j=0;j<2*GridSpacing;++j,++j)  
		{  
			feat_grid[i*2*GridSpacing+j]=-6.0+i*GridSpacing;  
			feat_grid[i*2*GridSpacing+j+1]=-6.0+0.5*j*GridSpacing;  
		}  
	}  
	//产生网格  
	float *feat_samples=(float *) malloc( 2*256 * sizeof(float));  
	for ( i=0;i<4*GridSpacing;i++)  
	{  
		for (int j=0;j<8*GridSpacing;j+=2)  
		{  
			feat_samples[i*8*GridSpacing+j]=-(2*GridSpacing-0.5)+i;  
			feat_samples[i*8*GridSpacing+j+1]=-(2*GridSpacing-0.5)+0.5*j;  
		}  
	}  
	float feat_window = 2*GridSpacing;  
	Keypoint p = keyDescriptors; // p指向第一个结点  
	while(p) // 没到表尾  
	{  
		float scale=(GaussianPyr[p->octave].Octave)[p->level].absolute_sigma;  

		float sine = sin(p->ori);  
		float cosine = cos(p->ori);    
		//计算中心点坐标旋转之后的位置  
		float *featcenter=(float *) malloc( 2*16 * sizeof(float));  
		for (int i=0;i<GridSpacing;i++)  
		{  
			for (int j=0;j<2*GridSpacing;j+=2)  
			{  
				float x=feat_grid[i*2*GridSpacing+j];  
				float y=feat_grid[i*2*GridSpacing+j+1];  
				featcenter[i*2*GridSpacing+j]=((cosine * x + sine * y) + p->sx);  
				featcenter[i*2*GridSpacing+j+1]=((-sine * x + cosine * y) + p->sy);  
			}  
		}  
		// calculate sample window coordinates (rotated along keypoint)  
		float *feat=(float *) malloc( 2*256 * sizeof(float));  
		for ( i=0;i<64*GridSpacing;i++,i++)  
		{  
			float x=feat_samples[i];  
			float y=feat_samples[i+1];  
			feat[i]=((cosine * x + sine * y) + p->sx);  
			feat[i+1]=((-sine * x + cosine * y) + p->sy);  
		}  
		//Initialize the feature descriptor.  
		float *feat_desc = (float *) malloc( 128 * sizeof(float));  
		for (i=0;i<128;i++)  
		{  
			feat_desc[i]=0.0;  
			// printf("%f  ",feat_desc[i]);    
		}  
		//printf("/n");  
		for ( i=0;i<512;++i,++i)  
		{  
			float x_sample = feat[i];  
			float y_sample = feat[i+1];  
			// Interpolate the gradient at the sample position  
			/* 
			0   1   0 
			1   *   1 
			0   1   0   具体插值策略如图示 
			*/  
			float sample12=getPixelBI(((GaussianPyr[p->octave].Octave)[p->level]).Level, x_sample, y_sample-1);  
			float sample21=getPixelBI(((GaussianPyr[p->octave].Octave)[p->level]).Level, x_sample-1, y_sample);   
			float sample22=getPixelBI(((GaussianPyr[p->octave].Octave)[p->level]).Level, x_sample, y_sample);   
			float sample23=getPixelBI(((GaussianPyr[p->octave].Octave)[p->level]).Level, x_sample+1, y_sample);   
			float sample32=getPixelBI(((GaussianPyr[p->octave].Octave)[p->level]).Level, x_sample, y_sample+1);   
			//float diff_x = 0.5*(sample23 - sample21);  
			//float diff_y = 0.5*(sample32 - sample12);  
			float diff_x = sample23 - sample21;  
			float diff_y = sample32 - sample12;  
			float mag_sample = sqrt( diff_x*diff_x + diff_y*diff_y );  
			float grad_sample = atan( diff_y / diff_x );  
			if(grad_sample == CV_PI)  
				grad_sample = -CV_PI;  
			// Compute the weighting for the x and y dimensions.  
			float *x_wght=(float *) malloc( GridSpacing * GridSpacing * sizeof(float));  
			float *y_wght=(float *) malloc( GridSpacing * GridSpacing * sizeof(float));  
			float *pos_wght=(float *) malloc( 8*GridSpacing * GridSpacing * sizeof(float));;  
			for (int m=0;m<32;++m,++m)  
			{  
				float x=featcenter[m];  
				float y=featcenter[m+1];  
				x_wght[m/2] = max(1 - (fabs(x - x_sample)*1.0/GridSpacing), 0);  
				y_wght[m/2] = max(1 - (fabs(y - y_sample)*1.0/GridSpacing), 0);   

			}  
			for ( m=0;m<16;++m)  
				for (int n=0;n<8;++n)  
					pos_wght[m*8+n]=x_wght[m]*y_wght[m];  
			free(x_wght);  
			free(y_wght);  
			//计算方向的加权,首先旋转梯度场到主方向,然后计算差异   
			float diff[8],orient_wght[128];  
			for ( m=0;m<8;++m)  
			{   
				float angle = grad_sample-(p->ori)-orient_angles[m]+CV_PI;  
				float temp = angle / (2.0 * CV_PI);  
				angle -= (int)(temp) * (2.0 * CV_PI);  
				diff[m]= angle - CV_PI;  
			}  
			// Compute the gaussian weighting.  
			float x=p->sx;  
			float y=p->sy;  
			float g = exp(-((x_sample-x)*(x_sample-x)+(y_sample-y)*(y_sample-y))/(2*feat_window*feat_window))/(2*CV_PI*feat_window*feat_window);  

			for ( m=0;m<128;++m)  
			{  
				orient_wght[m] = max((1.0 - 1.0*fabs(diff[m%8])/orient_bin_spacing),0);  
				feat_desc[m] = feat_desc[m] + orient_wght[m]*pos_wght[m]*g*mag_sample;  
			}  
			free(pos_wght);     
		}  
		free(feat);  
		free(featcenter);  
		float norm=GetVecNorm( feat_desc, 128);  
		for (int m=0;m<128;m++)  
		{  
			feat_desc[m]/=norm;  
			if (feat_desc[m]>0.2)  
				feat_desc[m]=0.2;  
		}  
		norm=GetVecNorm( feat_desc, 128);  
		for ( m=0;m<128;m++)  
		{  
			feat_desc[m]/=norm;  
			printf("%f  ",feat_desc[m]);    
		}  
		printf("/n");  
		p->descrip = feat_desc;  
		p=p->next;  
	}  
	free(feat_grid);  
	free(feat_samples);  
}  

//为了显示图象金字塔,而作的图像水平拼接  
CvMat* MosaicHorizen( CvMat* im1, CvMat* im2 )  
{  
	int row,col;  
	CvMat *mosaic = cvCreateMat( max(im1->rows,im2->rows),(im1->cols+im2->cols),CV_32FC1);  
#define Mosaic(ROW,COL) ((float*)(mosaic->data.fl + mosaic->step/sizeof(float)*(ROW)))[(COL)]  
#define Im11Mat(ROW,COL) ((float *)(im1->data.fl + im1->step/sizeof(float) *(ROW)))[(COL)]  
#define Im22Mat(ROW,COL) ((float *)(im2->data.fl + im2->step/sizeof(float) *(ROW)))[(COL)]  
	cvZero(mosaic);  
	/* Copy images into mosaic1. */  
	for ( row = 0; row < im1->rows; row++)  
		for ( col = 0; col < im1->cols; col++)  
			Mosaic(row,col)=Im11Mat(row,col) ;  
	for (  row = 0; row < im2->rows; row++)  
		for (  col = 0; col < im2->cols; col++)  
			Mosaic(row, (col+im1->cols) )= Im22Mat(row,col) ;  
	return mosaic;  
}  

//为了显示图象金字塔,而作的图像垂直拼接  
CvMat* MosaicVertical( CvMat* im1, CvMat* im2 )  
{  
	int row,col;  
	CvMat *mosaic = cvCreateMat(im1->rows+im2->rows,max(im1->cols,im2->cols), CV_32FC1);  
#define Mosaic(ROW,COL) ((float*)(mosaic->data.fl + mosaic->step/sizeof(float)*(ROW)))[(COL)]  
#define Im11Mat(ROW,COL) ((float *)(im1->data.fl + im1->step/sizeof(float) *(ROW)))[(COL)]  
#define Im22Mat(ROW,COL) ((float *)(im2->data.fl + im2->step/sizeof(float) *(ROW)))[(COL)]  
	cvZero(mosaic);  

	/* Copy images into mosaic1. */  
	for ( row = 0; row < im1->rows; row++)  
		for ( col = 0; col < im1->cols; col++)  
			Mosaic(row,col)= Im11Mat(row,col) ;  
	for ( row = 0; row < im2->rows; row++)  
		for ( col = 0; col < im2->cols; col++)  
			Mosaic((row+im1->rows),col)=Im22Mat(row,col) ;  

	return mosaic;  
}

//主函数
int main( void )  
{  
	//声明当前帧IplImage指针  
	IplImage* src = NULL;   
	IplImage* image1 = NULL;   
	IplImage* grey_im1 = NULL;   
	IplImage* DoubleSizeImage = NULL;  

	IplImage* mosaic1 = NULL;   
	IplImage* mosaic2 = NULL;   

	CvMat* mosaicHorizen1 = NULL;  
	CvMat* mosaicHorizen2 = NULL;  
	CvMat* mosaicVertical1 = NULL;  

	CvMat* image1Mat = NULL;  
	CvMat* tempMat=NULL;  

	ImageOctaves *Gaussianpyr;  
	int rows,cols;  

#define Im1Mat(ROW,COL) ((float *)(image1Mat->data.fl + image1Mat->step/sizeof(float) *(ROW)))[(COL)]  

	//灰度图象像素的数据结构  
#define Im1B(ROW,COL) ((uchar*)(image1->imageData + image1->widthStep*(ROW)))[(COL)*3]  
#define Im1G(ROW,COL) ((uchar*)(image1->imageData + image1->widthStep*(ROW)))[(COL)*3+1]  
#define Im1R(ROW,COL) ((uchar*)(image1->imageData + image1->widthStep*(ROW)))[(COL)*3+2]  

	storage = cvCreateMemStorage(0);   

	//读取图片  
	if( (src = cvLoadImage( "street1.jpg", 1)) == 0 )  // test1.jpg einstein.pgm back1.bmp  
		return -1;  

	//为图像分配内存   
	image1 = cvCreateImage(cvSize(src->width, src->height),  IPL_DEPTH_8U,3);  
	grey_im1 = cvCreateImage(cvSize(src->width, src->height),  IPL_DEPTH_8U,1);  
	DoubleSizeImage = cvCreateImage(cvSize(2*(src->width), 2*(src->height)),  IPL_DEPTH_8U,3);  

	//为图像阵列分配内存,假设两幅图像的大小相同,tempMat跟随image1的大小  
	image1Mat = cvCreateMat(src->height, src->width, CV_32FC1);  
	//转化成单通道图像再处理  
	cvCvtColor(src, grey_im1, CV_BGR2GRAY);  
	//转换进入Mat数据结构,图像操作使用的是浮点型操作  
	cvConvert(grey_im1, image1Mat);  

	double t = (double)cvGetTickCount();  
	//图像归一化  
	cvConvertScale( image1Mat, image1Mat, 1.0/255, 0 );  

	int dim = min(image1Mat->rows, image1Mat->cols);  
	numoctaves = (int) (log((double) dim) / log(2.0)) - 2;    //金字塔阶数  
	numoctaves = min(numoctaves, MAXOCTAVES);  

	//SIFT算法第一步,预滤波除噪声,建立金字塔底层  
	tempMat = ScaleInitImage(image1Mat) ;  
	//SIFT算法第二步,建立Guassian金字塔和DOG金字塔  
	Gaussianpyr = BuildGaussianOctaves(tempMat) ;  

	t = (double)cvGetTickCount() - t;  
	printf( "the time of build Gaussian pyramid and DOG pyramid is %.1f/n", t/(cvGetTickFrequency()*1000.) );  

#define ImLevels(OCTAVE,LEVEL,ROW,COL) ((float *)(Gaussianpyr[(OCTAVE)].Octave[(LEVEL)].Level->data.fl + Gaussianpyr[(OCTAVE)].Octave[(LEVEL)].Level->step/sizeof(float) *(ROW)))[(COL)]  
	//显示高斯金字塔  
	for (int i=0; i<numoctaves;i++)  
	{  
		if (i==0)  
		{  
			mosaicHorizen1=MosaicHorizen( (Gaussianpyr[0].Octave)[0].Level, (Gaussianpyr[0].Octave)[1].Level );  
			for (int j=2;j<SCALESPEROCTAVE+3;j++)  
				mosaicHorizen1=MosaicHorizen( mosaicHorizen1, (Gaussianpyr[0].Octave)[j].Level );  
			for ( j=0;j<NUMSIZE;j++)  
				mosaicHorizen1=halfSizeImage(mosaicHorizen1);  
		}  
		else if (i==1)  
		{  
			mosaicHorizen2=MosaicHorizen( (Gaussianpyr[1].Octave)[0].Level, (Gaussianpyr[1].Octave)[1].Level );  
			for (int j=2;j<SCALESPEROCTAVE+3;j++)  
				mosaicHorizen2=MosaicHorizen( mosaicHorizen2, (Gaussianpyr[1].Octave)[j].Level );  
			for ( j=0;j<NUMSIZE;j++)  
				mosaicHorizen2=halfSizeImage(mosaicHorizen2);  
			mosaicVertical1=MosaicVertical( mosaicHorizen1, mosaicHorizen2 );  
		}  
		else  
		{  
			mosaicHorizen1=MosaicHorizen( (Gaussianpyr[i].Octave)[0].Level, (Gaussianpyr[i].Octave)[1].Level );  
			for (int j=2;j<SCALESPEROCTAVE+3;j++)  
				mosaicHorizen1=MosaicHorizen( mosaicHorizen1, (Gaussianpyr[i].Octave)[j].Level );  
			for ( j=0;j<NUMSIZE;j++)  
				mosaicHorizen1=halfSizeImage(mosaicHorizen1);  
			mosaicVertical1=MosaicVertical( mosaicVertical1, mosaicHorizen1 );  
		}  
	}  
	mosaic1 = cvCreateImage(cvSize(mosaicVertical1->width, mosaicVertical1->height),  IPL_DEPTH_8U,1);  
	cvConvertScale( mosaicVertical1, mosaicVertical1, 255.0, 0 );  
	cvConvertScaleAbs( mosaicVertical1, mosaic1, 1, 0 );  

	//  cvSaveImage("GaussianPyramid of me.jpg",mosaic1);  
	cvNamedWindow("mosaic1",1);  
	cvShowImage("mosaic1", mosaic1);  
	cvWaitKey(0);  
	cvDestroyWindow("mosaic1");  
	//显示DOG金字塔  
	for ( i=0; i<numoctaves;i++)  
	{  
		if (i==0)  
		{  
			mosaicHorizen1=MosaicHorizen( (DOGoctaves[0].Octave)[0].Level, (DOGoctaves[0].Octave)[1].Level );  
			for (int j=2;j<SCALESPEROCTAVE+2;j++)  
				mosaicHorizen1=MosaicHorizen( mosaicHorizen1, (DOGoctaves[0].Octave)[j].Level );  
			for ( j=0;j<NUMSIZE;j++)  
				mosaicHorizen1=halfSizeImage(mosaicHorizen1);  
		}  
		else if (i==1)  
		{  
			mosaicHorizen2=MosaicHorizen( (DOGoctaves[1].Octave)[0].Level, (DOGoctaves[1].Octave)[1].Level );  
			for (int j=2;j<SCALESPEROCTAVE+2;j++)  
				mosaicHorizen2=MosaicHorizen( mosaicHorizen2, (DOGoctaves[1].Octave)[j].Level );  
			for ( j=0;j<NUMSIZE;j++)  
				mosaicHorizen2=halfSizeImage(mosaicHorizen2);  
			mosaicVertical1=MosaicVertical( mosaicHorizen1, mosaicHorizen2 );  
		}  
		else  
		{  
			mosaicHorizen1=MosaicHorizen( (DOGoctaves[i].Octave)[0].Level, (DOGoctaves[i].Octave)[1].Level );  
			for (int j=2;j<SCALESPEROCTAVE+2;j++)  
				mosaicHorizen1=MosaicHorizen( mosaicHorizen1, (DOGoctaves[i].Octave)[j].Level );  
			for ( j=0;j<NUMSIZE;j++)  
				mosaicHorizen1=halfSizeImage(mosaicHorizen1);  
			mosaicVertical1=MosaicVertical( mosaicVertical1, mosaicHorizen1 );  
		}  
	}  
	//考虑到DOG金字塔各层图像都会有正负,所以,必须寻找最负的,以将所有图像抬高一个台阶去显示  
	double min_val=0;  
	double max_val=0;  
	cvMinMaxLoc( mosaicVertical1, &min_val, &max_val,NULL, NULL, NULL );  
	if ( min_val<0.0 )  
		cvAddS( mosaicVertical1, cvScalarAll( (-1.0)*min_val ), mosaicVertical1, NULL );  
	mosaic2 = cvCreateImage(cvSize(mosaicVertical1->width, mosaicVertical1->height),  IPL_DEPTH_8U,1);  
	cvConvertScale( mosaicVertical1, mosaicVertical1, 255.0/(max_val-min_val), 0 );  
	cvConvertScaleAbs( mosaicVertical1, mosaic2, 1, 0 );  

	//  cvSaveImage("DOGPyramid of me.jpg",mosaic2);  
	cvNamedWindow("mosaic1",1);  
	cvShowImage("mosaic1", mosaic2);  
	cvWaitKey(0);  

	//SIFT算法第三步:特征点位置检测,最后确定特征点的位置  
	int keycount=DetectKeypoint(numoctaves, Gaussianpyr);  
	printf("the keypoints number are %d ;/n", keycount);  
	cvCopy(src,image1,NULL);  
	DisplayKeypointLocation( image1 ,Gaussianpyr);  

	cvPyrUp( image1, DoubleSizeImage, CV_GAUSSIAN_5x5 );  
	cvNamedWindow("image1",1);  
	cvShowImage("image1", DoubleSizeImage);  
	cvWaitKey(0);    
	cvDestroyWindow("image1");  

	//SIFT算法第四步:计算高斯图像的梯度方向和幅值,计算各个特征点的主方向  
	ComputeGrad_DirecandMag(numoctaves, Gaussianpyr);  
	AssignTheMainOrientation( numoctaves, Gaussianpyr,mag_pyr,grad_pyr);  
	cvCopy(src,image1,NULL);  
	DisplayOrientation ( image1, Gaussianpyr);  

	//  cvPyrUp( image1, DoubleSizeImage, CV_GAUSSIAN_5x5 );  
	cvNamedWindow("image1",1);  
	//  cvResizeWindow("image1", 2*(image1->width), 2*(image1->height) );  
	cvShowImage("image1", image1);  
	cvWaitKey(0);  

	//SIFT算法第五步:抽取各个特征点处的特征描述字  
	ExtractFeatureDescriptors( numoctaves, Gaussianpyr);  
	cvWaitKey(0);  

	//销毁窗口  
	cvDestroyWindow("image1");  
	cvDestroyWindow("mosaic1");  
	//释放图像  
	cvReleaseImage(&image1);  
	cvReleaseImage(&grey_im1);  
	cvReleaseImage(&mosaic1);  
	cvReleaseImage(&mosaic2);  
	return 0;  
} 

================================================
FILE: ebook/code/c/2.1:寻找最小的 k 个数.c
================================================
//解法四
//copyright@ mark allen weiss  
//July、updated,2011.05.05凌晨.  

//q_select places the kth smallest element in a[k]  
void q_select( input_type a[], int k, int left, int right )  
{  
	int i, j;
	input_type pivot;
	if( left + CUTOFF <= right )  
	{
		pivot = median3( a, left, right );
		//取三数中值作为枢纽元,可以消除最坏情况而保证此算法是O(N)的。不过,这还只局限在理论意义上。  
		//稍后,除了下文的第二节的随机选取枢纽元,在第四节末,您将看到另一种选取枢纽元的方法。  

		i=left; j=right-1;
		for(;;)
		{
			while( a[++i] < pivot );
			while( a[--j] > pivot );
			if (i < j )
				swap( &a[i], &a[j] );
			else
				break;
		}
		swap( &a[i], &a[right-1] ); /* restore pivot */
		if( k < i)
			q_select( a, k, left, i-1 );
		else
			if( k > i )
				q-select( a, k, i+1, right );
	}  
	else
		insert_sort(a, left, right );
}


//解法五
PARTITION(A, p, r)         //partition过程 p为第一个数,r为最后一个数
	1  x ← A[r]               //以最后一个元素作为主元
2  i ← p - 1
	3  for j ← p to r - 1
	4       do if A[j] ≤ x
	5             then i ← i + 1
	6                  exchange A[i] <-> A[j]
7  exchange A[i + 1] <-> A[r]
8  return i + 1

	RANDOMIZED-PARTITION(A, p, r)      //随机快排的partition过程
	1  i ← RANDOM(p, r)                                 //i  随机取p到r中个一个值
	2  exchange A[r] <-> A[i]                         //以随机的 i作为主元
3  return PARTITION(A, p, r)            //调用上述原来的partition过程

	RANDOMIZED-SELECT(A, p, r, i)       //以线性时间做选择,目的是返回数组A[p..r]中的第i 小的元素
	1  if p = r          //p=r,序列中只有一个元素
	2      then return A[p]
3  q ← RANDOMIZED-PARTITION(A, p, r)   //随机选取的元素q作为主元
	4  k ← q - p + 1                     //k表示子数组 A[p…q]内的元素个数,处于划分低区的元素个数加上一个主元元素
	5  if i == k                        //检查要查找的i 等于子数组中A[p....q]中的元素个数k
	6      then return A[q]        //则直接返回A[q]
7  else if i < k
	8      then return RANDOMIZED-SELECT(A, p, q - 1, i)
	//得到的k 大于要查找的i 的大小,则递归到低区间A[p,q-1]中去查找
	9  else return RANDOMIZED-SELECT(A, q + 1, r, i - k)
	//得到的k 小于要查找的i 的大小,则递归到高区间A[q+1,r]中去查找。  


//...

//解法四示例
#include <stdio.h>
#define Cutoff ( 3 )

void swap( int *a, int *b )
{
    int tmp = *a;
    *a = *b;
    *b = tmp;
}

int median3( int a[ ], int left, int right )
{
    int Center = ( left + right ) / 2;

    if( a[ left ] > a[ Center ] )
        swap( &a[ left ], &a[ Center ] );
    if( a[ left ] > a[ right ] )
        swap( &a[ left ], &a[ right ] );
    if( a[ Center ] > a[ right ] )
        swap( &a[ Center ], &a[ right ] );

    swap( &a[ Center ], &a[ right - 1 ] );  
    return a[ right - 1 ];                
}
void insert_sort( int a[ ], int n )
{
    int j, p, tmp; 
    for( p = 1; p < n; p++ )
    {
        tmp = a[ p ];
        for( j = p; j > 0 && a[ j - 1 ] > tmp; j-- )
            a[ j ] = a[ j - 1 ];
        a[ j ] = tmp;
    }
}

void q_select( int a[ ], int k, int left, int right )
{
    int i, j;
    int Pivot;

    if( left + Cutoff <= right )
    {
        Pivot = median3( a, left, right );
        //取三数中值作为枢纽元,可以消除最坏情况而保证此算法是O(N)
        i = left; j = right - 1;
        for( ; ; )
        {
            while( a[ ++i ] < Pivot ){ }
            while( a[ --j ] > Pivot ){ }
            if( i < j )
                swap( &a[ i ], &a[ j ] );
            else
                break;
        }
        swap( &a[ i ], &a[ right - 1 ] );  /* 重置枢纽元 */

        if( k <= i )
            q_select( a, k, left, i - 1 );
        else if( k > i + 1 )
            q_select( a, k, i + 1, right );
    }
    else  
        insert_sort( a + left, right - left + 1 );
}

int main(int argc, const char *argv[])
{
    int a[] = {0,2,1,3,4};
    int k = 2;
    q_select(a,k,0,5);
    printf("%d\n",a[k-1]);
    return 0;
}


================================================
FILE: ebook/code/c/2.2:求给定区间的第K小元素.c
================================================
//伴随数组解法
//copyright@ 水 && July  
//总的时间复杂度为O(N*logN+N)= O(N*logN)。  
//July、updated,2011.05.28.凌晨。  
#include<iostream>  
#include<algorithm>  
using namespace std;  

struct node{  
	int num,data;  
	bool operator < (const node &p) const   
	{  
		return data < p.data;  
	}  
};  
node p[100001];  

int main()  
{  
	int n=7;  
	int i,j,a,b,c;//c:flag;  

	for(i=1;i<=n;i++)   
	{  
		scanf("%d",&p[i].data);  
		p[i].num = i;  
	}  
	sort(p+1,p+1+n);    //调用库函数sort完成排序,复杂度n*logn  

	scanf("%d %d %d",&a,&b,&c);  
	for(i=1;i<=n;i++)   //扫描一遍,复杂度n  
	{  
		if(p[i].num>=a && p[i].num<=b)   
			c--;   
		if(c == 0)   
			break;  
	}  
	printf("%d/n",p[i].data);  
	return 0;  
}  


//问题扩展部分
//copyright@ 苍狼  
//直接对给定区间的数进行排序,没必要用伴随数组。  
#include<iostream>     
#include<algorithm>     
using namespace std;     

struct node{     
	int data;     
	bool operator < (const node &p) const      
	{     
		return data < p.data;     
	}     
};     
node p[100001];     

int main()     
{     
	int n=7;     
	int i,a,b,c;//c:flag;     

	for(i=1;i<=n;i++)      
	{     
		scanf("%d",&p[i].data);        
	}  

	scanf("%d%d%d", &a, &b, &c);   //b,a为原数组的下标索引  
	sort(p+a, p+b+1);     //直接对给定区间进行排序,|b-a+1|*log(b-a+1)  

	printf("The number is %d/n", p[a-1+c].data);      
	return 0;     
}  


================================================
FILE: ebook/code/c/2.3:求解500万以内的亲和数.c
================================================
//解法一
//求解亲和数问题

//第一个for和第二个for循环是logN*N(调和级数)次遍历,第三个for循环扫描O(N)。
//所以总的时间复杂度为 O(N*logN) + O(n) =O(N*logN+N)(其中logN为调和级数)。

//关于第一个for和第二个for寻找中,调和级数的说明:
//比如给2的倍数加2,那么应该是  n/2次,3的倍数加3 应该是 n/3次,...
//那么其实就是n*(1+1/2+1/3+1/4+...1/(n/2))=n*(调和级数)=n*logn。

//copyright@ 上善若水
//July、updated,2011.05.24。
#include<stdio.h>

int sum[5000010];   //为防越界

int main()
{
	int i, j;
	for (i = 0; i <= 5000000; i++)
		sum[i] = 1;  //1是所有数的真因数所以全部置1

	for (i = 2; i + i <= 5000000; i++)  //预处理,预处理是logN(调和级数)*N。
		//@litaoye:调和级数1/2 + 1/3 + 1/4......的和近似为ln(n),
		//因此O(n *(1/2 + 1/3 + 1/4......)) = O(n * ln(n)) = O(N*log(N))。
	{
		//5000000以下最大的真因数是不超过它的一半的
		j = i + i;  //因为真因数,所以不能算本身,所以从它的2倍开始
		while (j <= 5000000)
		{
			//将所有i的倍数的位置上加i
			sum[j] += i;
			j += i;
		}
	}

	for (i = 220; i <= 5000000; i++)   //扫描,O(N)。
	{
		// 一次遍历,因为知道最小是220和284因此从220开始
		if (sum[i] > i && sum[i] <= 5000000 && sum[sum[i]] == i)
		{
			//去重,不越界,满足亲和
			printf("%d %d/n",i,sum[i]);
		}
	}
	return 0;
}


================================================
FILE: ebook/code/c/2.4:寻找和为定值的两个数.c
================================================
#include <iostream>
#include <algorithm>
using namespace std;

//copyright@2014 July
void twoSum(int data[], unsigned int length, int sum)
{
	//sort(s, s+n);   如果数组非有序的,那就事先排好序O(N log N)

	int begin = 0;
	int end = length - 1;

	//俩头夹逼,或称两个指针两端扫描法,很经典的方法,O(N)
	while (begin < end)
	{
		long currSum = data[begin] + data[end];

		if (currSum == sum)
		{
			//题目只要求输出满足条件的任意一对即可
			printf("%d %d\n", data[begin], data[end]);

			//如果需要所有满足条件的数组对,则需要加上下面两条语句:
			//begin++
			//end--
			break;
		}
		else{
			if (currSum < sum)
				begin++;
			else
				end--;
		}
	}
}

int main(){
	int a[] = { 1, 2, 4, 7, 11, 15 };
	twoSum(a, 6, 15);
	return 0;
}


================================================
FILE: ebook/code/c/2.5:寻找和为定值的多个数.c
================================================
//解法一
//copyright@ July && yansha
//updated@ 2014 July
#include<list>
#include<iostream>
using namespace std;

list<int>list1;
void SumOfkNumber(int sum, int n)
{
	// 递归出口
	if (n <= 0 || sum <= 0)
		return;

	// 输出找到的结果
	if (sum == n)
	{
		// 反转list
		list1.reverse();
		for (list<int>::iterator iter = list1.begin(); iter != list1.end(); iter++)
			cout << *iter << " + ";
		cout << n << endl;
	}

	list1.push_front(n);      //典型的01背包问题
	SumOfkNumber(sum - n, n - 1);   //放n,n-1个数填满sum-n
	list1.pop_front();
	SumOfkNumber(sum, n - 1);     //不放n,n-1个数填满sum
}

int main()
{
	int sum, n;
	cout << "请输入你要等于多少的数值sum:" << endl;
	cin >> sum;
	cout << "请输入你要从1.....n数列中取值的n:" << endl;
	cin >> n;
	cout << "所有可能的序列,如下:" << endl;
	SumOfkNumber(sum, n);
	system("pause");
	return 0;
}

//解法二
//copyright@ 2011 zhouzhenren
//updated@2014 July
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <iostream>
using namespace std;

/**
* 输入t, r, 尝试Wk
*/
void SumOfkNumber(int t, int k, int r, int& M, bool& flag, bool* X)
{
	X[k] = true;   // 选第k个数
	if (t + k == M) // 若找到一个和为M,则设置解向量的标志位,输出解
	{
		flag = true;
		for (int i = 1; i <= k; ++i)
		{
			if (X[i] == 1)
			{
				printf("%d ", i);
			}
		}
		printf("\n");
	}
	else
	{   // 若第k+1个数满足条件,则递归左子树
		if (t + k + (k + 1) <= M)
		{
			SumOfkNumber(t + k, k + 1, r - k, M, flag, X);
		}
		// 若不选第k个数,选第k+1个数满足条件,则递归右子树
		if ((t + r - k >= M) && (t + (k + 1) <= M))
		{
			X[k] = false;
			SumOfkNumber(t, k + 1, r - k, M, flag, X);
		}
	}
}

void search(int& N, int& M)
{
	// 初始化解空间
	bool* X = (bool*)malloc(sizeof(bool)* (N + 1));
	memset(X, false, sizeof(bool)* (N + 1));
	int sum = (N + 1) * N * 0.5f;
	if (1 > M || sum < M) // 预先排除无解情况
	{
		printf("not found\n");
		return;
	}
	bool f = false;
	SumOfkNumber(0, 1, sum, M, f, X);
	if (!f)
	{
		printf("not found\n");
	}
	free(X);
}

int main()
{
	int sum, n;
	cout << "请输入你要等于多少的数值sum:" << endl;
	cin >> sum;
	cout << "请输入你要从1.....n数列中取值的n:" << endl;
	cin >> n;
	cout << "所有可能的序列,如下:" << endl;
	search(sum, n);
	system("pause");
	return 0;
}


================================================
FILE: ebook/code/c/2.6:求连续子数组的最大和.c
================================================
//解法一
int maxSubArray(int* A, int n)
{
    int maxSum = -INF;
    int currSum = 0;
    for (int i = 0; i < n; i++)
    {
        for (int j = i; j < n; j++)
        {
            for (int k = i; k <= j; k++)
            {
                currSum += A[k];
            }
            if (currSum > maxSum)
                maxSum = currSum;

            currSum = 0; //这里要记得清零,否则的话sum最终存放的是所有子数组的和。
        }
    }
    return maxSum;
}


//解法二
#include <iostream>
using namespace std;

int maxSubArray(int* a, int n)
{
	int maxSum = a[0];       //全负情况,返回最大数
	int currSum = 0;
	for (int j = 0; j < n; j++)
	{
		if (currSum >= 0)    //如果加上某个元素,sum>=0的话,就加
			currSum += a[j];
		else
			currSum = a[j];  //如果加上某个元素,sum<0了,就不加
		if (currSum > maxSum)
			maxSum = currSum;
	}
	return maxSum;
}

int main()
{
	int a[] = { 1, -2, 3, 10, -4, 7, 2, -5 };
	cout << maxSubArray(a,8) << endl;
	//int a[] = { -1, -2, -3, -4 };
	//cout << maxSubArray(a,4) << endl;
	return 0;
}


//解法三:动态规划的解法
#include <iostream>
using namespace std;

int maxSubArray(int* a, int n)
{
	if (a == nullptr || n == 0)
		return 0;

	int currSum = 0;
	int maxSum = a[0];       //全负情况,返回最大数

	for (int j = 0; j < n; j++)
	{
		currSum = (a[j] > currSum + a[j]) ? a[j] : currSum + a[j];
		maxSum = (maxSum > currSum) ? maxSum : currSum;

	}
	return maxSum;
}

int main()
{
	int a[] = { 1, -2, 3, 10, -4, 7, 2, -5 };
	cout << maxSubArray(a, 8) << endl;
	//int a[] = { -1, -2, -3, -4 };
	//cout << maxSubArray(a,4) << endl;
	return 0;
}


================================================
FILE: ebook/code/c/2.7:奇偶排序.c
================================================
// 6.7 奇偶排序.cpp : 定义控制台应用程序的入口点。
//实现一
#include "stdafx.h"
#include <iostream>
using namespace std;

//判断是否为奇数
bool isOddNumber(int data)
{
	return data & 1 == 1;
}

//交换两个元素
void swap(int* x, int* y)
{
	int temp = *x;
	*x = *y;
	*y = temp;
}

//奇偶互换
void oddEvenSort(int *pData, unsigned int length)
{
	if (pData == NULL || length == 0)
		return;

	int *pBegin = pData;
	int *pEnd = pData + length - 1;

	while (pBegin < pEnd)
	{
		//如果pBegin指针指向的是奇数,正常,向后移
		if (isOddNumber(*pBegin))
		{
			pBegin++;
		}
		//如果pEnd指针指向的是偶数,正常,向前移
		else if (!isOddNumber(*pEnd))
		{
			pEnd--;
		}
		else
		{
			//否则都不正常,交换
			swap(*pBegin, *pEnd);
		}
	}
}

int main(int argc, _TCHAR* argv[])
{
	int data[] = { 1, 2, 3, 4, 5 };
	for (int i = 0; i < 5; i++)
		cout << data[i] << " ";
	cout << endl;
	oddEvenSort(data, 5);
	for (int i = 0; i < 5; i++)
		cout << data[i] << " ";
	cout << endl;
	return 0;
}



//实现二
// 6.7 奇偶排序.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
using namespace std;

//判断是否为奇数
bool isOddNumber(int data)
{
	return data & 1 == 1;
}

//交换两个元素
void swap(int* x, int* y)
{
	int temp = *x;
	*x = *y;
	*y = temp;
}

//奇偶互换
void oddEvenSort2(int data[], int lo, int hi)
{
	int i = lo - 1;
	for (int j = lo; j < hi; j++)
	{
		//data[j]指向奇数,交换
		if ( isOddNumber(data[j]) )
		{
			i = i + 1;
			swap(&data[i], &data[j]);
		}
	}
	swap(&data[i + 1], &data[hi]);
}

int main(int argc, _TCHAR* argv[])
{
	int data[] = {1, 2, 3, 4, 5};
	for (int i = 0; i < 5; i++)
		cout << data[i] << " ";
	cout << endl;
	oddEvenSort2(data, 0, 4);
	for (int i = 0; i < 5; i++)
		cout << data[i] << " ";
	cout << endl;
	return 0;
}


================================================
FILE: ebook/code/c/2.7:荷兰国旗问题.c
================================================
//解法一
//引用自gnuhpc  
while( current<=end )        
{             
  if( array[current] ==0 )             
   {                 
      swap(array[current],array[begin]);                  
      current++;                  
      begin++;            
   }             
   else if( array[current] == 1 )            
   {                 
      current++;            
   }   

   else //When array[current] =2   
   {               
      swap(array[current],array[end]);                
      end--;            
   }      
}  


================================================
FILE: ebook/code/c/2.8:矩阵相乘之Strassen算法.c
================================================
//解法一
//矩阵乘法,3个for循环搞定    
void Mul(int** matrixA, int** matrixB, int** matrixC)    
{    
	for(int i = 0; i < 2; ++i)     
	{    
		for(int j = 0; j < 2; ++j)     
		{    
			matrixC[i][j] = 0;    
			for(int k = 0; k < 2; ++k)     
			{    
				matrixC[i][j] += matrixA[i][k] * matrixB[k][j];    
			}    
		}    
	}    
}  


================================================
FILE: ebook/code/c/3.1:二分查找实现.c
================================================
//二分查找V0.1实现版
//copyright@2011 July

//首先要把握下面几个要点:
//right = n-1 => while(left <= right) => right = middle-1;
//right = n   => while(left <  right) => right = middle;
//middle的计算不能写在while循环外,否则无法得到更新。

int binary_search(int array[], int n, int value)
{
	int left = 0;
	int right = n - 1;
	//如果这里是int right = n 的话,那么下面有两处地方需要修改,以保证一一对应:
	//1、下面循环的条件则是while(left < right)
	//2、循环内当 array[middle] > value 的时候,right = mid

	while (left <= right)  //循环条件,适时而变
	{
		int middle = left + ((right - left) >> 1);  //防止溢出,移位也更高效。同时,每次循环都需要更新。

		if (array[middle] > value)
		{
			right = middle - 1;  //right赋值,适时而变
		}
		else if(array[middle] < value)
		{
			left = middle + 1;
		}
		else
			return middle;
		//可能会有读者认为刚开始时就要判断相等,但毕竟数组中不相等的情况更多
		//如果每次循环都判断一下是否相等,将耗费时间
	}
	return -1;
}


================================================
FILE: ebook/code/c/3.2:杨氏矩阵查找.c
================================================
#include <stdio.h>
#include <iostream>
using namespace std;

#define ROW 4
#define COL 4

bool YoungMatrix(int array[][COL], int searchkey){
	int i = 0, j = COL - 1;
	int var = array[i][j];
	while (true){
		if (var == searchkey)
			return true;
		else if (var < searchkey && i < ROW - 1)
			var = array[++i][j];
		else if (var > searchkey && j > 0)
			var = array[i][--j];
		else
			return false;
	}
}

int main(){
	int array[ROW][COL] = { { 1, 2, 8, 9 }, { 2, 4, 9, 12 }, { 4, 7, 10, 13 }, { 6, 8, 11, 15 } };
	int searchkey;
	cin >> searchkey;
	if (YoungMatrix(array, searchkey)){
		printf("存在");
	}
	else{
		printf("不存在");
	}
}


================================================
FILE: ebook/code/c/4.1:木块砌墙.c
================================================
//copyright@红色标记 12/8/2013    
//updated@July 13/8/2013  
using System;    
using System.Collections.Generic;    
using System.Text;    
using System.Collections;    

namespace HeapBlock    
{    
	public class WoolWall    
	{            
		private int n;    
		private int height;    
		private int maxState;    
		private int[, ,] resultCache;   //结果缓存数组    

		public WoolWall(int n, int height)    
		{    
			this.n = n;    
			this.height = height;    
			maxState = (1 << height) - 1;    
			resultCache = new int[n + 1, maxState + 1, maxState + 1];   //构建缓存数组,每个值默认为0;    
		}    

		/// <summary>    
		/// 静态入口。计算堆放方案数。    
		/// </summary>    
		/// <param name="n"></param>    
		/// <param name="k"></param>    
		/// <returns></returns>    
		public static int Heap(int n, int k)    
		{    
			return new WoolWall(n, k).Heap();    
		}    

		/// <summary>    
		/// 计算堆放方案数。    
		/// </summary>    
		/// <returns></returns>    
		public int Heap()    
		{    
			return (int)Heap(n, 0, 0);    
		}    

		private long Heap(int n, int lState, int rState)    
		{    
			//如果缓存数组中的值不为0,则表示该结果已经存在缓存中。    
			//直接返回缓存结果。    
			if (resultCache[n, lState, rState] != 0)    
			{    
				return resultCache[n, lState, rState];    
			}    

			//在只有一列的情况,无法再进行切分    
			//根据列状态计算一列的堆放方案    
			if (n == 0)    
			{    
				return CalcOneColumnHeapCount(lState);    
			}    

			long result = 0;    
			for (int state = 0; state <= maxState; state++)    
			{    
				if (n == 1)    
				{    
					//在只有两列的情况,判断当前状态在切分之后是否有效    
					if (!StateIsAvailable(n, lState, rState, state))    
					{    
						continue;    
					}    
					result += Heap(n - 1, state | lState, state | lState)  //合并状态。因为只有一列,所以lState和rState相同。    
						* Heap(n - 1, state | rState, state | rState);    
				}    
				else    
				{    
					result += Heap(n - 1, lState, state) * Heap(n - 1, state, rState);     
				}    
				result %= 1000000007;//为了防止结果溢出,根据题目要求求模。    
			}    

			resultCache[n, lState, rState] = (int)result;   //将结果写入缓存数组中    
			resultCache[n, rState, lState] = (int)result;   //对称的墙结果相同,所以直接写入缓存。    
			return result;    
		}    

		/// <summary>    
		/// 根据一列的状态,计算列的堆放方案数。    
		/// </summary>    
		/// <param name="state">状态</param>    
		/// <returns></returns>    
		private int CalcOneColumnHeapCount(int state)    
		{    
			int sn = 0; //连续计数    
			int result = 1;    
			for (int i = 0; i < height; i++)    
			{    
				if ((state & 1) == 0)    
				{    
					sn++;    
				}    
				else    
				{    
					if (sn > 0)    
					{    
						result *= CalcAllState(sn);    
					}    
					sn = 0;    
				}    
				state >>= 1;    
			}    
			if (sn > 0)    
			{    
				result *= CalcAllState(sn);    
			}    

			return result;    
		}    

		/// <summary>    
		/// 类似于斐波那契序列。    
		/// f(1)=1    
		/// f(2)=2    
		/// f(n) = f(n-1)*f(n-2);    
		/// 只是初始值不同。    
		/// </summary>    
		/// <param name="k"></param>    
		/// <returns></returns>    
		private static int CalcAllState(int k)    
		{    
			return k <= 2 ? k : CalcAllState(k - 1) + CalcAllState(k - 2);    
		}    

		/// <summary>    
		/// 判断状态是否可用。    
		/// 当n=1时,分割之后,左墙和右边墙只有一列。    
		/// 所以state的状态码可能会覆盖原来的边缘状态。    
		/// 如果有覆盖,则该状态不可用;没有覆盖则可用。    
		/// 当n>1时,不存在这种情况,都返回状态可用。    
		/// </summary>    
		/// <param name="n"></param>    
		/// <param name="lState">左边界状态</param>    
		/// <param name="rState">右边界状态</param>    
		/// <param name="state">切开位置的当前状态</param>    
		/// <returns>状态有效返回 true,状态不可用返回 false</returns>    
		private bool StateIsAvailable(int n, int lState, int rState, int state)    
		{    
			return (n > 1) || ((lState | state) == lState + state && (rState | state) == rState + state);    
		}    
	}    
}    


//解法三
//copyright@caopengcs 12/08/2013  
#ifdef WIN32  
#define ll __int64   
#else  
#define ll long long  
#endif  

// 1 covered 0 uncovered  

void cal(int a[6][32][32],int n,int col,int laststate,int nowstate)
{
	if (col >= n)
	{
		++a[n][laststate][nowstate];  
		return;  
	}  
	//不填 或者用1*1的填  
	cal(a,n, col + 1, laststate, nowstate);  
	if (((laststate >> col) & 1) == 0)
	{
		cal(a,n, col + 1, laststate, nowstate | (1 << col));  
		if ((col + 1 < n) && (((laststate >> (col + 1)) & 1) == 0))
		{
			cal(a,n, col + 2, laststate, nowstate);  
		}  
	}  
}  

inline int mul(ll x, ll y)
{
	return x * y % 1000000007;  
}  

void multiply(int n,int a[][32],int b[][32])
{ // b = a * a
	int i,j, k;  
	for (i = 0; i < n; ++i)
	{
		for (j = 0; j < n; ++j)
		{
			for (k = b[i][j] = 0; k < n; ++k)
			{
				if ((b[i][j] += mul(a[i][k],a[k][j])) >= 1000000007)
				{
					b[i][j] -= 1000000007;
				}  
			}  
		}  
	}  
}  

int calculate(int n,int k)
{
	int i, j;  
	int a[6][32][32],mat[2][32][32];  
	memset(a,0,sizeof(a));  
	for (i = 1; i <= 5; ++i)
	{
		for (j = (1 << i) - 1; j >= 0; --j)
		{
			cal(a,i, 0, j, 0);  
		}  
	}  
	memcpy(mat[0], a[k],sizeof(mat[0]));  
	k = (1 << k);  
	for (i = 0; n; --n)
	{
		multiply(k, mat[i], mat[i ^ 1]);  
		i ^= 1;  
	}  
	return mat[i][0][0];  
}  


================================================
FILE: ebook/code/c/4.2:格子取数问题.c
================================================
//解法一
//copyright@西芹_new 2013
#include "stdafx.h"
#include <iostream>
using namespace std;

#define N 5
int map[5][5] =
{
	{2, 0, 8, 0, 2},
	{0, 0, 0, 0, 0},
	{0, 3, 2, 0, 0},
	{0, 0, 0, 0, 0},
	{2, 0, 8, 0, 2}
};
int sumMax = 0;
int p1x = 0;
int p1y = 0;
int p2x = 0;
int p2y = 0;
int curMax = 0;

void dfs( int index)
{
	if ( index == 2 * N - 2)
	{
		if ( curMax > sumMax)
			sumMax = curMax;
		return;
	}

	if ( !(p1x == 0 && p1y == 0) && !(p2x == N - 1 && p2y == N - 1))
	{
		if ( p1x >= p2x && p1y >= p2y )
			return;
	}

	//right right
	if ( p1x + 1 < N && p2x + 1 < N )
	{
		p1x++;
		p2x++;
		int sum = map[p1x][p1y] + map[p2x][p2y];
		curMax += sum;
		dfs(index + 1);
		curMax -= sum;
		p1x--;
		p2x--;
	}

	//down down
	if ( p1y + 1 < N && p2y + 1 < N )
	{
		p1y++;
		p2y++;
		int sum = map[p1x][p1y] + map[p2x][p2y];
		curMax += sum;
		dfs(index + 1);
		curMax -= sum;
		p1y--;
		p2y--;
	}

	//rd
	if ( p1x + 1 < N && p2y + 1 < N )
	{
		p1x++;
		p2y++;
		int sum = map[p1x][p1y] + map[p2x][p2y];
		curMax += sum;
		dfs(index + 1);
		curMax -= sum;
		p1x--;
		p2y--;
	}

	//dr
	if ( p1y + 1 < N && p2x + 1 < N )
	{
		p1y++;
		p2x++;
		int sum = map[p1x][p1y] + map[p2x][p2y];
		curMax += sum;
		dfs(index + 1);
		curMax -= sum;
		p1y--;
		p2x--;
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	curMax = map[0][0];
	dfs(0);
	cout << sumMax - map[N - 1][N - 1] << endl;
	return 0;
}


//解法二
//2.2、DP方法实现
//copyright@caopengcs 2013
const int N = 202;
const int inf = 1000000000;  //无穷大
int dp[N * 2][N][N];
bool isValid(int step, int x1, int x2, int n) //判断状态是否合法
{
	int y1 = step - x1, y2 = step - x2;
	return ((x1 >= 0) && (x1 < n) && (x2 >= 0) && (x2 < n) && (y1 >= 0) && (y1 < n) && (y2 >= 0) && (y2 < n));
}

int getValue(int step, int x1, int x2, int n)  //处理越界 不存在的位置 给负无穷的值
{
	return isValid(step, x1, x2, n) ? dp[step][x1][x2] : (-inf);
}

//状态表示dp[step][i][j] 并且i <= j, 第step步  两个人分别在第i行和第j行的最大得分 时间复杂度O(n^3) 空间复杂度O(n^3)
int getAnswer(int a[N][N], int n)
{
	int P = n * 2 - 2; //最终的步数
	int i, j, step;

	//不能到达的位置 设置为负无穷大
	for (i = 0; i < n; ++i)
	{
		for (j = i; j < n; ++j)
		{
			dp[0][i][j] = -inf;
		}
	}
	dp[0][0][0] = a[0][0];

	for (step = 1; step <= P; ++step)
	{
		for (i = 0; i < n; ++i)
		{
			for (j = i; j < n; ++j)
			{
				dp[step][i][j] = -inf;
				if (!isValid(step, i, j, n))   //非法位置
				{
					continue;
				}
				//对于合法的位置进行dp
				if (i != j)
				{
					dp[step][i][j] = max(dp[step][i][j], getValue(step - 1, i - 1, j - 1, n));
					dp[step][i][j] = max(dp[step][i][j], getValue(step - 1, i - 1, j, n));
					dp[step][i][j] = max(dp[step][i][j], getValue(step - 1, i, j - 1, n));
					dp[step][i][j] = max(dp[step][i][j], getValue(step - 1, i, j, n));
					dp[step][i][j] += a[i][step - i] + a[j][step - j];  //不在同一个格子,加两个数
				}
				else
				{
					dp[step][i][j] = max(dp[step][i][j], getValue(step - 1, i - 1, j - 1, n));
					dp[step][i][j] = max(dp[step][i][j], getValue(step - 1, i - 1, j,  n));
					dp[step][i][j] = max(dp[step][i][j], getValue(step - 1, i, j,  n));
					dp[step][i][j] += a[i][step - i]; // 在同一个格子里,只能加一次
				}
			}
		}
	}
	return dp[P][n - 1][n - 1];
}

//2.3、DP实现优化版
//copyright@caopengcs 8/24/2013
int dp[2][N][N];

bool isValid(int step, int x1, int x2, int n) //判断状态是否合法
{
	int y1 = step - x1, y2 = step - x2;
	return ((x1 >= 0) && (x1 < n) && (x2 >= 0) && (x2 < n) && (y1 >= 0) && (y1 < n) && (y2 >= 0) && (y2 < n));
}

int getValue(int step, int x1, int x2, int n)  //处理越界 不存在的位置 给负无穷的值
{
	return isValid(step, x1, x2, n) ? dp[step % 2][x1][x2] : (-inf);
}

//状态表示dp[step][i][j] 并且i <= j, 第step步  两个人分别在第i行和第j行的最大得分 时间复杂度O(n^3) 使用滚动数组 空间复杂度O(n^2)
int getAnswer(int a[N][N], int n)
{
	int P = n * 2 - 2; //最终的步数
	int i, j, step, s;

	//不能到达的位置 设置为负无穷大
	for (i = 0; i < n; ++i)
	{
		for (j = i; j < n; ++j)
		{
			dp[0][i][j] = -inf;
		}
	}
	dp[0][0][0] = a[0][0];

	for (step = 1; step <= P; ++step)
	{
		for (i = 0; i < n; ++i)
		{
			for (j = i; j < n; ++j)
			{
				dp[step][i][j] = -inf;
				if (!isValid(step, i, j, n))   //非法位置
				{
					continue;
				}
				s = step % 2;  //状态下表标
				//对于合法的位置进行dp
				if (i != j)
				{
					dp[s][i][j] = max(dp[s][i][j], getValue(step - 1, i - 1, j - 1, n));
					dp[s][i][j] = max(dp[s][i][j], getValue(step - 1, i - 1, j, n));
					dp[s][i][j] = max(dp[s][i][j], getValue(step - 1, i, j - 1, n));
					dp[s][i][j] = max(dp[s][i][j], getValue(step - 1, i, j, n));
					dp[s][i][j] += a[i][step - i] + a[j][step - j];  //不在同一个格子,加两个数
				}
				else
				{
					dp[s][i][j] = max(dp[s][i][j], getValue(step - 1, i - 1, j - 1, n));
					dp[s][i][j] = max(dp[s][i][j], getValue(step - 1, i - 1, j,  n));
					dp[s][i][j] = max(dp[s][i][j], getValue(step - 1, i, j,  n));
					dp[s][i][j] += a[i][step - i]; // 在同一个格子里,只能加一次
				}
			}
		}
	}
	return dp[P % 2][n - 1][n - 1];
}


================================================
FILE: ebook/code/c/4.3:出现次数超过一半的数字.c
================================================
// 4.3 出现次数超过一半.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>  
using namespace std;

//a代表数组,length代表数组长度
int FindOneNumber(int* a, int length)
{
	int candidate = a[0];
	int nTimes, i;
	for (i = nTimes = 0; i < length; i++)
	{
		if (candidate == a[i])
			nTimes++;
		else 
			nTimes--;
		if (nTimes == 0)
		{
			candidate = a[i];
			nTimes = 1;
		}
	}
	return candidate;
}

int main()
{
	int a[10] = { 1, 2, 3, 4, 6, 6, 6, 6, 6 };
	int* n = a;
	cout << FindOneNumber(a, 9) << endl;
	return 0;
}


================================================
FILE: ebook/code/c/4.3:完美洗牌算法.c
================================================
//解法二
//2.1、位置置换pefect_shuffle1算法
// 时间O(n),空间O(n) 数组下标从1开始
void pefect_shuffle1(int *a, int n)
{
	int n2 = n * 2, i, b[N];
	for (i = 1; i <= n2; ++i)
	{
		b[(i * 2) % (n2 + 1)] = a[i];
	}
	for (i = 1; i <= n2; ++i)
	{
		a[i] = b[i];
	}
}

//2.2、分而治之perfect_shuffle2算法
//copyright@caopengcs 8/23/2013
//时间O(nlogn) 空间O(1) 数组下标从1开始
void perfect_shuffle2(int *a, int n)
{
	int t, i;
	if (n == 1)
	{
		t = a[1];
		a[1] = a[2];
		a[2] = t;
		return;
	}
	int n2 = n * 2, n3 = n / 2;
	if (n % 2 == 1)    //奇数的处理
	{
		t = a[n];
		for (i = n + 1; i <= n2; ++i)
		{
			a[i - 1] = a[i];
		}
		a[n2] = t;
		--n;
	}
	//到此n是偶数

	for (i = n3 + 1; i <= n; ++i)
	{
		t = a[i];
		a[i] = a[i + n3];
		a[i + n3] = t;
	}

	// [1.. n /2]
	perfect_shuffle2(a, n3);
	perfect_shuffle2(a + n, n3);
}

//2.3.1、走圈算法cycle_leader
//数组下标从1开始,from是圈的头部,mod是要取模的数 mod 应该为 2 * n + 1,时间复杂度O(圈长)
void cycle_leader(int *a, int from, int mod)
{
	int t,i;

	for (i = from * 2 % mod; i != from; i = i * 2 % mod)
	{
		t = a[i];
		a[i] = a[from];
		a[from] = t;
	}
}



//2.3.2、神级结论:若2*n=(3^k - 1)
//翻转字符串时间复杂度O(to - from)
void reverse(int *a, int from, int to)
{
	int t;
	for (; from < to; ++from, --to)
	{
		t = a[from];
		a[from] = a[to];
		a[to] = t;
	}
}

//循环右移num位 时间复杂度O(n)
void right_rotate(int *a, int num, int n)
{
	reverse(a, 1, n - num);
	reverse(a, n - num + 1, n);
	reverse(a, 1, n);
}


//2.3.3、完美洗牌算法perfect_shuffle3
//copyright@caopengcs 8/24/2013
//时间O(n),空间O(1)
void perfect_shuffle3(int *a, int n)
{
	int n2, m, i, k, t;
	for (; n > 1;)
	{
		// step 1
		n2 = n * 2;
		for (k = 0, m = 1; n2 / m >= 3; ++k, m *= 3)
			;
		m /= 2;
		// 2m = 3^k - 1 , 3^k <= 2n < 3^(k + 1)

		// step 2
		right_rotate(a + m, m, n);

		// step 3
		for (i = 0, t = 1; i < k; ++i, t *= 3)
		{
			cycle_leader(a , t, m * 2 + 1);
		}

		//step 4
		a += m * 2;
		n -= m;

	}
	// n = 1
	t = a[1];
	a[1] = a[2];
	a[2] = t;
}


//2.3.4、perfect_shuffle3算法解决其变形问题
//copyright@caopengcs 8/24/2013
//时间复杂度O(n),空间复杂度O(1),数组下标从1开始,调用perfect_shuffle3
void shuffle(int *a, int n)
{
	int i, t, n2 = n * 2;
	perfect_shuffle3(a, n);
	for (i = 2; i <= n2; i += 2)
	{
		t = a[i - 1];
		a[i - 1] = a[i];
		a[i] = t;
	}
}


================================================
FILE: ebook/code/c/4.4:最近公共祖先LCA问题.LCAProblem.c
================================================
/**
 * Copyright (c) 2014 The TAOPP book Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be found 
 * in the LICENSE file.
 * 
 * 	Filename:	LCAProblem.c
 * 	Brief:		The C program for solving LCA problem
 * 	Version:	0.1
 * 	Created:	Tue Mar 18 21:25:58 2014
 * 
 * 	Author(s):	Liang Wang<fairywell28@yahoo.com>
 *          	eriol
 *          	July
 * 
 */

/** 
 * @brief 在二叉排序树中查找给定两个节点的LCA节点
 *
 * @author C version 0.1, 2014/3/18, Liang Wang<fairywell28@yahoo.com>
 *         C++ version 0.2, 2014, July
 *         C++ version 0.1, 2011, eriol 
 * @brief 在二叉排序树中查找给定两个节点的LCA节点
 *
 * @param root 该二叉排序树的根节点指针
 * @param u 给定节点一的指针
 * @param v 给定节点二的指针
 *
 * @return 找到LCA节点返回其指针;否则返回NULL
 */
Node* FindLowestCommonAncestorBst(Node* root, Node* u, Node* v)
{
    
    // 参数检查
    if (NULL == root || NULL == u || NULL == v) {
        fprintf(stderr, "Wrong input data! Exit!");
        return NULL;
    }
    
     if (root == u || root == v) {
         return root;
     }
     if (u == v) {
         return u;
     }
    
    //这段必须放在参数检查之后,不然有空指针异常
    
    int left_value = u->value;    
    int right_value = v->value;    
    Node* parent_node = NULL;
    Node* cur_node = root;
    

    // 调整左右节点值到正确
    if (left_value > right_value) {    
        swap(left_value, right_value);
    }    

    while (cur_node) {
        // 如果cur_node的值小于u、v的值,说明LCA节点应该在其右子树中
        if (cur_node->value < left_value) {    
            parent_node = cur_node;    
            cur_node = cur_node->right;    
        } else if (cur_node->value > right_value) {    
            // 如果cur_node的值大于u、v的值,则应该查询其左子树
            parent_node = cur_node;    
            cur_node = cur_node->left;    
        } else if (cur_node->value == left_value || cur_node->value == right_value) {
            // 找到节点u或者v处,说明其父节点即为所求
            return parent_node;
        } else {
            // 现在cur_node的值处于u和v的值之间,显然即为所求
            return cur_node;
        }    
    } 
    
    // 数据有误,找不到任何的LCA节点
    return NULL;
}

/** 
 * @brief 在二叉排序树中查找给定两个节点的LCA节点,递归版本
 *
 * @author C version 0.1, 2014/3/19, Liang Wang<fairywell28@yahoo.com> 
 *
 * @param root 该二叉排序树的根节点指针
 * @param u 给定节点一的指针
 * @param v 给定节点二的指针
 *
 * @return 找到LCA节点返回其指针;否则返回NULL
 */
Node* FindLcaBstRecursively(Node* root, Node* u, Node* v)
{
    // 参数检查
    // NOTICE:特别包含了u、v即是root节点的情况,此时应该返回NULL
    if (NULL == root || NULL == u || NULL == v
        || root == u || root == v || u == v) {
        fprintf(stderr, "Wrong input data: Arguments check failed! Exit!");
        return NULL;
    }
    
    int left_value = u->value;    
    int right_value = v->value;    

    // 调整左右节点值到正确
    if (left_value > right_value) {    
        swap(left_value, right_value);
    }    
    
    // 判断当前节点是否为所求LCA节点
    // 情形1:u、v分别在root的左右子树上
    if (root->value > left_value
        && root->value < right_value) {
        return root;
    }

    // 情形2:u、v都在root的同一棵子树且u、v有一个节点是root的子节点
    if (root->right == u || root->right == v
        || root->left == u || root->left == v) {
        return root;
    }

    // 当前节点不是所求LCA,则递归返回左右子树的LCA节点
    if (root->value < left_value) { // 查找右子树
        return FindLcaBstRecursively(root->right, u, v);
    } else if (root->value > right_value) { // 查找左子树
        return FindLcaBstRecursively(root->left, u, v);
    }
}


================================================
FILE: ebook/code/c/4.5:打印螺旋矩阵.SpiralMatrix.c
================================================
/**
 * Copyright (c) 2014 The TAOPP book Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be found 
 * in the LICENSE file.
 * 
 * 	Filename:	SpiralMatrix.c
 * 	Brief		打印顺时针螺旋数组,螺旋方向为从给定方阵左上角开始,右->下->左->上的次序	
 * 	Version:	0.1
 * 	Created:	Fri Mar 21 16:22:26 2014
 * 	Author(s):	Liang Wang<fairywell28@gmail.com>
 * 
 */

#include <stdio.h>
#include <stdlib.h>

/**
 * @brief 顺时针打印螺旋数组
 *        采用模拟的方法,模拟数组的打印过程,顺时针螺旋输出1~n*n的数值
 * @notice 为方便逻辑理解,数组多申请了一行和一列,便于下标从1开始计算
 * @param n 螺旋数组的行(列)数
 */
void PrintSpiralMatrix(int n)
{
    if (n > 0) {
        int i = 0, j = 0;
        // 正在模拟的当前待填入数值、当前行、当前列
        int curNum = 0, curRow = 0, curCol = 0;
        
        // 为矩阵动态分配空间
        // 如果仅仅是打印,可以不用分配,此处仅为演示
        int **matrix = (int **) malloc((n+1) * sizeof(int *));
        if (NULL == matrix) {
            fprintf(stderr, "malloc failed: out of memory\n");
            exit(-1);
        }

        for (i = 0; i <= n; i++) {
            matrix[i] = (int *) malloc((n+1) * sizeof(int));
            if (NULL == matrix[i]) {
                fprintf(stderr, "malloc failed: out of memory\n");
                exit(-1);
            }
        } 

        curNum = 1;
        // 需要转n/2圈
        for (i = 1; i <= n/2; i++) {
            // 顺序填写第curRow行
            curRow = i;
            for (curCol = i; curCol <= n-i; curCol++) {
                matrix[curRow][curCol] = curNum++;
            }

            // 顺序填写第curCol列
            curCol = n + 1 - i;
            for (curRow = i; curRow <= n-i; curRow++) {
                matrix[curRow][curCol] = curNum++;
            }

            // 逆序填写第curRow行
            curRow = n + 1 - i;
            for (curCol = n+1-i; curCol >= i+1; curCol--) {
                matrix[curRow][curCol] = curNum++;
            }

            // 逆序填写第curCol列
            curCol = i;
            for (curRow = n+1-i; curRow >= i+1; curRow--) {
                matrix[curRow][curCol] = curNum++;
            }
        } // end for
    
        // 如果方阵的阶为奇数,填入中心数
        if (n % 2 == 1) {
            matrix[n/2+1][n/2+1] = curNum; 
        }
        
        // 打印螺旋数组
        for (i = 1; i <= n; i++) {
            for (j = 1; j <= n; j++) {
                printf("%4d", matrix[i][j]);
            }
            printf("\n");
        }

        // 不要忘记释放malloc的内存
        // 并请注意释放方法
        for (i = 0; i <= n; i++) {
            free(matrix[i]);
        }
        free(matrix);
    }
}

int main(void)
{
    printf("-==- test for n=-1 -==-\n");
    PrintSpiralMatrix(-1);
    printf("\n");

    printf("-==- test for n=0 -==-\n");
    PrintSpiralMatrix(0);
    printf("\n");

    printf("-==- test for n=1 -==-\n");
    PrintSpiralMatrix(1);
    printf("\n");

    printf("-==- test for n=2 -==-\n");
    PrintSpiralMatrix(2);
    printf("\n");

    printf("-==- test for n=3 -==-\n");
    PrintSpiralMatrix(3);
    printf("\n");

    printf("-==- test for n=4 -==-\n");
    PrintSpiralMatrix(4);
    printf("\n");

    printf("-==- test for n=5 -==-\n");
    PrintSpiralMatrix(5);
    printf("\n");

    return 0;
}


================================================
FILE: ebook/code/c/5.1:最长公共子序列(LCS)问题.c
================================================
import java.util.Random;  

public class LCS{  
    public static void main(String[] args){  

        //设置字符串长度  
        int substringLength1 = 20;  
        int substringLength2 = 20;  //具体大小可自行设置  

        // 随机生成字符串  
        String x = GetRandomStrings(substringLength1);  
        String y = GetRandomStrings(substringLength2);  

        Long startTime = System.nanoTime();  
        // 构造二维数组记录子问题x[i]和y[i]的LCS的长度  
        int[][] opt = new int[substringLength1 + 1][substringLength2 + 1];  

        // 动态规划计算所有子问题  
        for (int i = substringLength1 - 1; i >= 0; i--){  
            for (int j = substringLength2 - 1; j >= 0; j--){  
                if (x.charAt(i) == y.charAt(j))  
                    opt[i][j] = opt[i + 1][j + 1] + 1;                                 //参考上文我给的公式。  
                else  
                    opt[i][j] = Math.max(opt[i + 1][j], opt[i][j + 1]);        //参考上文我给的公式。  
            }  
        }  

        -------------------------------------------------------------------------------------  

        理解上段,参考上文我给的公式:  

        根据上述结论,可得到以下公式,  

        如果我们记字符串Xi和Yj的LCS的长度为c[i,j],我们可以递归地求c[i,j]:  

                  /      0                               if i=0 or j=0  
        c[i,j]=          c[i-1,j-1]+1                    if i,j>0 and xi=xj  
                 /       max(c[i,j-1],c[i-1,j])           if i,j>0 and xi≠xj  

        -------------------------------------------------------------------------------------  

        System.out.println("substring1:"+x);  
        System.out.println("substring2:"+y);  
        System.out.print("LCS:");  

        int i = 0, j = 0;  
        while (i < substringLength1 && j < substringLength2){  
            if (x.charAt(i) == y.charAt(j)){  
                System.out.print(x.charAt(i));  
                i++;  
                j++;  
            } else if (opt[i + 1][j] >= opt[i][j + 1])  
                i++;  
            else  
                j++;  
        }  
        Long endTime = System.nanoTime();  
        System.out.println(" Totle time is " + (endTime - startTime) + " ns");  
    }  

    //取得定长随机字符串  
    public static String GetRandomStrings(int length){  
        StringBuffer buffer = new StringBuffer("abcdefghijklmnopqrstuvwxyz");  
        StringBuffer sb = new StringBuffer();  
        Random r = new Random();  
        int range = buffer.length();  
        for (int i = 0; i < length; i++){  
            sb.append(buffer.charAt(r.nextInt(range)));  
        }  
        return sb.toString();  
    }  
}  


================================================
FILE: ebook/code/c/5.2:最大连续乘积子串.c
================================================
//解法一
#include "stdafx.h"
#include <algorithm>
#include <iostream>
using namespace std;

double maxProductSubstring(double *a, int length) 
{
	double maxResult = a[0];
	for (int i = 0; i < length; i++)
	{
		double x = 1;
		for (int j = i; j < length; j++)
		{
			x *= a[j];
			if (x > maxResult)
			{
				maxResult = x;
			}
		}
	}
	return maxResult;
}

int _tmain(int argc, _TCHAR* argv[])
{
	double a[] = { -2.5,4,0,3,0.5,8,-1};
	cout << maxProductSubstring(a, 7) << endl;
	return 0;
}


//解法二
#include "stdafx.h"
#include <algorithm>
#include <iostream>
using namespace std;

double maxProductSubstring(double *a, int length)
{
	double maxEnd = a[0];
	double minEnd = a[0];
	double maxResult = a[0];
	// {-3,-0.5,-10}
	for (int i = 1; i < length; ++i)
	{
		double end1 = maxEnd * a[i], end2 = minEnd * a[i];
		maxEnd = max(max(end1, end2), a[i]);
		minEnd = min(min(end1, end2), a[i]);
		maxResult = max(maxResult, maxEnd);
	}
	return maxResult;
}

int _tmain(int argc, _TCHAR* argv[])
{
	double a[] = { -3, -0.5,- 10};
	cout << maxProductSubstring(a, 3) << endl;
	return 0;
}


================================================
FILE: ebook/code/c/5.3:字符串编辑距离.c
================================================
// 5.3 字符串编辑距离.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <algorithm>
using namespace std;

//编辑距离
//设每个字符串长度不超过 2000

//存储子问题的解 i,j表示source,target长度
//dp[i][j]表示source[0-i)与target[0-j)的编辑距离

int dp[2000][2000];
char source[2000];
char target[2000];

//dp[i][j]表示source[0-i)与target[0-j)的编辑距离
int editDistance(char *pSource, char *pTarget)
{
	int srcLength = strlen(pSource);
	int targetLength = strlen(pTarget);
	int i, j;
	//边界dp[i][0] = i,dp[0][j] = j  
	for (i = 1; i <= srcLength; ++i)
	{
		dp[i][0] = i;
	}
	for (j = 1; j <= targetLength; ++j)
	{
		dp[0][j] = j;
	}
	for (i = 1; i <= srcLength; ++i)
	{
		for (j = 1; j <= targetLength; ++j)
		{
			if (pSource[i - 1] == pTarget[j - 1])
			{
				dp[i][j] = dp[i - 1][j - 1];
			}
			else
			{
				dp[i][j] = 1 + min(dp[i - 1][j], dp[i][j - 1]);
			}
		}
	}
	return dp[srcLength][targetLength];
}

int main()
{
	cout << "hello July" << endl;
	cin.getline(source, 30);
	cin.getline(target, 30);

	printf("%d\n", editDistance(source, target));
	return 0;
}


================================================
FILE: ebook/code/c/5.4:交替字符串.c
================================================
bool isInterleave(string s1, string s2, string s3)
{

	int len1 = s1.size(), len2 = s2.size(), len3 = s3.size();
	if (len3 != len1 + len2) {
		return false;
	}
	vector<vector<bool> > dp;
	dp.resize(len1 + 1);
	for (int i = 0; i <= len1; ++i) {
		dp[i].resize(len2 + 1, false);
		for (int j = 0; j <= len2; ++j) {
			dp[i][j] = ((i == 0) && (j == 0)) || (i && dp[i - 1][j] && (s1[i - 1] == s3[i + j - 1])) || (j && dp[i][j - 1] && (s2[j - 1] == s3[i + j - 1]));
		}
	}
	return dp[len1][len2];
}


================================================
FILE: ebook/code/c/6.11:最小操作数.c
================================================
//解法一
//copyright@caopengcs     
//updated@July 08/12/2013    
class Solution    
{    
public:    
	// help 函数负责找到所有的路径    
	void help(intx,vector<int> &d, vector<string> &word,vector<vector<int> > &next,vector<string> &path,vector<vector<string> > &answer)
	{
		path.push_back(word[x]);    
		if (d[x] == 0)
		{   //已经达到终点了
			answer.push_back(path);    
		}    
		else
		{
			int i;    
			for (i = 0; i <next[x].size(); ++i)
			{
				help(next[x][i],d, word, next,path,answer);    
			}    
		}    
		path.pop_back();   //回溯    
	}    

	vector<vector<string>> findLadders(string start, string end, set<string>& dict)    
	{    
		vector<vector<string> > answer;    
		if (start == end)
		{   //起点终点恰好相等
			return answer;    
		}    
		//把起点终点加入字典的map    
		dict.insert(start);    
		dict.insert(end);    
		set<string>::iterator dt;    
		vector<string> word;    
		map<string,int>allword;    
		//把set转换为map,这样每个单词都有编号了。    
		for (dt = dict.begin(); dt!= dict.end(); ++dt)
		{
			word.push_back(*dt);    
			allword.insert(make_pair(*dt, allword.size()));    
		}    

		//建立连边 邻接表    
		vector<vector<int> > con;    
		int i,j,n =word.size(),temp,len = word[0].length();    
		con.resize(n);    
		for (i = 0; i < n; ++i)
		{
			for (j = 0; j <len; ++j)
			{
				char c;    
				for (c =word[i][j] + 1; c <= 'z'; ++c)
				{  //根据上面第二种方法的优化版的思路,让每个单词每个位置变更大
					char last =word[i][j];    
					word[i][j] =c;    
					map<string,int>::iterator t = allword.find(word[i]);    
					if (t !=allword.end())
					{
						con[i].push_back(t->second);    
						con[t->second].push_back(i);    
					}    
					word[i][j] =last;    
				}    
			}    
		}    

		//以下是标准bfs过程    
		queue<int> q;    
		vector<int> d;    
		d.resize(n, -1);    
		int from = allword[start],to = allword[end];    
		d[to] = 0;  //d记录的是路径长度,-1表示没经过    
		q.push(to);    
		vector<vector<int> > next;    
		next.resize(n);    
		while (!q.empty())
		{
			int x = q.front(), now= d[x] + 1;    
			//now相当于路径长度  
			//当now > d[from]时,则表示所有解都找到了  
			if ((d[from] >= 0)&& (now > d[from]))
			{
				break;    
			}    
			q.pop();    
			for (i = 0; i <con[x].size(); ++i)
			{
				int y = con[x][i];    
				//第一次经过y  
				if (d[y] < 0)
				{
					d[y] = now;    
					q.push(y);    
					next[y].push_back(x);    
				}    
				//非第一次经过y  
				else if (d[y] ==now)
				{  //是从上一层经过的,所以要保存
					next[y].push_back(x);    
				}    
			}    
		}    
		if (d[from] >= 0)
		{  //有解
			vector<string>path;    
			help(from, d,word,next, path,answer);    
		}    
		return answer;    
	}    
};


//解法二
//copyright@fuwutu 6/26/2013  
class Solution  
{  
public:  
	vector<vector<string>> findLadders(string start, string end, set<string>& dict)  
	{  
		vector<vector<string>> result, result_temp;  
		if (dict.erase(start) == 1 && dict.erase(end) == 1)   
		{  
			map<string, vector<string>> kids_from_start;  
			map<string, vector<string>> kids_from_end;  

			set<string> reach_start;  
			reach_start.insert(start);  
			set<string> reach_end;  
			reach_end.insert(end);  

			set<string> meet;  
			while (meet.empty() && !reach_start.empty() && !reach_end.empty())  
			{  
				if (reach_start.size() < reach_end.size())  
				{  
					search_next_reach(reach_start, reach_end, meet, kids_from_start, dict);  
				}  
				else  
				{  
					search_next_reach(reach_end, reach_start, meet, kids_from_end, dict);  
				}  
			}  

			if (!meet.empty())  
			{  
				for (set<string>::iterator it = meet.begin(); it != meet.end(); ++it)  
				{  
					vector<string> words(1, *it);  
					result.push_back(words);  
				}  

				walk(result, kids_from_start);  
				for (size_t i = 0; i < result.size(); ++i)  
				{  
					reverse(result[i].begin(), result[i].end());  
				}  
				walk(result, kids_from_end);  
			}  
		}  

		return result;  
	}  

private:  
	void search_next_reach(set<string>& reach, const set<string>& other_reach, set<string>& meet, map<string, vector<string>>& path, set<string>& dict)  
	{  
		set<string> temp;  
		reach.swap(temp);  

		for (set<string>::iterator it = temp.begin(); it != temp.end(); ++it)  
		{  
			string s = *it;  
			for (size_t i = 0; i < s.length(); ++i)  
			{  
				char back = s[i];  
				for (s[i] = 'a'; s[i] <= 'z'; ++s[i])  
				{  
					if (s[i] != back)  
					{  
						if (reach.count(s) == 1)  
						{  
							path[s].push_back(*it);  
						}  
						else if (dict.erase(s) == 1)  
						{  
							path[s].push_back(*it);  
							reach.insert(s);  
						}  
						else if (other_reach.count(s) == 1)  
						{  
							path[s].push_back(*it);  
							reach.insert(s);  
							meet.insert(s);  
						}  
					}  
				}  
				s[i] = back;  
			}  
		}  
	}  

	void walk(vector<vector<string>>& all_path, map<string, vector<string>> kids)  
	{  
		vector<vector<string>> temp;  
		while (!kids[all_path.back().back()].empty())  
		{  
			all_path.swap(temp);  
			all_path.clear();  
			for (vector<vector<string>>::iterator it = temp.begin(); it != temp.end(); ++it)  
			{  
				vector<string>& one_path = *it;  
				vector<string>& p = kids[one_path.back()];  
				for (size_t i = 0; i < p.size(); ++i)  
				{  
					all_path.push_back(one_path);  
					all_path.back().push_back(p[i]);  
				}  
			}  
		}  
	}  
};  


================================================
FILE: ebook/code/c/6.4:回文判断.c
================================================
//解法一
/**  
 *check weather s is a palindrome, n is the length of string s 
 *Copyright(C) fairywell 2011 
 */  
bool IsPalindrome(const char *s, int n)  
{  
    if (s == NULL || n < 1) return false; // invalid string  
    char *front, *back;  
    front = s; back = s + n - 1; // set front and back to the begin and endof the string  
    while (front < back) {  
        if (*front != *back) return false; // not a palindrome  
        ++front; --back;  
    }  
    return true; // check over, it's a palindrome  
}  


//解法二
/**  
 *check weather s is a palindrome, n is the length of string s 
 *Copyright(C) fairywell 2011 
 */  
bool IsPalindrome2(const char *s, int n)  
{  
    if (s == NULL || n < 1) return false; // invalid string  
    char *first, *second;  
    int m = ((n >> 1) - 1) >= 0 ? (n >> 1) - 1 : 0; // m is themiddle point of s      
    first = s + m; second = s + n - 1 - m;  
    while (first >= s)  
        if (s[first--] != s[second++]) return false; // not equal, so it's not apalindrome  
    return true; // check over, it's a palindrome  
} 


//问题扩展
/**  
 *find the longest palindrome in a string, n is the length of string s 
 *Copyright(C) fairywell 2011 
 */  
int LongestPalindrome(const char *s, int n)  
{
    int i, j, max;  
    if (s == 0 || n < 1) return 0;  
    max = 0;  
    for (i = 0; i < n; ++i) { // i is the middle point of the palindrome  
        for (j = 0; (i-j >= 0) && (i+j < n); ++j) // if the lengthof the palindrome is odd  
            if (s[i-j] != s[i+j]) break;  
        if (j*2+1 > max) max = j * 2 + 1;  
        for (j = 0; (i-j >= 0) && (i+j+1 < n); ++j) // for theeven case  
            if (s[i-j] != s[i+j+1]) break;  
        if (j*2+2 > max) max = j * 2 + 2;  
    }  
    return max;  
}  


================================================
FILE: ebook/code/c/6.6:跳台阶问题.c
================================================
//解法一
long long Fibonacci_Solution1(unsigned int n)
{
	int result[2] = {0, 1, 2};
	if (n <= 2)
		return result[n];

	return Fibonacci_Solution1(n - 1) + Fibonacci_Solution1(n - 2);
}


================================================
FILE: ebook/code/c/6.8:第一个只出现一次的字符.c
================================================
//代码一
#include <iostream>
using namespace std;

//查找第一个只出现一次的字符,第1个程序
//copyright@ Sorehead && July
//July、updated,2011.04.24.
char find_first_unique_char(char *str)
{
	int data[256];
	char *p;

	if (str == NULL)
		return '\0';

	memset(data, 0, sizeof(data));    //数组元素先全部初始化为0
	p = str;
	while (*p != '\0')
		data[(unsigned char)*p++]++;  //遍历字符串,在相应位置++,(同时,下标强制转换)

	while (*str != '\0')
	{
		if (data[(unsigned char)*str] == 1)  //最后,输出那个第一个只出现次数为1的字符
			return *str;

		str++;
	}

	return '\0';
}

int main()
{
	char *str = "afaccde";
	cout << find_first_unique_char(str) << endl;
	return 0;
}

//代码二
//查找第一个只出现一次的字符,第2个程序
//copyright@ yansha
//July、updated,2011.04.24.
char FirstNotRepeatChar(char* pString)
{
	if (!pString)
		return '\0';

	const int tableSize = 256;
	int hashTable[tableSize] = {0}; //存入数组,并初始化为0

	char* pHashKey = pString;
	while (*(pHashKey) != '\0')
		hashTable[*(pHashKey++)]++;

	while (*pString != '\0')
	{
		if (hashTable[*pString] == 1)
			return *pString;

		pString++;
	}
	return '\0';  //没有找到满足条件的字符,退出
}


================================================
FILE: ebook/code/c/6.9:Trie树.c
================================================
/*
 * Trie树(字典树)
 * liuyang1 2014.06.25
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define CHARSETSIZE    ('z'-'a' + 1)

typedef struct TrieNode{
    char c;
    int counter;
    struct TrieNode* nextMap[CHARSETSIZE];
}TrieNode;

void initTrieNode(TrieNode* p, char c)
{
    p->c = c;
    p->counter = 0;
    for(int i = 0; i < CHARSETSIZE; i++)
        p->nextMap[i] = NULL;
}

void incTrieNode(TrieNode* p)
{
    p->counter = p->counter + 1;
}

int compTrieNode(TrieNode* p, char c)
{
    if(p->c == c)
        return 0;
    else if(p->c > c)
        return 1;
    else
        return -1;
}

int Char2Index(char c)
{
    return c - 'a';
}

TrieNode* getNextChar(TrieNode* t, char c)
{
    return t->nextMap[Char2Index(c)];
}

void setNextChar(TrieNode* t, char c, TrieNode* new)
{
    TrieNode* ptr = getNextChar(t, c);
    if(ptr != NULL)
        printf("warnning: already set next char %p %c %p\n", t, c, new);
    t->nextMap[Char2Index(c)] = new;
}

void updateWord(TrieNode* t, char* word)
{

    TrieNode* ot = t;
    int len = strlen(word);
    int tail = len - 1;
    for(int i = 0; i < len; i++)
    {
        char c = word[i];
        TrieNode* ptr = getNextChar(t, c);
        if(ptr != NULL)
        {
            t = ptr;
            if(i == tail)
                incTrieNode(t);
        }else
        {
            TrieNode* new = (TrieNode*)malloc(sizeof(TrieNode));
            initTrieNode(new, c);
            if(i == tail)
                incTrieNode(new);
            setNextChar(t, c, new);
            t = new;
        }
    }
}

int getWord(TrieNode* t, char* word)
{
    int len = strlen(word);
    int tail = len - 1;
    for(int i = 0; i < len; i++)
    {
        char c = word[i];
        TrieNode* ptr = getNextChar(t, c);
        if(ptr != NULL)
        {
            t = ptr;
            if(i == tail)
                return t->counter;
        }else
            return 0;
    }
    return 0;
}
void dispTrieNodeI(TrieNode* t, int level)
{
    if(t == NULL)
        return;
    for(int i = 0; i < level; i++)
        putchar('\t');
    printf("%c %d\n", t->c, t->counter);
    int nextLevel = level + 1;
    for(int i = 0; i < CHARSETSIZE; i++)
    {
        dispTrieNodeI(t->nextMap[i], nextLevel);
    }
}

void dispTrieNode(TrieNode* t)
{
    dispTrieNodeI(t, 0);
}


int main()
{
    TrieNode* root = (TrieNode*)malloc(sizeof(TrieNode));
    initTrieNode(root, ' ');
    char words[][8] = {"inn", "int", "at", "age", "adv",
        "ant", "in", "in"};
    for(int i = 0; i < 8; i++)
        updateWord(root, words[i]);
    dispTrieNode(root);
    char se[] = "in";
    printf("search %s %d\n", se, getWord(root, se));
    return 0;
}


================================================
FILE: ebook/code/c/7.1:搜索引擎热门查询统计.c
================================================
//copyright@yansha &&July
//July、updated,2011.05.08

//题目描述:
//搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的
//长度为1-255字节。假设目前有一千万个记录(这些查询串的重复度比较高,虽然总数是1千万,但如果
//除去重复后,不超过3百万个。一个查询串的重复度越高,说明查询它的用户越多,也就是越热门),
//请你统计最热门的10个查询串,要求使用的内存不能超过1G。

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <assert.h>
using namespace std;

#define HASHLEN 2807303
#define WORDLEN 30

// 结点指针
typedef struct node_no_space *ptr_no_space;
typedef struct node_has_space *ptr_has_space;
ptr_no_space head[HASHLEN];

struct node_no_space
{
	char *word;
	int count;
	ptr_no_space next;
};

struct node_has_space
{
	char word[WORDLEN];
	int count;
	ptr_has_space next;
};

// 最简单hash函数
int hash_function(char const *p)
{
	int value = 0;
	while (*p != '\0')
	{
		value = value * 31 + *p++;
		if (value > HASHLEN)
			value = value % HASHLEN;
	}
	return value;
}

// 添加单词到hash表
void append_word(char const *str)
{
	int index = hash_function(str);
	ptr_no_space p = head[index];
	while (p != NULL)
	{
		if (strcmp(str, p->word) == 0)
		{
			(p->count)++;
			return;
		}
		p = p->next;
	}

	// 新建一个结点
	ptr_no_space q = new node_no_space;
	q->count = 1;
	q->word = new char [strlen(str)+1];
	strcpy(q->word, str);
	q->next = head[index];
	head[index] = q;
}


// 将单词处理结果写入文件
void write_to_file()
{
	FILE *fp = fopen("result.txt", "w");
	assert(fp);

	int i = 0;
	while (i < HASHLEN)
	{
		for (ptr_no_space p = head[i]; p != NULL; p = p->next)
			fprintf(fp, "%s  %d\n", p->word, p->count);
		i++;
	}
	fclose(fp);
}

// 从上往下筛选,保持小根堆
void sift_down(node_has_space heap[], int i, int len)
{
	int min_index = -1;
	int left = 2 * i;
	int right = 2 * i + 1;

	if (left <= len && heap[left].count < heap[i].count)
		min_index = left;
	else
		min_index = i;

	if (right <= len && heap[right].count < heap[min_index].count)
		min_index = right;

	if (min_index != i)
	{
		// 交换结点元素
		swap(heap[i].count, heap[min_index].count);

		char buffer[WORDLEN];
		strcpy(buffer, heap[i].word);
		strcpy(heap[i].word, heap[min_index].word);
		strcpy(heap[min_index].word, buffer);

		sift_down(heap, min_index, len);
	}
}

// 建立小根堆
void build_min_heap(node_has_space heap[], int len)
{
	if (heap == NULL)
		return;

	int index = len / 2;
	for (int i = index; i >= 1; i--)
		sift_down(heap, i, len);
}

// 去除字符串前后符号
void handle_symbol(char *str, int n)
{
	while (str[n] < '0' || (str[n] > '9' && str[n] < 'A') || (str[n] > 'Z' && str[n] < 'a') || str[n] > 'z')
	{
		str[n] = '\0';
		n--;
	}

	while (str[0] < '0' || (str[0] > '9' && str[0] < 'A') || (str[0] > 'Z' && str[0] < 'a') || str[0] > 'z')
	{
		int i = 0;
		while (i < n)
		{
			str[i] = str[i+1];
			i++;
		}
		str[i] = '\0';
		n--;
	}
}

int main()
{
	char str[WORDLEN];
	for (int i = 0; i < HASHLEN; i++)
		head[i] = NULL;

	// 将字符串用hash函数转换成一个整数并统计出现频率
	FILE *fp_passage = fopen("string.txt", "r");
	assert(fp_passage);
	while (fscanf(fp_passage, "%s", str) != EOF)
	{
		int n = strlen(str) - 1;
		if (n > 0)
			handle_symbol(str, n);
		append_word(str);
	}
	fclose(fp_passage);

	// 将统计结果输入文件
	write_to_file();

	int n = 10;
	ptr_has_space heap = new node_has_space [n+1];

	int c;

	FILE *fp_word = fopen("result.txt", "r");
	assert(fp_word);
	for (int j = 1; j <= n; j++)
	{
		fscanf(fp_word, "%s %d", &str, &c);
		heap[j].count = c;
		strcpy(heap[j].word, str);
	}

	// 建立小根堆
	build_min_heap(heap, n);

	// 查找出现频率最大的10个单词
	while (fscanf(fp_word, "%s %d", &str, &c) != EOF)
	{
		if (c > heap[1].count)
		{
			heap[1].count = c;
			strcpy(heap[1].word, str);
			sift_down(heap, 1, n);
		}
	}
	fclose(fp_word);

	// 输出出现频率最大的单词
	for (int k = 1; k <= n; k++)
		cout << heap[k].count << " " << heap[k].word << endl;

	return 0;
}


================================================
FILE: ebook/code/c/7.2:最短摘要的生成.c
================================================
//July、updated,2011.10.21
int nTargetLen = N + 1;           // 设置目标长度为总长度+1  
int pBegin = 0;                     // 初始指针  
int pEnd = 0;                       // 结束指针  
int nLen = N;                       // 目标数组的长度为N  
int nAbstractBegin = 0;           // 目标摘要的起始地址  
int nAbstractEnd = 0;           // 目标摘要的结束地址  

while(true)  
{  
    // 假设未包含所有的关键词,并且后面的指针没有越界,往后移动指针  
    while(!isAllExisted() && pEnd < nLen)  
    {  
        pEnd++;  
    }  

    // 假设找到一段包含所有关键词信息的字符串  
    while(isAllExisted())  
    {  
        if(pEnd – pBegin < nTargetLen)  
        {  
            nTargetLen = pEnd – pBegin;  
            nAbstractBegin = pBegin;  
            nAbstractEnd = pEnd – 1;   
        }  
        pBegin++;  
    }  
    if(pEnd >= N)  
        Break;  
}


================================================
FILE: ebook/code/c/7.3:倒排索引关键词不重复Hash编码.c
================================================
//24.4、暴雪的Hash算法
//函数prepareCryptTable以下的函数生成一个长度为0x500(合10进制数:1280)的cryptTable[0x500]  
void prepareCryptTable()  
{   
	unsigned long seed = 0x00100001, index1 = 0, index2 = 0, i;  

	for( index1 = 0; index1 < 0x100; index1++ )  
	{   
		for( index2 = index1, i = 0; i < 5; i++, index2 += 0x100 )  
		{   
			unsigned long temp1, temp2;  

			seed = (seed * 125 + 3) % 0x2AAAAB;  
			temp1 = (seed & 0xFFFF) << 0x10;  

			seed = (seed * 125 + 3) % 0x2AAAAB;  
			temp2 = (seed & 0xFFFF);  

			cryptTable[index2] = ( temp1 | temp2 );   
		}   
	}   
}  


//函数HashString以下函数计算lpszFileName 字符串的hash值,其中dwHashType 为hash的类型 
unsigned long HashString(const char *lpszkeyName, unsigned long dwHashType )  
{  
	unsigned char *key  = (unsigned char *)lpszkeyName;  
	unsigned long seed1 = 0x7FED7FED;  
	unsigned long seed2 = 0xEEEEEEEE;  
	int ch;  

	while( *key != 0 )  
	{  
		ch = *key++;  
		seed1 = cryptTable[(dwHashType<<8) + ch] ^ (seed1 + seed2);  
		seed2 = ch + seed1 + seed2 + (seed2<<5) + 3;  
	}  
	return seed1;  
} 


//函数GetHashTablePos下述函数为在Hash表中查找是否存在目标字符串,有则返回要查找字符串的Hash值,无则return -1.  
int GetHashTablePos( har *lpszString, SOMESTRUCTURE *lpTable )   
	//lpszString要在Hash表中查找的字符串,lpTable为存储字符串Hash值的Hash表。  
{   
	int nHash = HashString(lpszString);  //调用上述函数HashString,返回要查找字符串lpszString的Hash值。  
	int nHashPos = nHash % nTableSize;  

	if ( lpTable[nHashPos].bExists  &&  !strcmp( lpTable[nHashPos].pString, lpszString ) )   
	{  //如果找到的Hash值在表中存在,且要查找的字符串与表中对应位置的字符串相同,  
		return nHashPos;    //返回找到的Hash值  
	}   
	else  
	{  
		return -1;    
	}   
}  


//函数GetHashTablePos中,lpszString 为要在hash表中查找的字符串;lpTable 为存储字符串hash值的hash表;nTableSize 为hash表的长度:   
int GetHashTablePos( char *lpszString, MPQHASHTABLE *lpTable, int nTableSize )  
{  
	const int  HASH_OFFSET = 0, HASH_A = 1, HASH_B = 2;  

	int  nHash = HashString( lpszString, HASH_OFFSET );  
	int  nHashA = HashString( lpszString, HASH_A );  
	int  nHashB = HashString( lpszString, HASH_B );  
	int  nHashStart = nHash % nTableSize;  
	int  nHashPos = nHashStart;  

	while ( lpTable[nHashPos].bExists )  
	{  
		//     如果仅仅是判断在该表中时候存在这个字符串,就比较这两个hash值就可以了,不用对结构体中的字符串进行比较。  
		//         这样会加快运行的速度?减少hash表占用的空间?这种方法一般应用在什么场合?  
		if (   lpTable[nHashPos].nHashA == nHashA  
			&&  lpTable[nHashPos].nHashB == nHashB )  
		{  
			return nHashPos;  
		}  
		else  
		{  
			nHashPos = (nHashPos + 1) % nTableSize;  
		}  

		if (nHashPos == nHashStart)  
			break;  
	}  
	return -1;  
}  



//24.5、不重复Hash编码
//函数prepareCryptTable以下的函数生成一个长度为0x500(合10进制数:1280)的cryptTable[0x500]  
void prepareCryptTable()  
{  
	unsigned long seed = 0x00100001, index1 = 0, index2 = 0, i;  

	for( index1 = 0; index1 <0x100; index1++ )  
	{  
		for( index2 = index1, i = 0; i < 5; i++, index2 += 0x100)  
		{  
			unsigned long temp1, temp2;  
			seed = (seed * 125 + 3) % 0x2AAAAB;  
			temp1 = (seed & 0xFFFF)<<0x10;  
			seed = (seed * 125 + 3) % 0x2AAAAB;  
			temp2 = (seed & 0xFFFF);  
			cryptTable[index2] = ( temp1 | temp2 );  
		}  
	}  
}  

//函数HashString以下函数计算lpszFileName 字符串的hash值,其中dwHashType 为hash的类型,  
unsigned long HashString(const char *lpszkeyName, unsigned long dwHashType )  
{  
	unsigned char *key  = (unsigned char *)lpszkeyName;  
	unsigned long seed1 = 0x7FED7FED;  
	unsigned long seed2 = 0xEEEEEEEE;  
	int ch;  

	while( *key != 0 )  
	{  
		ch = *key++;  
		seed1 = cryptTable[(dwHashType<<8) + ch] ^ (seed1 + seed2);  
		seed2 = ch + seed1 + seed2 + (seed2<<5) + 3;  
	}  
	return seed1;  
}  

/////////////////////////////////////////////////////////////////////  
//function: 哈希词典 编码  
//parameter:  
//author: lei.zhou  
//time: 2011-12-14  
/////////////////////////////////////////////////////////////////////  
MPQHASHTABLE TestHashTable[nTableSize];  
int TestHashCTable[nTableSize];  
int TestHashDTable[nTableSize];  
key_list test_data[nTableSize];  

//直接调用上面的hashstring,nHashPos就是对应的HASH值。  
int insert_string(const char *string_in)  
{  
	const int HASH_OFFSET = 0, HASH_C = 1, HASH_D = 2;  
	unsigned int nHash = HashString(string_in, HASH_OFFSET);  
	unsigned int nHashC = HashString(string_in, HASH_C);  
	unsigned int nHashD = HashString(string_in, HASH_D);  
	unsigned int nHashStart = nHash % nTableSize;  
	unsigned int nHashPos = nHashStart;  
	int ln, ires = 0;  

	while (TestHashTable[nHashPos].bExists)  
	{  
		//      if (TestHashCTable[nHashPos]  == (int) nHashC && TestHashDTable[nHashPos] == (int) nHashD)  
		//          break;  
		//      //...  
		//      else  
		//如之前所提示读者的那般,暴雪的Hash算法对于查询那样处理可以,但对插入就不能那么解决  
		nHashPos = (nHashPos + 1) % nTableSize;  

		if (nHashPos == nHashStart)  
			break;  
	}  

	ln = strlen(string_in);  
	if (!TestHashTable[nHashPos].bExists && (ln < nMaxStrLen))  
	{   
		TestHashCTable[nHashPos] = nHashC;  
		TestHashDTable[nHashPos] = nHashD;  

		test_data[nHashPos] = (KEYNODE *) malloc (sizeof(KEYNODE) * 1);  
		if(test_data[nHashPos] == NULL)  
		{  
			printf("10000 EMS ERROR !!!!\n");  
			return 0;  
		}  

		test_data[nHashPos]->pkey = (char *)malloc(ln+1);  
		if(test_data[nHashPos]->pkey == NULL)  
		{  
			printf("10000 EMS ERROR !!!!\n");  
			return 0;  
		}  

		memset(test_data[nHashPos]->pkey, 0, ln+1);  
		strncpy(test_data[nHashPos]->pkey, string_in, ln);  
		*((test_data[nHashPos]->pkey)+ln) = 0;  
		test_data[nHashPos]->weight = nHashPos;  

		TestHashTable[nHashPos].bExists = 1;  
	}  
	else  
	{  
		if(TestHashTable[nHashPos].bExists)  
			printf("30000 in the hash table %s !!!\n", string_in);  
		else  
			printf("90000 strkey error !!!\n");  
	}  
	return nHashPos;  
}


void bigIndex_hash(const char *docpath, const char *hashpath)  
{  
	FILE *fr, *fw;  
	int len;  
	char *pbuf, *p;  
	char dockey[TERM_MAX_LENG];  

	if(docpath == NULL || *docpath == '\0')  
		return;  

	if(hashpath == NULL || *hashpath == '\0')  
		return;  

	fr = fopen(docpath, "rb");  //读取文件docpath  
	fw = fopen(hashpath, "wb");  
	if(fr == NULL || fw == NULL)  
	{  
		printf("open read or write file error!\n");  
		return;  
	}  

	pbuf = (char*)malloc(BUFF_MAX_LENG);  
	if(pbuf == NULL)  
	{  
		fclose(fr);  
		return ;  
	}  

	memset(pbuf, 0, BUFF_MAX_LENG);  

	while(fgets(pbuf, BUFF_MAX_LENG, fr))  
	{  
		len = GetRealString(pbuf);  
		if(len <= 1)  
			continue;  
		p = strstr(pbuf, "#####");    
		if(p != NULL)  
			continue;  

		p = strstr(pbuf, "  ");  
		if (p == NULL)  
		{  
			printf("file contents error!");  
		}  

		len = p - pbuf;  
		dockey[0] = 0;  
		strncpy(dockey, pbuf, len);  

		dockey[len] = 0;        

		int num = insert_string(dockey);   

		dockey[len] = ' ';  
		dockey[len+1] = '\0';  
		char str[20];  
		itoa(num, str, 10);  

		strcat(dockey, str);  
		dockey[len+strlen(str)+1] = '\0';  
		fprintf (fw, "%s\n", dockey);  

	}  
	free(pbuf);  
	fclose(fr);  
	fclose(fw);  
} 


int main()  
{  
	prepareCryptTable();  //Hash表起初要初始化  

	//现在要把整个big_index文件插入hash表,以取得编码结果  
	bigIndex_hash("big_index.txt", "hashpath.txt");  
	system("pause");  

	return 0;  
}  



//在上面的bigIndex_hashcode函数的基础上,修改
void bigIndex_hashcode(const char *in_file_path, const char *out_file_path)  
{  
	FILE *fr, *fw;  
	int len, value;  
	char *pbuf, *pleft, *p;  
	char keyvalue[TERM_MAX_LENG], str[WORD_MAX_LENG];  

	if(in_file_path == NULL || *in_file_path == '\0') {  
		printf("input file path error!\n");  
		return;  
	}  

	if(out_file_path == NULL || *out_file_path == '\0') {  
		printf("output file path error!\n");  
		return;  
	}  

	fr = fopen(in_file_path, "r");  //读取in_file_path路径文件  
	fw = fopen(out_file_path, "w");  

	if(fr == NULL || fw == NULL)  
	{  
		printf("open read or write file error!\n");  
		return;  
	}  

	pbuf = (char*)malloc(BUFF_MAX_LENG);  
	pleft = (char*)malloc(BUFF_MAX_LENG);  
	if(pbuf == NULL || pleft == NULL)  
	{  
		printf("allocate memory error!");  
		fclose(fr);  
		return ;  
	}  

	memset(pbuf, 0, BUFF_MAX_LENG);  

	int offset = 1;  
	while(fgets(pbuf, BUFF_MAX_LENG, fr))  
	{  
		if (--offset > 0)  
			continue;  

		if(GetRealString(pbuf) <= 1)  
			continue;  

		p = strstr(pbuf, "#####");    
		if(p != NULL)  
			continue;  

		p = strstr(pbuf, "  ");  
		if (p == NULL)  
		{  
			printf("file contents error!");  
		}  

		len = p - pbuf;  

		// 确定跳过行数  
		strcpy(pleft, p+1);   
		offset = atoi(pleft) + 1;  

		strncpy(keyvalue, pbuf, len);    
		keyvalue[len] = '\0';  
		value = insert_string(keyvalue);  

		if (value != -1) {  

			// key value中插入空格  
			keyvalue[len] = ' ';  
			keyvalue[len+1] = '\0';  

			itoa(value, str, 10);  
			strcat(keyvalue, str);  

			keyvalue[len+strlen(str)+1] = ' ';  
			keyvalue[len+strlen(str)+2] = '\0';  

			keysize++;  
			itoa(keysize, str, 10);  
			strcat(keyvalue, str);  

			// 将key value写入文件  
			fprintf (fw, "%s\n", keyvalue);  

		}  
	}  
	free(pbuf);  
	fclose(fr);  
	fclose(fw);  
} 


================================================
FILE: ebook/code/c/7.4:倒排索引关键词 Hash 不重复编码实践.c
================================================
#include <stdio.h>  
#include <ctype.h>     //多谢citylove指正。  
//crytTable[]里面保存的是HashString函数里面将会用到的一些数据,在prepareCryptTable  
//函数里面初始化  
unsigned long cryptTable[0x500];  
  
//以下的函数生成一个长度为0x500(合10进制数:1280)的cryptTable[0x500]  
void prepareCryptTable()  
{   
    unsigned long seed = 0x00100001, index1 = 0, index2 = 0, i;  
  
    for( index1 = 0; index1 < 0x100; index1++ )  
    {   
        for( index2 = index1, i = 0; i < 5; i++, index2 += 0x100 )  
        {   
            unsigned long temp1, temp2;  
  
            seed = (seed * 125 + 3) % 0x2AAAAB;  
            temp1 = (seed & 0xFFFF) << 0x10;  
  
            seed = (seed * 125 + 3) % 0x2AAAAB;  
            temp2 = (seed & 0xFFFF);  
  
            cryptTable[index2] = ( temp1 | temp2 );   
       }   
   }   
}  
  
//以下函数计算lpszFileName 字符串的hash值,其中dwHashType 为hash的类型,  
//在下面GetHashTablePos函数里面调用本函数,其可以取的值为0、1、2;该函数  
//返回lpszFileName 字符串的hash值;  
unsigned long HashString( char *lpszFileName, unsigned long dwHashType )  
{   
    unsigned char *key  = (unsigned char *)lpszFileName;  
unsigned long seed1 = 0x7FED7FED;  
unsigned long seed2 = 0xEEEEEEEE;  
    int ch;  
  
    while( *key != 0 )  
    {   
        ch = toupper(*key++);  
  
        seed1 = cryptTable[(dwHashType << 8) + ch] ^ (seed1 + seed2);  
        seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;   
    }  
    return seed1;   
}  
  
//在main中测试argv[1]的三个hash值:  
//./hash  "arr/units.dat"  
//./hash  "unit/neutral/acritter.grp"  
int main( int argc, char **argv )  
{  
    unsigned long ulHashValue;  
    int i = 0;  
  
    if ( argc != 2 )  
    {  
        printf("please input two arguments/n");  
        return -1;  
    }  
  
     /*初始化数组:crytTable[0x500]*/  
     prepareCryptTable();  
  
     /*打印数组crytTable[0x500]里面的值*/  
     for ( ; i < 0x500; i++ )  
     {  
         if ( i % 10 == 0 )  
         {  
             printf("/n");  
         }  
  
         printf("%-12X", cryptTable[i] );  
     }  
  
     ulHashValue = HashString( argv[1], 0 );  
     printf("/n----%X ----/n", ulHashValue );  
  
     ulHashValue = HashString( argv[1], 1 );  
     printf("----%X ----/n", ulHashValue );  
  
     ulHashValue = HashString( argv[1], 2 );  
     printf("----%X ----/n", ulHashValue );  
  
     return 0;  
}  


================================================
FILE: ebook/code/c/makefile
================================================
CC = gcc
CPPFLAGS = -Wall

FILE_SUFFIX = c

SRCS := $(wildcard *.$(FILE_SUFFIX))
EXES := $(patsubst %.$(FILE_SUFFIX),%,$(SRCS))

all:$(EXES)

$(EXES): % : %.$(FILE_SUFFIX)
	$(CC) $(CPPFLAGS) $< -o $@

clean:
	rm -rf $(EXES)


================================================
FILE: ebook/code/cpp/1.1:左旋转字符串.cpp
================================================
#include <iostream>

using namespace std;

/* brute force */
void leftShiftOne(string &str) 
{
    int n = str.length();
    if (n < 2) return; // args check
    char t = str[0];  //保存第一个字符
    for (int i = 1; i < n; ++i) 
    {
        str[i - 1] = str[i];
    }
    str[n - 1] = t;
}

void rotate_1(string &str, int m) 
{
    while (m--) 
    {
        leftShiftOne(str);
    }
}

/* pointer manipulation part 1 */
void rotate_2(string &str, int m)
{

    if (str.length() == 0 || m <= 0)
        return;

    int n = str.length();

    if (m % n <= 0)
        return;

    int p1 = 0, p2 = m;
    int k = (n - m) - n % m;

    // 交换p1,p2指向的元素,然后移动p1,p2
    while (k --)
    {
        swap(str[p1], str[p2]);
        p1++;
        p2++;
    }

    // 处理尾部,r为尾部左移次数
    int r = n - p2;
    while (r--)
    {
        int i = p2;
        while (i > p1)
        {
            swap(str[i], str[i-1]);
            i--;
        }
        p2++;
        p1++;
    }
}

/* pointer manipulation part 2 */
void rotate_3(string &str, int m)
{
    if (str.length() == 0 || m < 0)
        return;

    //初始化p1,p2
    int p1 = 0, p2 = m;
    int n = str.length();

    // 处理m大于n
    if (m > n)
        return;

    // 循环直至p2到达字符串末尾
    while(true)
    {
        swap(str[p1], str[p2]);
        p1++;
        if (p2 < n - 1)
            p2++;
        else
            break;
    }

    // 处理尾部,r为尾部循环左移次数
    int r = m - n % m;
    while (r--) //外循环执行一次
    {
        int i = p1;
        char temp = str[p1];
        while (i < p2) //内循环执行俩次
        {
            str[i] = str[i+1];
            i++;
        }
        str[p2] = temp;
    }
}

/* pointer manipulation part 3 */
/*
 *左旋字符串str,m为负数时表示右旋abs(m)个字母
 */
void rotate_4(string &str, int m) 
{
    if (str.length() == 0)
        return;

    int n = str.length();

    //处理大于str长度及m为负数的情况,positiveMod可以取得m为负数时对n取余得到正数
#define positiveMod(m, n) ((m) % (n) + (n)) % (n)
    m = positiveMod(m, n);
    if (m == 0)
        return;

    int p1 = 0, p2 = m;
    int round;

    //p2当前所指和之后的m-1个字母共m个字母,就可以和p2前面的m个字母交换。
    while (p2 + m - 1 < n) 
    {
        round = m;
        while (round--)
        {
            swap(str[p1], str[p2]);
            p1++;
            p2++;
        }
    }

    //剩下的不足m个字母逐个交换
    int r = n - p2;
    while (r--)
    {
        int i = p2;
        while (i > p1) 
        {
            swap(str[i], str[i - 1]);
            i--;
        }
        p2++;
        p1++;
    }
}

/* recursion */
void rotate_5(string &str, int n, int m, int head, int tail, bool flag)
{
    //n 待处理部分的字符串长度,m:待处理部分的旋转长度
    //head:待处理部分的头指针,tail:待处理部分的尾指针
    //flag = true进行左旋,flag = false进行右旋

    // 返回条件
    if (head == tail || m <= 0)
        return;

    if (flag == true)
    {
        int p1 = head;
        int p2 = head + m;  //初始化p1,p2

        //1、左旋:对于字符串abc def ghi gk,
        //将abc右移到def ghi gk后面,此时n = 11,m = 3,m’ = n % m = 2;
        //abc def ghi gk -> def ghi abc gk

        int k = (n - m) - n % m;   //p1,p2移动距离,向右移六步

        for (int i = 0; i < k; i++, p1++, p2++)
            swap(str[p1], str[p2]);

        rotate_5(str, n - k, n % m, p1, tail, false);  //flag标志变为false,结束左旋,下面,进入右旋
    }
    else
    {
        //2、右旋:问题变成gk左移到abc前面,此时n = m’ + m = 5,m = 2,m’ = n % m 1;
        //abc gk -> a gk bc

        int p1 = tail;
        int p2 = tail - m;

        // p1,p2移动距离,向左移俩步
        int k = (n - m) - n % m;

        for (int i = 0; i < k; i++, p1--, p2--)
            swap(str[p1], str[p2]);

        rotate_5(str, n - k, n % m, head, p1, true);  //再次进入上面的左旋部分,
        //3、左旋:问题变成a右移到gk后面,此时n = m’ + m = 3,m = 1,m’ = n % m = 0;
        //a gk bc-> gk a bc。 由于此刻,n % m = 0,满足结束条件,返回结果。
    }
}

/* using gcd */

//所有序号为 (j+i *m) % n (j 表示每个循环链起始位置,i 为计数变量,m表示左旋转位数,n表示字符串长度),
//会构成一个循环链(共有gcd(n,m)个,gcd为n、m的最大公约数),

//每个循环链上的元素只要移动一个位置即可,最后整个过程总共交换了n次
//(每一次循环链,是交换n/gcd(n,m)次,共有gcd(n,m)个循环链,所以,总共交换n次)。

int gcd (int m, int n)
{
    int c;
    while ( m != 0 ) 
    {
        c = m; 
        m = n % m;  
        n = c;
    }
    return n;
}

void rotate_6(string &str, int m)
{
    int lenOfStr = str.length();
    int numOfGroup = gcd(lenOfStr, m);
    int elemInSub = lenOfStr / numOfGroup;

    for(int j = 0; j < numOfGroup; j++)
        //对应上面的文字描述,外循环次数j为循环链的个数,即gcd(n, m)个循环链
    {
        char tmp = str[j];
        int i;
        for (i = 0; i < elemInSub - 1; i++)
            //内循环次数i为,每个循环链上的元素个数,n/gcd(m,n)次
            str[(j + i * m) % lenOfStr] = str[(j + (i + 1) * m) % lenOfStr];
        str[(j + i * m) % lenOfStr] = tmp;
    }
}

//对上述方案4的改写。
//④ 所有序号为 (i+t*k) % n (i为指定整数,t为任意整数),....
//copyright@ hplonline && July 2011.04.18。
//July、sahala、yansha,updated,2011.06.02。
void rotate_7(char *begin, char *mid, char *end)
{
    int n = end - begin;
    int k = mid - begin;
    int d = gcd(n, k);
    int i, j;
    for (i = 0; i < d; i ++)
    {
        int tmp = begin[i];
        int last = i;

        //i+k为i右移k的位置,%n是当i+k>n时从左重新开始。
        for (j = (i + k) % n; j != i; j = (j + k) % n)    //多谢laocpp指正。
        {
            begin[last] = begin[j];
            last = j;
        }
        begin[last] = tmp;
    }
}

/* 3 step rotation */
//Copyright@ 小桥流水 && July
//c代码实现,已测试正确。
//July、updated,2011.04.17。
char *invert(char *start, char *end)
{
    char tmp, *ptmp = start;
    while (start != NULL && end != NULL && start < end)
    {
        tmp = *start;
        *start = *end;
        *end = tmp;
        start ++;
        end --;
    }
    return ptmp;
}

char *rotate_8(char *s, int len, int pos)   //pos为要旋转的字符个数,或长度,下面主函数测试中,pos=3。
{
    invert(s, s + (pos - 1));  //如上,X->X^T,即 abc->cba
    invert(s + pos, s + (len - 1)); //如上,Y->Y^T,即 def->fed
    invert(s, s + (len - 1));  //如上,整个翻转,(X^TY^T)^T=YX,即 cbafed->defabc。
    return s;
}

int main () {

    string s;
    int shift = 3;

    s = "abcdefghi";
    cout << "testing rotate_1" << endl;
    cout << "before shift: " << s << endl;
    rotate_1(s, shift);
    cout << "after  shift: " << s << endl << endl;

    s = "abcdefghi";
    cout << "testing rotate_2" << endl;
    cout << "before shift: " << s << endl;
    rotate_2(s, shift);
    cout << "after  shift: " << s << endl << endl;

    s = "abcdefghi";
    cout << "testing rotate_3" << endl;
    cout << "before shift: " << s << endl;
    rotate_3(s, shift);
    cout << "after  shift: " << s << endl << endl;

    s = "abcdefghi";
    cout << "testing rotate_4" << endl;
    cout << "before shift: " << s << endl;
    rotate_4(s, shift);
    cout << "after  shift: " << s << endl << endl;

    s = "abcdefghi";
    cout << "testing rotate_4 (shift right)" << endl;
    cout << "before shift: " << s << endl;
    rotate_4(s, -3);
    cout << "after  shift: " << s << endl << endl;

    s = "abcdefghi";
    cout << "testing rotate_5" << endl;
    cout << "before shift: " << s << endl;
    rotate_5(s, s.length(), shift, 0, s.length() - 1, true);
    cout << "after  shift: " << s << endl << endl;

    s = "abcdefghi";
    cout << "testing rotate_5 (shift right)" << endl;
    cout << "before shift: " << s << endl;
    rotate_5(s, s.length(), shift, 0, s.length() - 1, false);
    cout << "after  shift: " << s << endl << endl;

    s = "abcdefghi";
    cout << "testing rotate_6" << endl;
    cout << "before shift: " << s << endl;
    rotate_6(s, shift);
    cout << "after  shift: " << s << endl << endl;

    char str1[] = "abcdefghi";
    cout << "testing rotate_7" << endl;
    cout << "before shift: " << str1 << endl;
    rotate_7(&str1[0], &str1[shift], &str1[9]);
    cout << "after  shift: " << str1 << endl << endl;

    char str2[] = "abcdefghi";
    cout << "testing rotate_8" << endl;
    cout << "before shift: " << str2 << endl;
    cout << "after  shift: " << rotate_8(str2, 9, shift) << endl;

    return 0;
}


================================================
FILE: ebook/code/cpp/2.1:寻找最小的 k 个数.cpp
================================================
#include <iostream>

using namespace std;

//获取父节点指针
int GetParent(int* pArray, int* pLast)
{
  if(pLast >= pArray)
        return (pLast - pArray + 1) / 2 - 1;
    else
        return -1;
}

//获取左孩子节点指针
int GetLeft(int* pArray, int* pLast)
{
    if(pLast >= pArray)
        return (pLast - pArray + 1) * 2 - 1;
    else
        return -1;
}

//获取右孩子节点指针
int GetRight(int* pArray, int* pLast)
{
    if(pLast >= pArray)
        return (pLast - pArray + 1) * 2;
    else
        return -1;
}

//交换两个元素的值
void Swap(int* pa, int* pb)
{
    int temp = *pa;
    *pa = *pb;
    *pb = temp;
}

//最大化堆过程,保持最大堆性质,即父节点元素值大于等于其子孙节点元素
void MaxHeapify(int* pArray, const int nLength, const int nI)
{
    if((nI < 0) || (pArray == NULL) || (nI > nLength))
    {
        return;
    }

    int nLeft = GetLeft(pArray, pArray+nI);         //获取当前节点的左儿子索引
    int nRight = GetRight(pArray, pArray+nI);       //获取当前节点的右儿子索引
    int* pLargest = NULL;                           //初始化记录最大值的指针

  //若当前元素小于左儿子,则对最大值指针赋值为左儿子指针
    if((nLeft < nLength) && (*(pArray + nI) < *(pArray + nLeft)))
    {
        pLargest = pArray + nLeft;
    }
    else
    {
        pLargest = pArray + nI;
    }

  //若右儿子元素大于最大值元素,则对最大值指针赋值
    if((nRight < nLength) && (*(pLargest) < *(pArray + nRight)))
    {
        pLargest = pArray + nRight;
    }

  //当前元素指针不为最大值,则交换最大值与当前元素值
    if(pLargest != (pArray + nI))
    {
        Swap(pLargest, (pArray + nI));
        {
      //对交换后后的子堆递归进行堆的最大化过程
            MaxHeapify(pArray, nLength, pLargest - pArray);
        }
    }
}

//建立最大堆函数
int BuildMaxHeap(int* pArray, int* pLast)
{
    if((pArray == NULL) || (pLast == NULL))
    {
        return -1;
    }

    int nLength = pLast - pArray + 1;   //获取当前堆数组长度
    int nMid = nLength / 2;

    //对数组的前半数据进行堆最大化过程,因为后半部分数据为叶子节点数据,已经保持了最大堆性质
    for(int i = nMid ; i >= 0; i--)
    {
        MaxHeapify(pArray, nLength, i);
    }
    return 0;
}

//寻找数组中最小的k个数,考虑到对空间的有效利用,这里数组pArray的前k项即为最小的k个数,函数正确返回0,错误返回-1
int FindMinimumK(int* pArray, int nLength, int k)
{
    int nIndex = 0;

    if((pArray == NULL) || (nLength <= 0) || (k <= 0))
        return -1;

    BuildMaxHeap(pArray, pArray + k - 1);

    for(nIndex = k; nIndex < nLength; nIndex++)
    {
        if(pArray[0] > pArray[nIndex])
        {
            Swap(&pArray[0], &pArray[nIndex]);
            MaxHeapify(pArray, k, 0);
        }
    }
    return 0;
}

int main()
{
    int Array[] = {9, 8, 6, 4, 1, 2, 3};
    int k = 3;
    int i = 0;
    FindMinimumK(Array, sizeof(Array) / sizeof(int), k);
    cout << "The " << k << " minimum numbers in Array are:" << endl;
    for(i = 0; i < k; i++)
        cout << Array[i] << " ";
    cout << endl;
    return 0;
}


================================================
FILE: ebook/code/cpp/3.1:二分查找实现(Jon Bentley
================================================


================================================
FILE: ebook/code/cpp/4.2:完美洗牌算法.cpp
================================================
//compiled with g++
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <cassert>
using namespace std;

void cycle_leader(vector<int> &a,int from, int mod) {  
  for (int i = from * 2 % mod;i != from; i = i * 2 % mod)  
     swap(a[from],a[i]);
}

void perfect_shuffle(vector<int> &a,int n){
   int n2,m,i,k,t;
   vector<int>::iterator iter = a.begin()+1; //exclude index 0
   for(;n > 1;){
      //step 1
      n2 = n * 2;
      for(k = 0,m = 1; n2 / m >=3; ++k,m *= 3)
         ;
      m /= 2;
      // 2m = 3^k - 1 , 3^k <= 2n < 3^(k + 1)

      //step 2   STL/algorithm-rotate
      rotate(iter+m, iter+n, iter+m+n ); //right cyclic shift of the index[m+1,...,n+m] O(n)
      
      //step 3
      for(i = 0,t = 1;i < k; ++i,t *= 3)
         cycle_leader(a,t,m * 2 +1);
      
      //step 4
      iter += (m * 2);
      n -= m;
   }
   //n = 1
   swap(a[1],a[2]);
}

int main(){
   vector<int > a;
   a.push_back(0);//to make index start from 1
   int num = 0,length = 0;
   cout<<"Please input your number to be shuffled and '0' to end up \n";
   cin>>num;
   while(num != 0){
      a.push_back(num);
      cin>>num;
   }
   cout<<"The input number is \n";
   copy(a.begin()+1,a.end(),ostream_iterator<int> (cout," "));
   cout<<"\n";
   
   length = a.size();
   assert(length % 2 == 1); //the size of input number is even
   perfect_shuffle(a,length / 2);
   
   cout<<"After shuffered,the number is  \n";
   copy(a.begin()+1,a.end(),ostream_iterator<int> (cout," "));
   cout<<"\n";
}


================================================
FILE: ebook/code/cpp/7.4:倒排索引关键词 Hash 不重复编码实践.cpp
================================================
#include <stdio.h>  
#include <ctype.h>     //多谢citylove指正。  
//crytTable[]里面保存的是HashString函数里面将会用到的一些数据,在prepareCryptTable  
//函数里面初始化  
unsigned long cryptTable[0x500];  
  
//以下的函数生成一个长度为0x500(合10进制数:1280)的cryptTable[0x500]  
void prepareCryptTable()  
{   
    unsigned long seed = 0x00100001, index1 = 0, index2 = 0, i;  
  
    for( index1 = 0; index1 < 0x100; index1++ )  
    {   
        for( index2 = index1, i = 0; i < 5; i++, index2 += 0x100 )  
        {   
            unsigned long temp1, temp2;  
  
            seed = (seed * 125 + 3) % 0x2AAAAB;  
            temp1 = (seed & 0xFFFF) << 0x10;  
  
            seed = (seed * 125 + 3) % 0x2AAAAB;  
            temp2 = (seed & 0xFFFF);  
  
            cryptTable[index2] = ( temp1 | temp2 );   
       }   
   }   
}  
  
//以下函数计算lpszFileName 字符串的hash值,其中dwHashType 为hash的类型,  
//在下面GetHashTablePos函数里面调用本函数,其可以取的值为0、1、2;该函数  
//返回lpszFileName 字符串的hash值;  
unsigned long HashString( char *lpszFileName, unsigned long dwHashType )  
{   
    unsigned char *key  = (unsigned char *)lpszFileName;  
unsigned long seed1 = 0x7FED7FED;  
unsigned long seed2 = 0xEEEEEEEE;  
    int ch;  
  
    while( *key != 0 )  
    {   
        ch = toupper(*key++);  
  
        seed1 = cryptTable[(dwHashType << 8) + ch] ^ (seed1 + seed2);  
        seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;   
    }  
    return seed1;   
}  
  
//在main中测试argv[1]的三个hash值:  
//./hash  "arr/units.dat"  
//./hash  "unit/neutral/acritter.grp"  
int main( int argc, char **argv )  
{  
    unsigned long ulHashValue;  
    int i = 0;  
  
    if ( argc != 2 )  
    {  
        printf("please input two arguments/n");  
        return -1;  
    }  
  
     /*初始化数组:crytTable[0x500]*/  
     prepareCryptTable();  
  
     /*打印数组crytTable[0x500]里面的值*/  
     for ( ; i < 0x500; i++ )  
     {  
         if ( i % 10 == 0 )  
         {  
             printf("/n");  
         }  
  
         printf("%-12X", cryptTable[i] );  
     }  
  
     ulHashValue = HashString( argv[1], 0 );  
     printf("/n----%X ----/n", ulHashValue );  
  
     ulHashValue = HashString( argv[1], 1 );  
     printf("----%X ----/n", ulHashValue );  
  
     ulHashValue = HashString( argv[1], 2 );  
     printf("----%X ----/n", ulHashValue );  
  
     return 0;  
}  


================================================
FILE: ebook/code/cpp/9.2:海量数据处理之Bit-map详解.cpp
================================================
//定义每个Byte中有8个Bit位  
#include <memory.h>  
#define BYTESIZE 8  
void SetBit(char *p, int posi)  
{  
    for(int i=0; i < (posi/BYTESIZE); i++)  
    {  
        p++;  
    }  
  
    *p = *p|(0x01<<(posi%BYTESIZE));//将该Bit位赋值1  
    return;  
}  
  
void BitMapSortDemo()  
{  
    //为了简单起见,我们不考虑负数  
    int num[] = {3,5,2,10,6,12,8,14,9};  
  
    //BufferLen这个值是根据待排序的数据中最大值确定的  
    //待排序中的最大值是14,因此只需要2个Bytes(16个Bit)  
    //就可以了。  
    const int BufferLen = 2;  
    char *pBuffer = new char[BufferLen];  
  
    //要将所有的Bit位置为0,否则结果不可预知。  
    memset(pBuffer,0,BufferLen);  
    for(int i=0;i<9;i++)  
    {  
        //首先将相应Bit位上置为1  
        SetBit(pBuffer,num[i]);  
    }  
  
    //输出排序结果  
    for(int i=0;i<BufferLen;i++)//每次处理一个字节(Byte)  
    {  
        for(int j=0;j<BYTESIZE;j++)//处理该字节中的每个Bit位  
        {  
            //判断该位上是否是1,进行输出,这里的判断比较笨。  
            //首先得到该第j位的掩码(0x01<<j),将内存区中的  
            //位和此掩码作与操作。最后判断掩码是否和处理后的  
            //结果相同  
            if((*pBuffer&(0x01<<j)) == (0x01<<j))  
            {  
                printf("%d ",i*BYTESIZE + j);  
            }  
        }  
        pBuffer++;  
    }  
}  
  
int _tmain(int argc, _TCHAR* argv[])  
{  
    BitMapSortDemo();  
    return 0;  
} 


================================================
FILE: ebook/code/cpp/chapter04.cpp
================================================
#include <stdio.h>
#include <assert.h>
#include <string.h>

char *mystrcpy(char* dest, const char *src)
{
	assert(dest != NULL && src != NULL);
	assert(dest < src || strlen(src) < (unsigned int)(dest - src));
	if (src == dest)
		return dest;
	char *ret = dest;
	while('\0' != (*dest++ = *src++))
		;
	return ret;
}

int main()
{
	char dest[1024];
	char src[] = "abcdef";
	mystrcpy(dest, src);
	printf("%s\n", dest);
	return 0;
}


================================================
FILE: ebook/code/cpp/chapter06.cpp
================================================
#include <iostream>
#include <vector>

using namespace std;

void createCounter(vector<int>& counter, int n)
{
    vector<int> primes;
    counter.resize(n + 1, 0);
    counter[1] = 1;

    for(int i = 2; i <= n; i++)
    {
        if (counter[i] == 0)
        {
            counter[i] = i + 1;
            primes.push_back(i);
        }

        for(size_t j = 0; j < primes.size(); j++)
        {
            if (primes[j] * i > n)
                break;

            if (i % primes[j] == 0)
            {
                int k = i;
                int l = primes[j] * primes[j]; 

                while(k % primes[j] == 0)
                {
                    l *= primes[j];
                    k /= primes[j];
                }

                counter[primes[j] * i] = counter[k] * (l - 1) / (primes[j] - 1);
                break;
            }
            else
                counter[primes[j] * i] = counter[i] * (primes[j] + 1);
        }
    }
}

int main ()
{

    int max = 5000000;
    vector<int> counter;
    createCounter(counter, max);

    for (size_t i = 0; i < counter.size(); i++)
    {
        size_t num = counter[i] - i;
        if (num < counter.size() && num > i && counter[num] == counter[i])
            cout << i << " " << num << endl;
    }

    return 0;
}


================================================
FILE: ebook/code/cpp/makefile
================================================
CC = g++
CPPFLAGS = -Wall

FILE_SUFFIX = cpp

SRCS := $(wildcard *.$(FILE_SUFFIX))
EXES := $(patsubst %.$(FILE_SUFFIX),%,$(SRCS))

all:$(EXES)

$(EXES): % : %.$(FILE_SUFFIX)
	$(CC) $(CPPFLAGS) $< -o $@

clean:
	rm -rf $(EXES)


================================================
FILE: ebook/code/erlang/1.1:左旋转字符串.erl
================================================
%%%-----------------------------------
%%% @Module      : july_1_1
%%% @Author      : hejavac
%%% @Email       : hejavac@gmail.com
%%% @Created     : 创建日期
%%% @Description : 1.1、左旋转字符串 : 字符串旋转问题,例如abcdef 左旋2位 变成 cdefab
%%%-----------------------------------

-module(july_1_1).

-compile(export_all).

%% 启动
%% Str:字符串
%% Step:位移量
%% 返回:位移后的字符串
start(Str, Step) -> 
    shift(Str, Step).	

%% 字符串位移递归函数
%% Str:字符串
%% Step:位移量
%% 返回:位移后的字符串
shift(S, 0) ->
    S;
shift([T|S], Step) ->
    %或者是:shift(lists:concat([S, [T]]), Step-1).
    shift(S ++ [T], Step-1).

%% 测试(bcdef 左旋2位 变成 cdefab)
test() ->
    dbg:tracer(),
    dbg:p(all,[c]),
    dbg:tpl(?MODULE, [{'_', [], [{return_trace}]}]),
    start("abcdef", 2).


================================================
FILE: ebook/code/erlang/3.1:二分查找实现.erl
================================================
%%%--------------------------------------
%%% @Module  : binary_search
%%% @Author  : hejavac@gmail
%%% @Created : 2014.5.23
%%% @Description:  二分查找V0.1实现版
%%%--------------------------------------
-module(binary_search).
-compile(export_all).

%%--------------------------------------
%% @doc 二分查找算法初始化,Left初始值是1,Right是列表的长度。
-spec binary_search(L, Value) -> Pos when
      L :: list,
      Value :: integer(),
      Pos :: integer(). %%(返回0则是查找失败)
%%--------------------------------------
binary_search(L, Value) when is_list(L) ->
    Left = 1,
    Right = length(L), 
    {Mid, MidValue} = get_Mid_and_MidValue(L, Left, Right),
    binary_search(L, Mid, MidValue, Left, Right, Value);
binary_search(_L, _Value) ->
    is_not_list. 

%%  二分查找V0.1实现版
%%  首先要把握下面几个要点:
%%  right = n-1 => while(left <= right) => right = middle-1;
%%  right = n   => while(left <  right) => right = middle;
%%  middle的计算不能写在while循环外,否则无法得到更新。

%%--------------------------------------
%% @doc 二分查找算法,使用匹配递归模拟while循环。
-spec binary_search(L, Mid, MidValue, Left, Right, Value) -> Pos when
      L :: integer(),
      Mid :: integer(),
      MidValue :: integer(),
      Left :: integer(),
      Right :: integer(),
      Value :: integer(),
      Pos :: integer().%%(返回0则是查找失败)
%% @end
%%--------------------------------------
binary_search(_L, _Mid, _MidValue, Left, Right, _Value) when Left > Right ->
    0;
binary_search(L, Mid, MidValue, Left, _Right, Value) when MidValue > Value ->
    NewRight = Mid - 1,
    {NewMid, NewMidValue} = get_Mid_and_MidValue(L, Left, NewRight),
    binary_search(L, NewMid, NewMidValue, Left, NewRight, Value);
binary_search(L, Mid, MidValue, _Left, Right, Value) when MidValue < Value ->
    NewLeft = Mid + 1,
    {NewMid, NewMidValue} = get_Mid_and_MidValue(L, NewLeft, Right),
    binary_search(L, NewMid, NewMidValue, NewLeft, Right, Value);
binary_search(_L, Mid, MidValue, _Left, _Right, Value) when MidValue =:= Value ->
    Mid.

%% @doc 获取Left和Right的中间位置和中间值
get_Mid_and_MidValue(L, Left, Right) ->
    Mid = (Left + Right) div 2,
    if
        Mid =:= 0 ->
            {0, 0};
        true ->
            MidValue = lists:nth(Mid, L),
            {Mid, MidValue}
    end.


================================================
FILE: ebook/code/erlang/6.4:回文判断.erl
================================================
%%%--------------------------------------
%%% @Module  : ispalindrome
%%% @Author  : hejavac@gmail.com
%%% @Created : 2014.5.30
%%% @Description:  字符串回文
%%%--------------------------------------
-module(ispalindrome).
-export([
        ispalindrome1/1,
        ispalindrome2/1
        ]).

%%--------------------------------------
%% @doc 回文,整个列表都检查,时间复杂度是2N=N+N,其中reverse函数时间复杂度是N,ispalindrome函数复杂度是N
-spec ispalindrome1(L) -> R when
        L  :: list(),
        R  :: boolean().  
%%--------------------------------------
ispalindrome1(L) when is_list(L) ->
    ispalindrome(L, lists:reverse(L)).

%%--------------------------------------
%% @doc 回文,只检查半个列表,这里时间复杂度是3.5N=N+N/2+N+N/2+N/2,其中length是N,reverse函数是N, 
%%      sublist函数是N/2,ispalindrome函数复杂度是N/2
-spec ispalindrome2(L) -> R when
        L  :: list(),
        R  :: boolean().  
%%--------------------------------------
ispalindrome2(L) when is_list(L) ->
    Half = length(L) div 2,
    L1 = lists:sublist(L, Half),
    L2 = lists:sublist(lists:reverse(L), Half),
    ispalindrome(L1, L2).

%%--------------------------------------
%% @doc 回文检查,输入如[1,2,3,4,]
-spec ispalindrome(L1, L2) -> R when
        L1 :: [T],
        L2 :: [T],
        R :: boolean(),     %% 是否回文
        T  :: term().   
%%--------------------------------------
ispalindrome([], []) ->
    true;
ispalindrome([E|L1], [E|L2]) ->
    ispalindrome(L1, L2);
ispalindrome(_, _) ->
    false.
   
%%--------------------------------------
%% @doc lists:reverse、lists:nth、sublist源码
%%--------------------------------------
reverse([] = L) ->
    L;
reverse([_] = L) ->
    L;
reverse([A, B]) ->
    [B, A];
reverse([A, B | L]) ->
    lists:reverse(L, [B, A]).

nth(1, [H|_]) -> H;
nth(N, [_|T]) when N > 1 ->
    nth(N - 1, T).

sublist(List, L) when is_integer(L), is_list(List) ->
    sublist_2(List, L).
 
sublist_2([H|T], L) when L > 0 ->
    [H|sublist_2(T, L-1)];
sublist_2(_, 0) ->
    [];
sublist_2(List, L) when is_list(List), L > 0 ->
    [].


================================================
FILE: ebook/code/go/1.1-左旋转字符串.go
================================================
//1.1 左旋转字符串
//@author leiyonglin <leiyonglin@gmail.com>
//http://play.golang.org/p/SxiFC1eRsE

package main

import (
	"fmt"
)

//解法一: 暴力移位法
//左移一位
func left_shift_one(s []byte, n int) {
	if n == 0 {
		return
	}

	t := s[0]
	for i := 1; i < n; i++ {
		s[i-1] = s[i]
	}
	s[n-1] = t
}

//左移m位
func left_shift_m(s []byte, n int, m int) {
	m %= n

	for m > 0 {
		left_shift_one(s, n)
		m--
	}
}

//解法二:三步反转法
func reverse(s []byte, from int, to int) {
	for from < to {
		t := s[from]
		s[from] = s[to]
		s[to] = t
		from++
		to--
	}
}

func leftshift(s []byte, n int, m int) {
	m %= n
	reverse(s, 0, m-1)
	reverse(s, m, n-1)
	reverse(s, 0, n-1)
}

func main() {
	s := []byte("abcdef")
	n := len(s)
	m := 8

	left_shift_m(s, n, m)
	fmt.Println(string(s))

	leftshift(s, n, m)
	fmt.Println(string(s))
}


================================================
FILE: ebook/code/go/1.2-字符串是否包含问题.go
================================================
//1.2 字符串是否包含问题
//@author leiyonglin <leiyonglin@gmail.com>
//http://play.golang.org/p/sO4hYrRtYT

package main

import (
	"fmt"
	"sort"
	"strings"
)

//方法一: 暴力轮询
func compare1(a string, b string) bool {
	la := len(a)
	lb := len(b)
	for i := 0; i < lb; i++ {
		for j := 0; j < la; j++ {
			if b[i] == a[j] {
				break
			}
			if j >= la-1 {
				return false
			}
		}
	}

	return true
}

//方法二:普通排序
func compare2(a string, b string) bool {
	as := sortString(a)
	bs := sortString(b)
	la := len(as)
	lb := len(bs)
	pa := 0
	pb := 0
	for pb < lb {
		for pa < la && as[pa] < bs[pb] {
			pa++
		}
		if pa >= la || as[pa] > bs[pb] {
			return false
		}
		pb++
	}

	return true
}

func sortString(w string) string {
	s := strings.Split(w, "")
	sort.Strings(s)
	return strings.Join(s, "")
}

//方法三:记数比较
func compare3(a string, b string) bool {
	var have [26]int = [26]int{}
	ab := []byte(a)
	bb := []byte(b)
	la := len(a)
	lb := len(b)

	//A ASCII code is 65
	for i := 0; i < la; i++ {
		have[ab[i]-65] = 1
	}

	for i := 0; i < lb; i++ {
		if have[bb[i]-65] == 0 {
			return false
		}
	}

	return true
}

//方法四: 巧用hashtable
func compare4(a string, b string) bool {
	var hash [26]int = [26]int{}
	var m int = 0
	ab := []byte(a)
	bb := []byte(b)
	la := len(a)
	lb := len(b)

	for i := 0; i < lb; i++ {
		x := bb[i] - 65
		if hash[x] == 0 {
			hash[x] = 1
			m++
		}
	}

	for i := 0; i < la && m > 0; i++ {
		x := ab[i] - 65
		if hash[x] == 1 {
			hash[x] = 0
			m--
		}
	}

	return m == 0
}

//解法五:素数相乘
func compare5(a string, b string) bool {
	return true
}

//解法六:位运算
func compare6(a string, b string) bool {
	hash := 0
	ab := []byte(a)
	bb := []byte(b)
	la := len(a)
	lb := len(b)

	for i := 0; i < la; i++ {
		hash |= (1 << (ab[i] - 65))
	}
	for i := 0; i < lb; i++ {
		if (hash & (1 << (bb[i] - 65))) == 0 {
			return false
		}
	}

	return true
}

func main() {
	//true
	a := "ABCDEFGHLMNOPQRS"
	b := "DCGSRQPO"

	fmt.Println("字符串a:", a)
	fmt.Println("字符串b:", b)

	fmt.Println("compare1 - a包含b:", compare1(a, b))
	fmt.Println("compare2 - a包含b:", compare2(a, b))
	fmt.Println("compare3 - a包含b:", compare3(a, b))
	fmt.Println("compare4 - a包含b:", compare4(a, b))
	fmt.Println("compare6 - a包含b:", compare6(a, b))

	//false
	a = "ABCDEFGHLMNOPQRS"
	b = "DCGSRQPOZ"

	fmt.Println("字符串a:", a)
	fmt.Println("字符串b:", b)

	fmt.Println("compare1 - a包含b:", compare1(a, b))
	fmt.Println("compare2 - a包含b:", compare2(a, b))
	fmt.Println("compare3 - a包含b:", compare3(a, b))
	fmt.Println("compare4 - a包含b:", compare4(a, b))
	fmt.Println("compare6 - a包含b:", compare6(a, b))
}


================================================
FILE: ebook/code/go/1.5-回文判断.go
================================================
//1.5 回文判断
//@author leiyonglin <leiyonglin@gmail.com>
//http://play.golang.org/p/K4NyYq-Teo
package main

import (
	"fmt"
)

//解法一
func isPalindrome(s string) bool {
	l := len(s)
	if l < 1 {
		return false
	}

	left := 0
	right := l - 1
	for left < right {
		if s[left] != s[right] {
			return false
		}
		left++
		right--
	}

	return true
}

//解法二
func isPalindrome2(s string) bool {
	l := len(s)
	if l < 1 {
		return false
	}

	m := l / 2
	left := m - 1
	right := m + l%2

	for left >= 0 {
		if s[left] != s[right] {
			return false
		}
		left--
		right++
	}

	return true
}

func main() {
	s := "madam"

	fmt.Printf("字符串%s是否为回文:%v \n", s, isPalindrome(s))
	fmt.Printf("字符串%s是否为回文:%v \n", s, isPalindrome2(s))

	s = "david"

	fmt.Printf("字符串%s是否为回文:%v \n", s, isPalindrome(s))
	fmt.Printf("字符串%s是否为回文:%v \n", s, isPalindrome2(s))
}


================================================
FILE: ebook/code/go/2.1-寻找最小的k个数.go
================================================
//2.1 寻找最小的k个数
//@author leiyonglin <leiyonglin@gmail.com>
//http://play.golang.org/p/41xfLFuTYq

package main

import (
	"fmt"
)

func quicksort(seq []int) []int {
	l := len(seq)
	if l <= 1 {
		return seq
	}
	s := seq[0]
	left := []int{}
	right := []int{}

	for i := 1; i < l; i++ {
		if seq[i] <= s {
			left = append(left, seq[i])
		} else {
			right = append(right, seq[i])
		}
	}
	left = quicksort(left)
	right = quicksort(right)

	seq = append(left, s)
	seq = append(seq, right...)

	return seq
}

func max(seq []int) int {
	l := len(seq)
	if l == 0 {
		//ERROR
		return 0
	}
	if l == 1 {
		return seq[0]
	}

	m := 0
	for i := 1; i < l; i++ {
		if seq[i] > seq[m] {
			m = i
		}
	}

	return m
}

func bInsert(seq []int, k int) []int {
	l := len(seq)
	left := 0
	right := l - 1
	for left <= right {
		m := (left + right) / 2
		if seq[m] > k {
			right = m - 1
		} else {
			left = m + 1
		}
	}
	w := []int{}

	w = append(w, seq[:left]...)
	w = append(w, k)
	w = append(w, seq[left:l-1]...)

	return w
}

//解法一
func sort1(seq []int, k int) []int {
	if len(seq) <= k {
		return seq
	}
	s := quicksort(seq)
	return s[:k]
}

//解法二
func sort2(seq []int, k int) []int {
	l := len(seq)
	if l <= k {
		return seq
	}

	ks := make([]int, k)
	copy(ks, seq[:k])
	m := max(ks)

	for i := k; i < l; i++ {
		if seq[i] < ks[m] {
			ks[m] = seq[i]
			m = max(ks)
		}
	}

	return ks
}

//解法三
func sort3(seq []int, k int) []int {
	l := len(seq)
	if l <= k {
		return seq
	}

	ks := make([]int, k)
	copy(ks, seq[:k])
	ks = quicksort(ks)

	for i := k; i < l; i++ {
		if seq[i] < ks[k-1] {
			ks = bInsert(ks, seq[i])
		}
	}

	return ks
}

func main() {
	seq := []int{1, 5, 6, 3, 4, 5, 8, 4, 1, 7}
	k := 4
	fmt.Println("原字符串:", seq)

	fmt.Println("sort1:", sort1(seq, k))
	fmt.Println("sort2:", sort2(seq, k))
	fmt.Println("sort3:", sort3(seq, k))

}


================================================
FILE: ebook/code/go/2.2-求数组中给定下标区间内的第K小元素.go
================================================
//2.2 求数组中给定下标区间内的第K小元素
//@author leiyonglin <leiyonglin@gmail.com>
//http://play.golang.org/p/eGkDSKGnhq

package main

import (
	"fmt"
	"sort"
)

type Node struct {
	Num  int
	Data int
}

type SortNodeByData []Node

func (a SortNodeByData) Len() int {
	return len(a)
}
func (a SortNodeByData) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}
func (a SortNodeByData) Less(i, j int) bool {
	return a[i].Data < a[j].Data
}

//伴随数组解法
func find1(arr []int, a int, b int, flag int) int {
	i := 0
	p := []Node{}

	for k, v := range arr {
		node := Node{Data: v, Num: k}
		p = append(p, node)
	}

	sort.Sort(SortNodeByData(p))

	for i, _ = range p {
		if p[i].Num >= a && p[i].Num <= b {
			flag--
		}
		if flag == 0 {
			break
		}
	}

	return p[i].Data
}

func main() {

	arr := []int{5, 7, 1, 2, 9, 4, 6, 3, 80}
	a := 2
	b := 6
	flag := 4

	fmt.Println("原数组", arr)
	fmt.Printf("查找%v-%v第%v小的数\n", a, b, flag)

	fmt.Println(find1(arr, a, b, flag))
}


================================================
FILE: ebook/code/go/3.2-杨氏矩阵查找.go
================================================
// 3.2 杨氏矩阵查找
// @author leiyonglin <leiyonglin@gmail.com>
// http://play.golang.org/p/EcFyPADISb

package main

import (
	"fmt"
)

//解法二:定位法
func find2(arr [][]int, s int) bool {
	n := len(arr)
	if n == 0 {
		return false
	}
	m := len(arr[0])
	if m == 0 {
		return false
	}

	x := m - 1
	y := 0

	for x >= 0 && y < n {
		if arr[y][x] > s {
			x--
		} else if arr[y][x] < s {
			y++
		} else {
			return true
		}

	}
	return false
}

func main() {
	arr := [][]int{
		[]int{1, 2, 8, 9},
		[]int{2, 4, 9, 12},
		[]int{4, 7, 10, 13},
		[]int{6, 8, 11, 15},
	}

	fmt.Println("数组:", arr)

	s := 10
	fmt.Printf("%d 是否在数组中: %t \n", s, find2(arr, s))

	s = 16
	fmt.Printf("%d 是否在数组中: %t \n", s, find2(arr, s))

}


================================================
FILE: ebook/code/go/3.3:出现次数超过一半的数字.go
================================================
package main

import (
	"fmt"

//	"math"
)

func findNumberAppearEqualHalf(data []int) int {
	var (
		c1 = findNumberAppearMoreThanHalf(data)
		c2 = data[len(data)-1]
		n  = 0
	)
	for _, c := range data {
		if c1 == c {
			n++
		}
	}

	if n == len(data)/2 {
		return c1
	} else {
		return c2
	}
}

func findNumberAppearMoreThanHalf(data []int) int {
	var (
		candidate int
		nTimes    int = 0
	)

	for i := 0; i < len(data); i++ {
		switch {
		case nTimes == 0:
			candidate = data[i]
			nTimes = 1
		case candidate == data[i]:
			nTimes++
		default:
			nTimes--
		}
	}
	return candidate
}

func main() {
	a := []int{3, 5, 7, 5, 15, 5}
	fmt.Printf("%d\n", findNumberAppearMoreThanHalf(a))
	fmt.Printf("%d\n", findNumberAppearEqualHalf(a))
}


================================================
FILE: ebook/code/java/chapter1/1.1:左旋转字符串.java
================================================
package org.yousharp.julycoding.string;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yousharp.common.ListNode;

/**
 * 1.1 旋转字符串
 * (github链接:https://github.com/julycoding/The-Art-Of-Programming-By-July/blob/master/ebook/zh/01.01.md)
 *
 * Created by lingguo on 14-6-26.
 */
public class RotateString {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 问题描述:
     *  给定一个字符串,要求把字符串前面的若干个字符移动到字符串的尾部,如把字符串“abcdef”前面的2个字符'a'和'b'移动到字符串
     *  的尾部,使得原字符串变成字符串“cdefab”。请写一个函数完成此功能,要求对长度为n的字符串操作的时间复杂度为 O(n),空间
     *  复杂度为 O(1)。
     *
     * 思路:
     *  三步旋转法:(X^TY^T)^T=YX
     *
     * @param str   输入串
     * @param n     前n个字符移到串的最后
     * @return      翻转后的串
     */
     public static char[] leftRotateString(char[] str, int n) {
         char[] rotateLeft = rotate(str, 0, n - 1);
         char[] rotateRight = rotate(rotateLeft, n, str.length - 1);
         char[] result = rotate(rotateRight, 0, str.length - 1);
         return result;
     }

    /**
     * 将字符串翻转
     *
     * @param str       输入串
     * @param start     字符串中的起始索引(包括)
     * @param end       字符串中的终止索引(包括)
     * @return          翻转后的串
     */
    private static char[] rotate(char[] str, int start, int end) {
        while (start < end) {
            char tmp = str[start];
            str[start] = str[end];
            str[end] = tmp;
            start++;
            end--;
        }
        return str;
    }
/*********************************************************************************************************/


    /**
     * 问题描述:
     *  链表翻转。给出一个链表和一个数k,比如,链表为1→2→3→4→5→6,k=2,则翻转后2→1→6→5→4→3,若k=3,翻转后
     *  3→2→1→6→5→4,若k=4,翻转后4→3→2→1→6→5,用程序实现。
     *
     * 思路:
     *  使用反转链表的思路,将链表的前部分反转,然后将链表的后部分反转,最后将前部分链表的尾节点指向后部分链表的头节点。
     *
     * @param head  链表的头节点
     * @param n     将前n个节点反转,剩下的节点反转
     * @return      翻转后链表的头节点
     */
    public static ListNode rotateLinkList(ListNode head, int n) {
        ListNode leftEnd = head;
        int i = 0;
        while (i++ < n) {
            leftEnd = leftEnd.next;     // 左链表的终点
        }
        ListNode leftRotateStart = rotateList(head, leftEnd);       // 左部分反转
        ListNode rightRotateStart = rotateList(leftEnd, null);      // 右部分反转
        head.next = rightRotateStart;                               // 左右部分连接起来
        return leftRotateStart;
    }

    /**
     * 将链表从起点start(inclusive)到终点end(exclusive)的节点反转
     *
     * @param start     链表的起点(包括)
     * @param end       链表的终点(不包括)
     * @return          反转后链表的头节点
     */
    private static ListNode rotateList(ListNode start, ListNode end) {
        ListNode pre = null;
        ListNode cur = start;
        ListNode next = cur.next;
        while (cur != end) {
            next = cur.next;
            cur.next = pre;
            pre = cur;
            cur = next;
        }
        return pre;
    }

    /**
     * 问题描述:
     *  编写程序,在原字符串中把字符串尾部的m个字符移动到字符串的头部,要求:长度为n的字符串操作时间复杂度为O(n),空间复杂度
     *  为O(1)。 例如,原字符串为”Ilovebaofeng”,m=7,输出结果为:”baofengIlove”。
     *
     * 思路:
     *  与左旋转字符串的思路是一样的;
     *
     * @param str       输入串
     * @param n         将最后n个字符移到串的最前面
     * @return          翻转后的串
     */
    public static char[] rightRotateString(char[] str, int n) {
        rotate(str, 0, str.length - n - 1);
        rotate(str, str.length - n, str.length - 1);
        char[] result = rotate(str, 0, str.length - 1);
        return result;
    }
/**********************************************************************************************************/

    /**
     * 问题描述:
     *  单词翻转。输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变,句子中单词以空格符隔开。为简单起见,标点符
     *  号和普通字母一样处理。例如,输入“I am a student.”,则输出“student. a am I”。
     *
     * 思路:
     *  先将每个单词反转,然后将整个句子反转;
     *
     * @param sentence      输入的句子
     * @return              翻转后的句子
     */
    public static char[] rotateSentence(char[] sentence) {
        int start = 0;
        int end = 0;
        int i = 0;
        while (i < sentence.length) {
            // 空格是单词的分隔符
            while (i < sentence.length && sentence[i] != ' ') {
                i++;
            }
            end = i - 1;
            sentence = rotate(sentence, start, end);        // 旋转一个单词
            start = (++i);
        }
        sentence = rotate(sentence, 0, sentence.length - 1);    // 翻转整个句子
        return sentence;
    }
/*********************************************************************************************/

}


================================================
FILE: ebook/code/java/chapter1/1.2:字符串包含.java
================================================
package org.yousharp.julycoding.string;

/**
 * 1.2 字符串包含
 * (july github链接:https://github.com/julycoding/The-Art-Of-Programming-By-July/blob/master/ebook/zh/01.02.md)
 *
 * User: lingguo
 * Date: 14-6-29
 */
public class StringContain {

    /**
     *  * 问题描述:
     *  给定两个分别由字母组成的字符串A和字符串B,字符串B的长度比字符串A短。请问,如何最快地判断字符串B
     *  中所有字母是否都在字符串A里?为了简单起见,我们规定输入的字符串只包含大写英文字母。比如String A:ABCD,String B:BAD,
     *  返回true;string A:ABCD,string B:BCE,返回false;String A:ABCD,String B:AA,返回true。
     *
     * 思路:
     *  思路一:遍历字符串B,判断每一个字符是否出现在字符串A中,时间复杂度O(n*m),空间复杂度O(1);
     *  思路二:先对两个字符串排序,然后同时遍历字符串A和B,判断B中的每一个字符是否都在字符串A中。时间复杂度O(nlogn),空间复杂度O(1);
     *  思路三:将每一个字符映射到一个素数上,对字符串A中的每一个字符表示的素数,求累积;然后遍历字符串B,用每一个字符表示的素
     *  数去除字符串A的累积,判断余数是否为0。时间复杂度:O(n),空间复杂度O(1)。可能存在的问题:乘积时可能会溢出。
     *  思路四:如果可以使用Java中的数据结构,HashMap和Set可以很方便地解决问题;如果不能,我们可以构造一个“签名”,将每一个字
     *  符映射为整数(范围:0到26),然后遍历A中的每一个字符,将32位整数的对应位置1(整数初始为0),最后遍历B中的每一个字符,判断
     *  每一个字符代表的整数在整数中是否已置位。时间复杂度O(n),空间复杂度O(1),思路四为最优算法。
     *
     *  这里仅给出思路四的示例代码。
     *
     * @param s1
     * @param s2
     * @return
     */
    public static boolean hashCheck(char[] s1, char[] s2) {
        int mask = 0;
        for (char c: s1) {
            mask = mask | (1 << (c - 'A'));
        }
        for (char c: s2) {
            if ((mask & (1 << (c - 'A'))) == 0) {
                return false;
            }
        }
        return true;
    }
}


================================================
FILE: ebook/code/java/chapter1/Chapter1.java
================================================
class Chapter1 {
    
    // Version 1
    public void leftShiftV1 (char[] s, int m) {
        while (m > 0) {
            leftShiftOne(s);
            m--;
        }
    }

    private void leftShiftOne (char[] s) {
        int len = s.length;
        int i = 0;
        char c = s[0];
        while (i < len - 1) {
            s[i] = s[i + 1];
            i++;
        }
        s[len - 1] = c;
    }


    // Version2
    public void leftShiftV2(char[] s, int m) {
        int len = s.length;
        m = m % len;
        reverse(s, 0, m - 1);
        reverse(s, m, len - 1);
        reverse(s, 0, len - 1);
    }

    private void reverse (char[] s, int from, int to) {
        while(from < to) {
            char c = s[from];
            s[from] = s[to];
            s[to] = c;
            from++;
            to--;
        }
    }

    public static void main (String[] args) {
        Chapter1 chapter1 = new Chapter1();
        
        String str = "asdfghjkl";
        System.out.println("Original String:");
        System.out.println(str);
        char[] arr1 = str.toCharArray();
        char[] arr2 = str.toCharArray();

        chapter1.leftShiftV1(arr1, 2);
        chapter1.leftShiftV2(arr2, 2);
        
        System.out.println("Left shift V1:");
        System.out.println(new String(arr1));
        System.out.println("left Shift V2:");
        System.out.println(new String(arr2));
    }
}


================================================
FILE: ebook/code/java/chapter1/Palindrome.java
================================================
/**
 * Check weather a string is a palindrome
 * @author WangTaoTheTonic
 */
public class Palindrome
{
	// Solution 1, from sides to middle
	public static boolean isPalindromeV1(String str)
	{
		if(null == str || 0 == str.length())
		{
			return false;
		}
		
		int length = str.length();
		if(1 == length)
		{
			return true;
		}
		
		for(int leftFlag = 0, rightFlag = length - 1 ; leftFlag < rightFlag; leftFlag ++, rightFlag --)
		{
			if(str.charAt(leftFlag) != str.charAt(rightFlag))
				return false;
		}
		
		return true;
	}
	
	// Solution 2, from middle to sides
	public static boolean isPalindromeV2(String str)
	{
		if(null == str || 0 == str.length())
		{
			return false;
		}
		
		int length = str.length();
		if(1 == length)
		{
			return true;
		}
		
		int leftFlag = 0;
		int rightFlag = length;
		leftFlag = length / 2 - 1;
		if(0 == length % 2)
		{
			rightFlag = leftFlag + 1;
		}
		else
		{
			rightFlag = leftFlag + 2;
		}
		
		for( ; leftFlag >= 0; leftFlag --, rightFlag ++)
		{
			if(str.charAt(leftFlag) != str.charAt(rightFlag))
				return false;
		}
		
		return true;
	}

}


================================================
FILE: ebook/code/java/chapter1/StringToInt
================================================
/**
 * 将String类型转为Integer类型
 * 
 * @author gongyu.wang
 * 
 */
public class Solution {
    	private static int radis = 10;

	/**
	 * 将STRING类型转化为int类型,有如下几个步骤 
	 * 1、判断正负 
	 * 2、判断非整数 
	 * 3、“321” 转为 321 可以看做是 3*100 + 2*10 + 1 这等于是每次循环时,都对前几位数字*10再累加
	 * 4、判断是否超出int的最大值范围(-2^31~2^31-1)
	 *    判断是否超过最大值范围 不能直接拿值和Integer的max比较, 因为可能会发生溢出  应该使用 max/10来比较
	 */
	public int atoi(String str)  {
       
        	if(str==null || "".equals(str)){
        	    return 0;
        	}
        	String s = str.trim();
		int result = 0;
		boolean negative = false;
		int i = 0, len = s.length();
		int limit = -Integer.MAX_VALUE;
		int multmin;
		int digit;
    		try{
    
	    		if(len>0){
	    			char firstChar = s.charAt(0);
	                if (firstChar < '0') { // Possible leading "+" or "-"
	                    if (firstChar == '-') {
	                        negative = true;
	                        limit = Integer.MIN_VALUE;
	                    } else if (firstChar != '+')
	                    	throw new Exception("char Exception");
	    
	                    if (len == 1) // Cannot have lone "+" or "-"
	                    	throw new Exception("char Exception");
	                    i++;
	                }
	                multmin = limit / radis;
	                
	                while(i<len){ 
	                    digit = Character.digit(s.charAt(i++),radis);
	                    if (digit < 0) {
	                		return negative ? result : -result;
	                    }
	                    if (result < multmin) {
	                    	if(negative){
	    	        			return Integer.MIN_VALUE;
	    	        		}else{
	    	        			return Integer.MAX_VALUE;
	    	        		}
	                    }
	                	result = result * radis;
	    	        	if (result < limit + digit) {
	    	        		if(negative){
	    	        			return Integer.MIN_VALUE;
	    	        		}else{
	    	        			return Integer.MAX_VALUE;
	    	        		}
	    	        		
	    	            }
	                	result -= digit;
	                 }
	    		}
    	
        	} catch (Exception e) {
			e.printStackTrace();
		}
		return negative ? result : -result;
    }

}


================================================
FILE: ebook/code/java/chapter2/Chapter2.java
================================================
class Chapter2 {
    public static void main (String[] args) {
        System.out.println("QuickSort and Compare:");
        ICompare sortAndCompare = new SortAndCompare();
        System.out.println(sortAndCompare.compare("ABCDEFGHLMNOPQRS", "DCGSRQPOM"));
        System.out.println(sortAndCompare.compare("ASDF", "GHJK"));
    
        System.out.println("Counting Sort and Compare:");
        ICompare countAndCompare = new CountAndCompare();
        System.out.println(countAndCompare.compare("ABCDEFGHLMNOPQRS", "DCGSRQPOM"));
        System.out.println(countAndCompare.compare("ASDF", "GHJK"));

        System.out.println("Using HashTable:");
        ICompare hashTableCompare = new HashTableCompare();
        System.out.println(hashTableCompare.compare("ABCDEFGHLMNOPQRS", "DCGSRQPOM"));
        System.out.println(hashTableCompare.compare("ASDF", "GHJK"));
       
        System.out.println("Using Prime Product and Mode:");
        ICompare primeCompare = new PrimeCompare();
        System.out.println(primeCompare.compare("ABCDEFGHLMNOPQRS", "DCGSRQPOM"));
        System.out.println(primeCompare.compare("ASDF", "GHJK"));
       
    }
}


================================================
FILE: ebook/code/java/chapter2/CountAndCompare.java
================================================
class CountAndCompare implements ICompare {
    @Override
    public boolean compare(String longString, String shortString) {
        int posLong = 0, posShort = 0;
        longString = countSort(longString);
        shortString = countSort(shortString);
        while (posLong < longString.length() && posShort < shortString.length()) {
            while (posLong < longString.length() && longString.charAt(posLong) < shortString.charAt(posShort)) {
                posLong++;
            }

            if (posLong >= longString.length() || longString.charAt(posLong) != shortString.charAt(posShort)) {
                return false;
            } else {
                posShort++;
            }
        }
        return posShort == shortString.length();
    }

    private String countSort(String str) {
        int[] help = new int[26];
        for (int i = 0; i < str.length(); i++) {
            int index = str.charAt(i) - 'A';
            help[index]++;
        }
        StringBuilder buf = new StringBuilder();
        for (int i = 0; i < 26; i++) {
           for (int j = 0; j < help[i]; j++) {
               buf.append((char)(i + (int)'A'));
           } 
        }
        return buf.toString();
    }


}


================================================
FILE: ebook/code/java/chapter2/HashTableCompare.java
================================================
class HashTableCompare implements ICompare {
    @Override
    public boolean compare(String longString, String shortString) {
        int[] hash = new int[26];
        
        int num = 0;

        for (int j = 0; j < shortString.length(); j++) {
            int index = shortString.charAt(j) - 'A';
            if (hash[index] == 0) {
                num++;
            }
            hash[index]++;
        }

        for (int k = 0; k < longString.length(); k++) {
            int index = longString.charAt(k) - 'A';
            hash[index]--;
            if (hash[index] == 0) {
               num--;
               if (num == 0) {
                    break;
               }
            }
        }

        return num == 0;
    }    

}


================================================
FILE: ebook/code/java/chapter2/ICompare.java
================================================
interface ICompare {
    public boolean compare(String longStr, String shortStr);
}


================================================
FILE: ebook/code/java/chapter2/PrimeCompare.java
================================================
import java.math.BigInteger;

class PrimeCompare implements ICompare {
    
    @Override
    public boolean compare(String longString, String shortString) {
        BigInteger product = new BigInteger("1");

        for (int i = 0; i < longString.length(); i++) {
            int index = longString.charAt(i) - 'A';
            product = product.multiply(BigInteger.valueOf(primeTable[index]));
        }
        
        for (int j = 0; j < shortString.length(); j++) {
            int index = shortString.charAt(j) - 'A';
            BigInteger prime = BigInteger.valueOf(primeTable[index]);
            if (!(product.mod(prime).equals(BigInteger.ZERO))) {
                return false;
            } 
        }
        return true;
    }

    private long[] primeTable = new long[]{ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101};
}


================================================
FILE: ebook/code/java/chapter2/SortAndCompare.java
================================================
import java.util.Arrays;

class SortAndCompare implements ICompare {
    @Override
    public boolean compare(String longString, String shortString) {
        char[] longStr = longString.toCharArray();
        char[] shortStr = shortString.toCharArray();
        Arrays.sort(longStr);
        Arrays.sort(shortStr);

        int posShort = 0, posLong = 0;
        while (posShort < shortStr.length && posLong < longStr.length) {
            while (posLong < longStr.length && longStr[posLong] < shortStr[posShort]) {
                posLong++;
            }

            if (posLong == longStr.length || longStr[posLong] != shortStr[posShort]) {
                break;
            }
            
            posShort++;
        }
        return posShort == shortStr.length;
    }
}


================================================
FILE: ebook/code/java/chapter2/TopK.java
================================================
import java.util.Collections;
import java.util.List;

/**
 * Select the K least numbers in a List
 * @author WangTaoTheTonic
 *
 */
public class TopK
{
	// version 1, pick the 0 to k element of the List quick sorted.
	public static List<Integer> topKV1(List<Integer> list, int k)
	{
		if(null == list || k > list.size())
			return null;
		if(k == list.size())
			return list;
		// self defined quickSort algorithm.
		quickSort(list, 0, list.size() - 1);
		// Collections.sort(List<T>) is a modified merge sort algorithm, which can be used here instead. 
		// Collections.sort(list);
		return list.subList(0, k);
	}
	
	// version 2, exchange the k least element to the front of List 
	public static List<Integer> topKV2(List<Integer> list, int k)
	{
		if(null == list || k > list.size())
			return null;
		int length = list.size();
		if(k == length)
			return list;
		int numI = 0;
		int numJ = 0;
		int temp = 0;
		for(int i = 0; i < k; i ++)
		{
			numI = list.get(i);
			for(int j = i + 1; j < length; j ++)
			{
				numJ = list.get(j);
				if(numJ < numI)
				{
					temp = numI;
					list.set(i, numJ);
					list.set(j, temp);
					numI = list.get(i);
				}
			}
		}
	
Download .txt
gitextract_a78wrx3g/

├── .gitignore
├── Readme.md
└── ebook/
    ├── build/
    │   ├── Makefile
    │   ├── README.md
    │   ├── book.json
    │   ├── metadata.yaml
    │   └── style.css
    ├── code/
    │   ├── c/
    │   │   ├── 1.1:左旋转字符串.c
    │   │   ├── 1.2:字符串是否包含问题.c
    │   │   ├── 1.3:带通配符的字符串匹配问题.c
    │   │   ├── 1.4:字符串转换成整数.c
    │   │   ├── 1.7:字符串的全排列.c
    │   │   ├── 10.1.3:教你一步一步用c语言实现sift算法、下.c
    │   │   ├── 2.1:寻找最小的 k 个数.c
    │   │   ├── 2.2:求给定区间的第K小元素.c
    │   │   ├── 2.3:求解500万以内的亲和数.c
    │   │   ├── 2.4:寻找和为定值的两个数.c
    │   │   ├── 2.5:寻找和为定值的多个数.c
    │   │   ├── 2.6:求连续子数组的最大和.c
    │   │   ├── 2.7:奇偶排序.c
    │   │   ├── 2.7:荷兰国旗问题.c
    │   │   ├── 2.8:矩阵相乘之Strassen算法.c
    │   │   ├── 3.1:二分查找实现.c
    │   │   ├── 3.2:杨氏矩阵查找.c
    │   │   ├── 4.1:木块砌墙.c
    │   │   ├── 4.2:格子取数问题.c
    │   │   ├── 4.3:出现次数超过一半的数字.c
    │   │   ├── 4.3:完美洗牌算法.c
    │   │   ├── 4.4:最近公共祖先LCA问题.LCAProblem.c
    │   │   ├── 4.5:打印螺旋矩阵.SpiralMatrix.c
    │   │   ├── 5.1:最长公共子序列(LCS)问题.c
    │   │   ├── 5.2:最大连续乘积子串.c
    │   │   ├── 5.3:字符串编辑距离.c
    │   │   ├── 5.4:交替字符串.c
    │   │   ├── 6.11:最小操作数.c
    │   │   ├── 6.4:回文判断.c
    │   │   ├── 6.6:跳台阶问题.c
    │   │   ├── 6.8:第一个只出现一次的字符.c
    │   │   ├── 6.9:Trie树.c
    │   │   ├── 7.1:搜索引擎热门查询统计.c
    │   │   ├── 7.2:最短摘要的生成.c
    │   │   ├── 7.3:倒排索引关键词不重复Hash编码.c
    │   │   ├── 7.4:倒排索引关键词 Hash 不重复编码实践.c
    │   │   └── makefile
    │   ├── cpp/
    │   │   ├── 1.1:左旋转字符串.cpp
    │   │   ├── 2.1:寻找最小的 k 个数.cpp
    │   │   ├── 3.1:二分查找实现(Jon Bentley
    │   │   ├── 4.2:完美洗牌算法.cpp
    │   │   ├── 7.4:倒排索引关键词 Hash 不重复编码实践.cpp
    │   │   ├── 9.2:海量数据处理之Bit-map详解.cpp
    │   │   ├── chapter04.cpp
    │   │   ├── chapter06.cpp
    │   │   └── makefile
    │   ├── erlang/
    │   │   ├── 1.1:左旋转字符串.erl
    │   │   ├── 3.1:二分查找实现.erl
    │   │   └── 6.4:回文判断.erl
    │   ├── go/
    │   │   ├── 1.1-左旋转字符串.go
    │   │   ├── 1.2-字符串是否包含问题.go
    │   │   ├── 1.5-回文判断.go
    │   │   ├── 2.1-寻找最小的k个数.go
    │   │   ├── 2.2-求数组中给定下标区间内的第K小元素.go
    │   │   ├── 3.2-杨氏矩阵查找.go
    │   │   └── 3.3:出现次数超过一半的数字.go
    │   ├── java/
    │   │   ├── chapter1/
    │   │   │   ├── 1.1:左旋转字符串.java
    │   │   │   ├── 1.2:字符串包含.java
    │   │   │   ├── Chapter1.java
    │   │   │   ├── Palindrome.java
    │   │   │   └── StringToInt
    │   │   ├── chapter2/
    │   │   │   ├── Chapter2.java
    │   │   │   ├── CountAndCompare.java
    │   │   │   ├── HashTableCompare.java
    │   │   │   ├── ICompare.java
    │   │   │   ├── PrimeCompare.java
    │   │   │   ├── SortAndCompare.java
    │   │   │   └── TopK.java
    │   │   ├── chapter3/
    │   │   │   ├── Chapter3.java
    │   │   │   ├── HeapSolution.java
    │   │   │   ├── IFindMinK.java
    │   │   │   └── MaxHeap.java
    │   │   ├── chapter4/
    │   │   │   └── Chapter4.java
    │   │   └── chapter6/
    │   │       └── Chapter6.java
    │   ├── js/
    │   │   ├── 1.1:左旋转字符串/
    │   │   │   ├── 1.1:左旋转字符串.js
    │   │   │   ├── test.html
    │   │   │   └── tests.js
    │   │   ├── 1.2:字符串是否包含问题/
    │   │   │   ├── 1.2:字符串是否包含问题.js
    │   │   │   ├── test.html
    │   │   │   └── tests.js
    │   │   └── 2.4:寻找和为定值的两个数/
    │   │       ├── 2.4:寻找和为定值的两个数.js
    │   │       ├── test.html
    │   │       └── tests.js
    │   ├── php/
    │   │   ├── chapter1.php
    │   │   ├── chapter2.php
    │   │   └── chapter3.php
    │   ├── python/
    │   │   ├── 1.1:字符的移动.py
    │   │   ├── 1.2:字符串是否包含问题.py
    │   │   ├── 1.5:回文判断.py
    │   │   ├── 1.6:最长回文子串.py
    │   │   ├── 2.1:寻找最小的k个数.py
    │   │   ├── 2.1:寻找最小的k个数_2.py
    │   │   ├── 2.3:求解500万以内的亲和数.py
    │   │   ├── 2.3:求解500万以内的亲和数_2.py
    │   │   ├── 2.4:寻找和为定值的两个数.py
    │   │   ├── 2.6:求连续子数组的最大和.py
    │   │   ├── 3.1:二分查找实现.py
    │   │   ├── 3.2:杨氏矩阵查找.py
    │   │   ├── 3.3:出现次数超过一半的数字.py
    │   │   ├── 6.5:全排列.py
    │   │   ├── 6.6:跳台阶.py
    │   │   ├── 6.8:第一个只出现一次等问题.py
    │   │   ├── 6.9:Trie树.py
    │   │   ├── chapter04.py
    │   │   └── rcdtype.py
    │   ├── rebol/
    │   │   ├── 1.1:左旋转字符串.reb
    │   │   └── 1.2:字符串是否包含问题.reb
    │   ├── ruby/
    │   │   ├── chapter01.rb
    │   │   ├── chapter02.rb
    │   │   ├── chapter03.rb
    │   │   ├── chapter0301.searchTrend.rb
    │   │   ├── chapter0302.quickSort.rb
    │   │   ├── chapter04.rb
    │   │   ├── chapter05.findSum.rb
    │   │   ├── chapter06.amicableNumber.rb
    │   │   ├── chapter07.findMaxSum.rb
    │   │   ├── chapter16.permutation.rb
    │   │   ├── chapter17.rb
    │   │   ├── chapter18.rb
    │   │   └── chapter19.rb
    │   └── scheme/
    │       ├── chapter01.scm
    │       ├── chapter06.scm
    │       ├── chapter06v2.scm
    │       ├── chapter17.scm
    │       └── chapter25.scm
    ├── en/
    │   ├── 01.0.md
    │   ├── 03.0.md
    │   ├── 07.0.md
    │   ├── 11.0.md
    │   ├── 25.0.md
    │   ├── 28.0.md
    │   ├── 35.0.md
    │   └── Readme.md
    ├── epub/
    │   └── TAOP_July.epub
    ├── images/
    │   ├── .directory
    │   ├── 1/
    │   │   ├── 1.1.tex
    │   │   ├── 1.2.tex
    │   │   ├── 1.3.tex
    │   │   ├── 1.4.tex
    │   │   ├── 2.1.tex
    │   │   ├── 2.2.tex
    │   │   ├── 2.3.tex
    │   │   └── include.tex
    │   └── 3/
    │       └── 3.1/
    │           └── .directory
    └── zh/
        ├── 00.01.md
        ├── 01.00.md
        ├── 01.01.md
        ├── 01.02.md
        ├── 01.03.md
        ├── 01.04.md
        ├── 01.05.md
        ├── 01.06.md
        ├── 01.10.md
        ├── 02.00.md
        ├── 02.01.md
        ├── 02.02.md
        ├── 02.03.md
        ├── 02.04.md
        ├── 02.05.md
        ├── 02.06.md
        ├── 02.07.md
        ├── 02.08.md
        ├── 02.09.md
        ├── 02.10.md
        ├── 02.15.md
        ├── 03.00.md
        ├── 03.01.md
        ├── 03.02.md
        ├── 03.03.md
        ├── 03.05.md
        ├── 03.10.md
        ├── 04.01.md
        ├── 04.02.md
        ├── 04.03.md
        ├── 05.00.md
        ├── 05.01.md
        ├── 05.02.md
        ├── 05.03.md
        ├── 05.04.md
        ├── 05.06.md
        ├── 05.10.md
        ├── 06.00.md
        ├── 06.01.md
        ├── 06.02.md
        ├── 06.03.md
        ├── 06.04.md
        ├── 06.05.md
        ├── 06.06.md
        ├── 06.07.md
        ├── 06.08.md
        ├── 06.09.md
        ├── 06.10.md
        ├── 06.11.md
        ├── 06.15.md
        ├── 07.01.md
        ├── 07.02.svm.md
        ├── 08.00.md
        ├── 08.01.md
        ├── 08.02.md
        ├── 08.03.md
        ├── 08.04.md
        ├── 08.05.md
        ├── 10.01.01.md
        ├── 10.01.02.md
        ├── 10.01.03.md
        ├── 40亿个数中快速查找.md
        ├── Readme.md
        ├── hash表算法.md
        ├── 一致性哈希算法.md
        ├── 倒排索引关键词不重复Hash编码.md
        ├── 傅里叶变换算法、上.md
        ├── 傅里叶变换算法、下.md
        ├── 后缀树.md
        ├── 基于给定的文档生成倒排索引的编码与实践.md
        ├── 搜索关键词智能提示suggestion.md
        ├── 最小操作数.md
        ├── 最短摘要的生成.md
        ├── 最长公共子序列.md
        ├── 木块砌墙原稿.md
        ├── 附近地点搜索.md
        └── 随机取出其中之一元素.md
Download .txt
SYMBOL INDEX (417 symbols across 100 files)

FILE: ebook/code/c/1.1:左旋转字符串.c
  function leftShift1 (line 12) | void leftShift1(char * arr, int n)
  function leftShift2 (line 43) | void leftShift2(char * arr, int len, int n)
  function leftShift3 (line 83) | void leftShift3(char * arr, int len, int n)
  function leftShift4 (line 104) | void leftShift4(char * arr, int len, int n)
  function myinvert (line 126) | void myinvert(char * start, char * end)
  function leftShift5 (line 140) | void leftShift5(char * arr, int len, int n)
  function gcd (line 146) | int gcd(int m, int n)
  function leftShift6 (line 157) | void leftShift6(char * arr, int len, int n)
  function main (line 173) | int main()

FILE: ebook/code/c/1.2:字符串是否包含问题.c
  function partion1 (line 15) | int partion1(char * arr, int start, int end)
  function partion (line 44) | int partion(char * arr, int start, int end)
  function quickSort (line 80) | void quickSort(char * arr, int start, int end)
  function countSort (line 90) | void countSort(char * oldArr, char * newArr)
  function contain1 (line 118) | bool contain1(char * stra, char * strb)
  function contain2 (line 141) | bool contain2(char * stra, char * strb)
  function contain3 (line 178) | bool contain3(char * stra, char * strb)
  function contain4 (line 206) | bool contain4(char * stra, char * strb)
  function contain5 (line 220) | bool contain5(char * stra, char * strb)
  function main (line 250) | int main()

FILE: ebook/code/c/1.3:带通配符的字符串匹配问题.c
  function str_len (line 3) | int str_len(char *a)
  function str_copy (line 16) | void str_copy(char *a, const char *b, int len)
  function canMatch (line 48) | int canMatch(char *input, char *rule)

FILE: ebook/code/c/1.4:字符串转换成整数.c
  function StrToInt (line 1) | int StrToInt(const char* str)

FILE: ebook/code/c/1.7:字符串的全排列.c
  function calcAllPermutation (line 7) | void calcAllPermutation(char* perm, int from, int to)
  function _tmain (line 31) | int _tmain(int argc, _TCHAR* argv[])
  function calcAllPermutation (line 47) | void calcAllPermutation(char* perm, int num)
  function main (line 87) | int main()
  function CalcAllPermutation (line 103) | bool CalcAllPermutation(char* perm, int num){
  function main (line 128) | int main()
  function perm (line 142) | void perm(char *str, int size, int resPos)

FILE: ebook/code/c/10.1.3:教你一步一步用c语言实现sift算法、下.c
  function CvMat (line 2) | CvMat * halfSizeImage(CvMat * im)
  function CvMat (line 18) | CvMat * doubleSizeImage(CvMat * im)
  function CvMat (line 36) | CvMat * doubleSizeImage2(CvMat * im)
  function getPixelBI (line 77) | float getPixelBI(CvMat * im, float col, float row)
  function normalizeMat (line 120) | void normalizeMat(CvMat* mat)
  function normalizeVec (line 134) | void normalizeVec(float* vec, int dim)
  function GetVecNorm (line 145) | float GetVecNorm( float* vec, int dim )
  function CvMat (line 179) | CvMat* GaussianKernel2D(float sigma)
  function ConvolveLocWidth (line 210) | float ConvolveLocWidth(float* kernel, int dim, CvMat * src, int x, int y)
  function Convolve1DWidth (line 233) | void Convolve1DWidth(float* kern, int dim, CvMat * src, CvMat * dst)
  function ConvolveLocHeight (line 249) | float ConvolveLocHeight(float* kernel, int dim, CvMat * src, int x, int y)
  function Convolve1DHeight (line 271) | void Convolve1DHeight(float* kern, int dim, CvMat * src, CvMat * dst)
  function BlurImage (line 286) | int BlurImage(CvMat * src, CvMat * dst, float sigma)
  function CvMat (line 304) | CvMat *ScaleInitImage(CvMat * im)
  function ImageOctaves (line 345) | ImageOctaves* BuildGaussianOctaves(CvMat * image)
  function DetectKeypoint (line 445) | int DetectKeypoint(int numoctaves, ImageOctaves *GaussianPyr)
  function DisplayKeypointLocation (line 579) | void DisplayKeypointLocation(IplImage* image, ImageOctaves *GaussianPyr)
  function ComputeGrad_DirecandMag (line 599) | void ComputeGrad_DirecandMag(int numoctaves, ImageOctaves *GaussianPyr)
  function AssignTheMainOrientation (line 646) | void AssignTheMainOrientation(int numoctaves, ImageOctaves *GaussianPyr,...
  function FindClosestRotationBin (line 798) | int FindClosestRotationBin (int binCount, float angle)
  function AverageWeakBins (line 811) | void AverageWeakBins (double* hist, int binCount)
  function InterpolateOrientation (line 840) | bool InterpolateOrientation (double left, double middle,double right, do...
  function DisplayOrientation (line 858) | void DisplayOrientation (IplImage* image, ImageOctaves *GaussianPyr)
  function ExtractFeatureDescriptors (line 891) | void ExtractFeatureDescriptors(int numoctaves, ImageOctaves *GaussianPyr)
  function CvMat (line 1039) | CvMat* MosaicHorizen( CvMat* im1, CvMat* im2 )
  function CvMat (line 1058) | CvMat* MosaicVertical( CvMat* im1, CvMat* im2 )
  function main (line 1079) | int main( void )

FILE: ebook/code/c/2.1:寻找最小的 k 个数.c
  function q_select (line 6) | void q_select( input_type a[], int k, int left, int right )

FILE: ebook/code/c/2.2:求给定区间的第K小元素.c
  type node (line 9) | struct node{
  function main (line 18) | int main()
  type node (line 50) | struct node{
  function main (line 59) | int main()

FILE: ebook/code/c/2.3:求解500万以内的亲和数.c
  function main (line 17) | int main()

FILE: ebook/code/c/2.4:寻找和为定值的两个数.c
  function twoSum (line 6) | void twoSum(int data[], unsigned int length, int sum)
  function main (line 37) | int main(){

FILE: ebook/code/c/2.5:寻找和为定值的多个数.c
  function SumOfkNumber (line 9) | void SumOfkNumber(int sum, int n)
  function main (line 31) | int main()
  function SumOfkNumber (line 56) | void SumOfkNumber(int t, int k, int r, int& M, bool& flag, bool* X)
  function search (line 86) | void search(int& N, int& M)
  function main (line 106) | int main()

FILE: ebook/code/c/2.6:求连续子数组的最大和.c
  function maxSubArray (line 2) | int maxSubArray(int* A, int n)
  function maxSubArray (line 28) | int maxSubArray(int* a, int n)
  function main (line 44) | int main()
  function maxSubArray (line 58) | int maxSubArray(int* a, int n)
  function main (line 75) | int main()

FILE: ebook/code/c/2.7:奇偶排序.c
  function isOddNumber (line 8) | bool isOddNumber(int data)
  function swap (line 14) | void swap(int* x, int* y)
  function oddEvenSort (line 22) | void oddEvenSort(int *pData, unsigned int length)
  function main (line 50) | int main(int argc, _TCHAR* argv[])
  function isOddNumber (line 74) | bool isOddNumber(int data)
  function swap (line 80) | void swap(int* x, int* y)
  function oddEvenSort2 (line 88) | void oddEvenSort2(int data[], int lo, int hi)
  function main (line 103) | int main(int argc, _TCHAR* argv[])

FILE: ebook/code/c/2.8:矩阵相乘之Strassen算法.c
  function Mul (line 3) | void Mul(int** matrixA, int** matrixB, int** matrixC)

FILE: ebook/code/c/3.1:二分查找实现.c
  function binary_search (line 9) | int binary_search(int array[], int n, int value)

FILE: ebook/code/c/3.2:杨氏矩阵查找.c
  function YoungMatrix (line 8) | bool YoungMatrix(int array[][COL], int searchkey){
  function main (line 23) | int main(){

FILE: ebook/code/c/4.1:木块砌墙.c
  function namespace (line 8) | namespace HeapBlock
  function cal (line 163) | void cal(int a[6][32][32],int n,int col,int laststate,int nowstate)
  function mul (line 182) | inline int mul(ll x, ll y)
  function multiply (line 187) | void multiply(int n,int a[][32],int b[][32])
  function calculate (line 205) | int calculate(int n,int k)

FILE: ebook/code/c/4.2:格子取数问题.c
  function dfs (line 23) | void dfs( int index)
  function _tmain (line 91) | int _tmain(int argc, _TCHAR* argv[])
  function isValid (line 106) | bool isValid(int step, int x1, int x2, int n) //判断状态是否合法
  function getValue (line 112) | int getValue(int step, int x1, int x2, int n)  //处理越界 不存在的位置 给负无穷的值
  function getAnswer (line 118) | int getAnswer(int a[N][N], int n)
  function isValid (line 170) | bool isValid(int step, int x1, int x2, int n) //判断状态是否合法
  function getValue (line 176) | int getValue(int step, int x1, int x2, int n)  //处理越界 不存在的位置 给负无穷的值
  function getAnswer (line 182) | int getAnswer(int a[N][N], int n)

FILE: ebook/code/c/4.3:出现次数超过一半的数字.c
  function FindOneNumber (line 9) | int FindOneNumber(int* a, int length)
  function main (line 28) | int main()

FILE: ebook/code/c/4.3:完美洗牌算法.c
  function pefect_shuffle1 (line 4) | void pefect_shuffle1(int *a, int n)
  function perfect_shuffle2 (line 20) | void perfect_shuffle2(int *a, int n)
  function cycle_leader (line 57) | void cycle_leader(int *a, int from, int mod)
  function reverse (line 73) | void reverse(int *a, int from, int to)
  function right_rotate (line 85) | void right_rotate(int *a, int num, int n)
  function perfect_shuffle3 (line 96) | void perfect_shuffle3(int *a, int n)
  function shuffle (line 132) | void shuffle(int *a, int n)

FILE: ebook/code/c/4.4:最近公共祖先LCA问题.LCAProblem.c
  function Node (line 31) | Node* FindLowestCommonAncestorBst(Node* root, Node* u, Node* v)
  function Node (line 93) | Node* FindLcaBstRecursively(Node* root, Node* u, Node* v)

FILE: ebook/code/c/4.5:打印螺旋矩阵.SpiralMatrix.c
  function PrintSpiralMatrix (line 23) | void PrintSpiralMatrix(int n)
  function main (line 96) | int main(void)

FILE: ebook/code/c/5.1:最长公共子序列(LCS)问题.c
  function public (line 3) | public class LCS{

FILE: ebook/code/c/5.2:最大连续乘积子串.c
  function maxProductSubstring (line 7) | double maxProductSubstring(double *a, int length)
  function _tmain (line 25) | int _tmain(int argc, _TCHAR* argv[])
  function maxProductSubstring (line 39) | double maxProductSubstring(double *a, int length)
  function _tmain (line 55) | int _tmain(int argc, _TCHAR* argv[])

FILE: ebook/code/c/5.3:字符串编辑距离.c
  function editDistance (line 20) | int editDistance(char *pSource, char *pTarget)
  function main (line 51) | int main()

FILE: ebook/code/c/5.4:交替字符串.c
  function isInterleave (line 1) | bool isInterleave(string s1, string s2, string s3)

FILE: ebook/code/c/6.11:最小操作数.c
  function class (line 4) | class Solution
  function class (line 118) | class Solution

FILE: ebook/code/c/6.4:回文判断.c
  function IsPalindrome (line 6) | bool IsPalindrome(const char *s, int n)
  function IsPalindrome2 (line 24) | bool IsPalindrome2(const char *s, int n)
  function LongestPalindrome (line 41) | int LongestPalindrome(const char *s, int n)

FILE: ebook/code/c/6.6:跳台阶问题.c
  function Fibonacci_Solution1 (line 2) | long long Fibonacci_Solution1(unsigned int n)

FILE: ebook/code/c/6.8:第一个只出现一次的字符.c
  function find_first_unique_char (line 8) | char find_first_unique_char(char *str)
  function main (line 32) | int main()
  function FirstNotRepeatChar (line 43) | char FirstNotRepeatChar(char* pString)

FILE: ebook/code/c/6.9:Trie树.c
  type TrieNode (line 12) | typedef struct TrieNode{
  function initTrieNode (line 18) | void initTrieNode(TrieNode* p, char c)
  function incTrieNode (line 26) | void incTrieNode(TrieNode* p)
  function compTrieNode (line 31) | int compTrieNode(TrieNode* p, char c)
  function Char2Index (line 41) | int Char2Index(char c)
  function TrieNode (line 46) | TrieNode* getNextChar(TrieNode* t, char c)
  function setNextChar (line 51) | void setNextChar(TrieNode* t, char c, TrieNode* new)
  function updateWord (line 59) | void updateWord(TrieNode* t, char* word)
  function getWord (line 86) | int getWord(TrieNode* t, char* word)
  function dispTrieNodeI (line 104) | void dispTrieNodeI(TrieNode* t, int level)
  function dispTrieNode (line 118) | void dispTrieNode(TrieNode* t)
  function main (line 124) | int main()

FILE: ebook/code/c/7.1:搜索引擎热门查询统计.c
  type node_no_space (line 20) | struct node_no_space
  type node_has_space (line 21) | struct node_has_space
  type node_no_space (line 24) | struct node_no_space
  type node_has_space (line 31) | struct node_has_space
  function hash_function (line 39) | int hash_function(char const *p)
  function append_word (line 52) | void append_word(char const *str)
  function write_to_file (line 77) | void write_to_file()
  function sift_down (line 93) | void sift_down(node_has_space heap[], int i, int len)
  function build_min_heap (line 122) | void build_min_heap(node_has_space heap[], int len)
  function handle_symbol (line 133) | void handle_symbol(char *str, int n)
  function main (line 154) | int main()

FILE: ebook/code/c/7.3:倒排索引关键词不重复Hash编码.c
  function prepareCryptTable (line 3) | void prepareCryptTable()
  function HashString (line 26) | unsigned long HashString(const char *lpszkeyName, unsigned long dwHashTy...
  function GetHashTablePos (line 44) | int GetHashTablePos( har *lpszString, SOMESTRUCTURE *lpTable )
  function GetHashTablePos (line 62) | int GetHashTablePos( char *lpszString, MPQHASHTABLE *lpTable, int nTable...
  function prepareCryptTable (line 96) | void prepareCryptTable()
  function HashString (line 115) | unsigned long HashString(const char *lpszkeyName, unsigned long dwHashTy...
  function insert_string (line 143) | int insert_string(const char *string_in)
  function bigIndex_hash (line 204) | void bigIndex_hash(const char *docpath, const char *hashpath)
  function main (line 273) | int main()
  function bigIndex_hashcode (line 287) | void bigIndex_hashcode(const char *in_file_path, const char *out_file_path)

FILE: ebook/code/c/7.4:倒排索引关键词 Hash 不重复编码实践.c
  function prepareCryptTable (line 8) | void prepareCryptTable()
  function HashString (line 32) | unsigned long HashString( char *lpszFileName, unsigned long dwHashType )
  function main (line 52) | int main( int argc, char **argv )

FILE: ebook/code/cpp/1.1:左旋转字符串.cpp
  function leftShiftOne (line 6) | void leftShiftOne(string &str)
  function rotate_1 (line 18) | void rotate_1(string &str, int m)
  function rotate_2 (line 27) | void rotate_2(string &str, int m)
  function rotate_3 (line 65) | void rotate_3(string &str, int m)
  function rotate_4 (line 108) | void rotate_4(string &str, int m)
  function rotate_5 (line 152) | void rotate_5(string &str, int n, int m, int head, int tail, bool flag)
  function gcd (line 206) | int gcd (int m, int n)
  function rotate_6 (line 218) | void rotate_6(string &str, int m)
  function rotate_7 (line 240) | void rotate_7(char *begin, char *mid, char *end)
  function main (line 287) | int main () {

FILE: ebook/code/cpp/2.1:寻找最小的 k 个数.cpp
  function GetParent (line 6) | int GetParent(int* pArray, int* pLast)
  function GetLeft (line 15) | int GetLeft(int* pArray, int* pLast)
  function GetRight (line 24) | int GetRight(int* pArray, int* pLast)
  function Swap (line 33) | void Swap(int* pa, int* pb)
  function MaxHeapify (line 41) | void MaxHeapify(int* pArray, const int nLength, const int nI)
  function BuildMaxHeap (line 80) | int BuildMaxHeap(int* pArray, int* pLast)
  function FindMinimumK (line 99) | int FindMinimumK(int* pArray, int nLength, int k)
  function main (line 119) | int main()

FILE: ebook/code/cpp/4.2:完美洗牌算法.cpp
  function cycle_leader (line 9) | void cycle_leader(vector<int> &a,int from, int mod) {
  function perfect_shuffle (line 14) | void perfect_shuffle(vector<int> &a,int n){
  function main (line 40) | int main(){

FILE: ebook/code/cpp/7.4:倒排索引关键词 Hash 不重复编码实践.cpp
  function prepareCryptTable (line 8) | void prepareCryptTable()
  function HashString (line 32) | unsigned long HashString( char *lpszFileName, unsigned long dwHashType )
  function main (line 52) | int main( int argc, char **argv )

FILE: ebook/code/cpp/9.2:海量数据处理之Bit-map详解.cpp
  function BitMapSortDemo (line 15) | void BitMapSortDemo()
  function _tmain (line 52) | int _tmain(int argc, _TCHAR* argv[])

FILE: ebook/code/cpp/chapter04.cpp
  function main (line 17) | int main()

FILE: ebook/code/cpp/chapter06.cpp
  function createCounter (line 6) | void createCounter(vector<int>& counter, int n)
  function main (line 45) | int main ()

FILE: ebook/code/go/1.1-左旋转字符串.go
  function left_shift_one (line 13) | func left_shift_one(s []byte, n int) {
  function left_shift_m (line 26) | func left_shift_m(s []byte, n int, m int) {
  function reverse (line 36) | func reverse(s []byte, from int, to int) {
  function leftshift (line 46) | func leftshift(s []byte, n int, m int) {
  function main (line 53) | func main() {

FILE: ebook/code/go/1.2-字符串是否包含问题.go
  function compare1 (line 14) | func compare1(a string, b string) bool {
  function compare2 (line 32) | func compare2(a string, b string) bool {
  function sortString (line 52) | func sortString(w string) string {
  function compare3 (line 59) | func compare3(a string, b string) bool {
  function compare4 (line 81) | func compare4(a string, b string) bool {
  function compare5 (line 109) | func compare5(a string, b string) bool {
  function compare6 (line 114) | func compare6(a string, b string) bool {
  function main (line 133) | func main() {

FILE: ebook/code/go/1.5-回文判断.go
  function isPalindrome (line 11) | func isPalindrome(s string) bool {
  function isPalindrome2 (line 31) | func isPalindrome2(s string) bool {
  function main (line 52) | func main() {

FILE: ebook/code/go/2.1-寻找最小的k个数.go
  function quicksort (line 11) | func quicksort(seq []int) []int {
  function max (line 36) | func max(seq []int) int {
  function bInsert (line 56) | func bInsert(seq []int, k int) []int {
  function sort1 (line 78) | func sort1(seq []int, k int) []int {
  function sort2 (line 87) | func sort2(seq []int, k int) []int {
  function sort3 (line 108) | func sort3(seq []int, k int) []int {
  function main (line 127) | func main() {

FILE: ebook/code/go/2.2-求数组中给定下标区间内的第K小元素.go
  type Node (line 12) | type Node struct
  type SortNodeByData (line 17) | type SortNodeByData
    method Len (line 19) | func (a SortNodeByData) Len() int {
    method Swap (line 22) | func (a SortNodeByData) Swap(i, j int) {
    method Less (line 25) | func (a SortNodeByData) Less(i, j int) bool {
  function find1 (line 30) | func find1(arr []int, a int, b int, flag int) int {
  function main (line 53) | func main() {

FILE: ebook/code/go/3.2-杨氏矩阵查找.go
  function find2 (line 12) | func find2(arr [][]int, s int) bool {
  function main (line 38) | func main() {

FILE: ebook/code/go/3.3:出现次数超过一半的数字.go
  function findNumberAppearEqualHalf (line 9) | func findNumberAppearEqualHalf(data []int) int {
  function findNumberAppearMoreThanHalf (line 28) | func findNumberAppearMoreThanHalf(data []int) int {
  function main (line 48) | func main() {

FILE: ebook/code/java/chapter1/1.1:左旋转字符串.java
  class RotateString (line 13) | public class RotateString {
    method leftRotateString (line 29) | public static char[] leftRotateString(char[] str, int n) {
    method rotate (line 44) | private static char[] rotate(char[] str, int start, int end) {
    method rotateLinkList (line 69) | public static ListNode rotateLinkList(ListNode head, int n) {
    method rotateList (line 88) | private static ListNode rotateList(ListNode start, ListNode end) {
    method rightRotateString (line 113) | public static char[] rightRotateString(char[] str, int n) {
    method rotateSentence (line 132) | public static char[] rotateSentence(char[] sentence) {

FILE: ebook/code/java/chapter1/1.2:字符串包含.java
  class StringContain (line 10) | public class StringContain {
    method hashCheck (line 33) | public static boolean hashCheck(char[] s1, char[] s2) {

FILE: ebook/code/java/chapter1/Chapter1.java
  class Chapter1 (line 1) | class Chapter1 {
    method leftShiftV1 (line 4) | public void leftShiftV1 (char[] s, int m) {
    method leftShiftOne (line 11) | private void leftShiftOne (char[] s) {
    method leftShiftV2 (line 24) | public void leftShiftV2(char[] s, int m) {
    method reverse (line 32) | private void reverse (char[] s, int from, int to) {
    method main (line 42) | public static void main (String[] args) {

FILE: ebook/code/java/chapter1/Palindrome.java
  class Palindrome (line 5) | public class Palindrome
    method isPalindromeV1 (line 8) | public static boolean isPalindromeV1(String str)
    method isPalindromeV2 (line 31) | public static boolean isPalindromeV2(String str)

FILE: ebook/code/java/chapter2/Chapter2.java
  class Chapter2 (line 1) | class Chapter2 {
    method main (line 2) | public static void main (String[] args) {

FILE: ebook/code/java/chapter2/CountAndCompare.java
  class CountAndCompare (line 1) | class CountAndCompare implements ICompare {
    method compare (line 2) | @Override
    method countSort (line 21) | private String countSort(String str) {

FILE: ebook/code/java/chapter2/HashTableCompare.java
  class HashTableCompare (line 1) | class HashTableCompare implements ICompare {
    method compare (line 2) | @Override

FILE: ebook/code/java/chapter2/ICompare.java
  type ICompare (line 1) | interface ICompare {
    method compare (line 2) | public boolean compare(String longStr, String shortStr);

FILE: ebook/code/java/chapter2/PrimeCompare.java
  class PrimeCompare (line 3) | class PrimeCompare implements ICompare {
    method compare (line 5) | @Override

FILE: ebook/code/java/chapter2/SortAndCompare.java
  class SortAndCompare (line 3) | class SortAndCompare implements ICompare {
    method compare (line 4) | @Override

FILE: ebook/code/java/chapter2/TopK.java
  class TopK (line 9) | public class TopK
    method topKV1 (line 12) | public static List<Integer> topKV1(List<Integer> list, int k)
    method topKV2 (line 26) | public static List<Integer> topKV2(List<Integer> list, int k)
    method quickSort (line 54) | public static void quickSort(List<Integer> arr, int low, int high) {

FILE: ebook/code/java/chapter3/Chapter3.java
  class Chapter3 (line 3) | public class Chapter3 {
    method main (line 5) | public static void main(String[] args) {

FILE: ebook/code/java/chapter3/HeapSolution.java
  class HeapSolution (line 1) | class HeapSolution implements IFindMinK {
    method findMinK (line 3) | @Override

FILE: ebook/code/java/chapter3/IFindMinK.java
  type IFindMinK (line 1) | interface IFindMinK {
    method findMinK (line 2) | public int[] findMinK(int[] data, int k);

FILE: ebook/code/java/chapter3/MaxHeap.java
  class MaxHeap (line 7) | public class MaxHeap {
    method MaxHeap (line 12) | public MaxHeap(int capacity) {
    method getAll (line 18) | public int[] getAll() {
    method insert (line 22) | public void insert(int m) {
    method maxHeapify (line 32) | private void maxHeapify(int n) {
    method swap (line 53) | private void swap(int i, int j) {

FILE: ebook/code/java/chapter4/Chapter4.java
  class Chapter4 (line 4) | public class Chapter4 {
    method findSum_1 (line 7) | public Pair findSum_1(int[] data, int sum) {
    method findSum_2 (line 20) | public Pair findSum_2(int[] data, int sum) {
    method binarySearch (line 36) | public int binarySearch(int[] data, int target) {
    method findSum_3 (line 53) | public Pair findSum_3(int[] data, int sum) {
    method findSum_4 (line 77) | public Pair findSum_4(int[] data, int sum) {
    method findSum_5 (line 104) | public Pair findSum_5(int[] data, int sum) {
    method main (line 122) | public static void main(String[] argv) {
  class Pair (line 154) | class Pair {
    method Pair (line 158) | public Pair(int num1, int num2) {
    method getNum1 (line 163) | public int getNum1() {
    method setNum1 (line 167) | public void setNum1(int num1) {
    method getNum2 (line 171) | public int getNum2() {
    method setNum2 (line 175) | public void setNum2(int num2) {
    method toString (line 179) | public String toString() {

FILE: ebook/code/java/chapter6/Chapter6.java
  class Chapter6 (line 1) | public class Chapter6 {
    method findAmicableNumber_1 (line 4) | public void findAmicableNumber_1() {
    method main (line 26) | public static void main(String[] argv) {

FILE: ebook/code/js/1.1:左旋转字符串/1.1:左旋转字符串.js
  function leftShift1 (line 14) | function leftShift1(s, m) {
  function shiftHeadToEnd (line 32) | function shiftHeadToEnd(arr, length) {
  function leftShift2 (line 50) | function leftShift2(s, m) {
  function reverse (line 74) | function reverse(arr, start, end) {

FILE: ebook/code/js/1.2:字符串是否包含问题/1.2:字符串是否包含问题.js
  function compare1 (line 14) | function compare1(a, b) {
  function compare2 (line 37) | function compare2(a, b) {
  function compare3 (line 61) | function compare3(a, b) {
  function compare4 (line 87) | function compare4(a, b) {
  function compare5 (line 116) | function compare5(a, b) {
  function compare6 (line 148) | function compare6(a, b) {

FILE: ebook/code/js/2.4:寻找和为定值的两个数/2.4:寻找和为定值的两个数.js
  function solution1 (line 14) | function solution1(arr, number) {
  function solution2 (line 34) | function solution2(arr, number) {
  function binarySearch (line 51) | function binarySearch(arr, key, low, high) {
  function solution3 (line 77) | function solution3(arr, number) {
  function solution4 (line 115) | function solution4(arr, number) {
  function solution5 (line 139) | function solution5(arr, number) {

FILE: ebook/code/php/chapter1.php
  function LeftShiftOne (line 3) | function LeftShiftOne($string){
  function LeftShiftString (line 9) | function LeftShiftString($string,$m){
  function reverse (line 21) | function reverse($string){
  function LeftRotateString (line 26) | function LeftRotateString($string,$m){
  function LeftShiftTest (line 37) | function LeftShiftTest($str){
  function LeftRotateTest (line 48) | function LeftRotateTest($str){

FILE: ebook/code/php/chapter2.php
  function compare_1 (line 6) | function compare_1($a,$b){
  function compare_2 (line 27) | function compare_2($a,$b){
  function compare_3 (line 50) | function compare_3($a,$b){
  function compare_4 (line 80) | function compare_4($a,$b){
  function compare_5 (line 108) | function compare_5($a,$b) {
  function compare_6 (line 138) | function compare_6($a,$b) {
  function test (line 162) | function test($a,$b){

FILE: ebook/code/php/chapter3.php
  class Wildcard (line 2) | class Wildcard{
    method str_join (line 7) | private static function str_join($a,$b,$lenb){
    method canMatch (line 25) | private static function canMatch($input,$rule){
    method my_find (line 57) | public static function my_find($input,$rule){
  function test (line 88) | function test($input,$rule){

FILE: ebook/code/python/1.1:字符的移动.py
  function left_shift_one (line 20) | def left_shift_one(s, i, j):
  function simple_shift (line 40) | def simple_shift(s, m):
  function left_shift (line 58) | def left_shift(s, m):
  function invert (line 75) | def invert(s, start, end):
  function invert_solution (line 90) | def invert_solution(s, m):

FILE: ebook/code/python/1.2:字符串是否包含问题.py
  function compare_1 (line 2) | def compare_1(long_string, short_string):
  function compare_2 (line 26) | def compare_2(long_string, short_string):
  function string_contain3 (line 49) | def string_contain3(long_str, short_str):
  function string_contain4 (line 70) | def string_contain4(long_str, short_str):
  function compare_5 (line 108) | def compare_5(long_string, short_string):
  function compare_6 (line 132) | def compare_6(long_string, short_string):
  function compare_7 (line 160) | def compare_7(long_string, short_string):

FILE: ebook/code/python/1.5:回文判断.py
  function is_palindrome1 (line 9) | def is_palindrome1(s):
  function is_palindrome2 (line 26) | def is_palindrome2(s):

FILE: ebook/code/python/1.6:最长回文子串.py
  function fastLongestPalindromes (line 14) | def fastLongestPalindromes(seq):
  function naiveLongestPalindromes (line 95) | def naiveLongestPalindromes(seq):
  function pre_process (line 131) | def pre_process(seq):
  function manacher (line 137) | def manacher(seq):

FILE: ebook/code/python/2.1:寻找最小的k个数.py
  function ksmallest1 (line 11) | def ksmallest1(lst, k):
  function ksmallest2 (line 24) | def ksmallest2(lst, k):
  function ksmallest3 (line 44) | def ksmallest3(lst, k):

FILE: ebook/code/python/2.1:寻找最小的k个数_2.py
  class topk (line 4) | class topk():
    method __init__ (line 6) | def __init__(self, k):
    method push (line 10) | def push(self, val):
    method result (line 17) | def result(self):

FILE: ebook/code/python/2.3:求解500万以内的亲和数.py
  function prime_list (line 4) | def prime_list(n):
  function sum_divisors (line 16) | def sum_divisors(n, primelst):
  function get_sum_div (line 33) | def get_sum_div(n, primelst):

FILE: ebook/code/python/2.4:寻找和为定值的两个数.py
  function find_sum (line 4) | def find_sum(array, key):
  function main (line 19) | def main():

FILE: ebook/code/python/2.6:求连续子数组的最大和.py
  function max_sum (line 8) | def max_sum(ls):
  function test (line 27) | def test():

FILE: ebook/code/python/3.1:二分查找实现.py
  function binary_search (line 1) | def binary_search(lst, n):

FILE: ebook/code/python/3.2:杨氏矩阵查找.py
  function young_matrix_1 (line 2) | def young_matrix_1(matrix, key):
  function young_matrix (line 27) | def young_matrix(matrix, key):

FILE: ebook/code/python/3.3:出现次数超过一半的数字.py
  function more_than_half_number (line 4) | def more_than_half_number(array):

FILE: ebook/code/python/6.6:跳台阶.py
  function fib (line 1) | def fib(n):
  function fib2 (line 13) | def fib2(n):

FILE: ebook/code/python/6.8:第一个只出现一次等问题.py
  function find_first_unique_char (line 1) | def find_first_unique_char(string):

FILE: ebook/code/python/6.9:Trie树.py
  function newTrie (line 5) | def newTrie():
  function updateWord (line 8) | def updateWord(t, word):
  function getWord (line 27) | def getWord(t, word):

FILE: ebook/code/python/chapter04.py
  function strstr (line 1) | def strstr(haystack, needle):
  function test_strstr (line 7) | def test_strstr():
  function find_no_repeat_char (line 13) | def find_no_repeat_char(string):
  function test_find_no_repeat_char (line 23) | def test_find_no_repeat_char():

FILE: ebook/code/python/rcdtype.py
  function recordtype (line 8) | def recordtype(typename, field_names, verbose=False, **default_kwds):

FILE: ebook/code/ruby/chapter01.rb
  function swap (line 4) | def swap(s, i, j)
  function left_shift_one (line 8) | def left_shift_one(s, i, j)
  function simple_shift (line 14) | def simple_shift(s, m)
  function left_shift (line 20) | def left_shift(s, m)
  function invert (line 25) | def invert(s, from, to)
  function invert_solution (line 30) | def invert_solution(s, m)

FILE: ebook/code/ruby/chapter02.rb
  function compare_1 (line 4) | def compare_1(long_string, short_string)
  function compare_2 (line 11) | def compare_2(long_string, short_string)
  function count_sort (line 23) | def count_sort(src)
  function compare_3 (line 38) | def compare_3(long_string, short_string)
  function compare_4 (line 56) | def compare_4(long_string, short_string)
  function compare_5 (line 77) | def compare_5(long_string, short_string)
  function compare_6 (line 90) | def compare_6(long_string, short_string)
  function compare_ruby (line 101) | def compare_ruby(long_string, short_string)

FILE: ebook/code/ruby/chapter03.rb
  function top_minimum (line 4) | def top_minimum(list, k)

FILE: ebook/code/ruby/chapter0301.searchTrend.rb
  function create_hash (line 5) | def create_hash(input)
  function trend (line 17) | def trend(array, k, v, top = 10, desc = true)
  function search_trend (line 34) | def search_trend(input, top = 10, desc = true)

FILE: ebook/code/ruby/chapter0302.quickSort.rb
  function quick_sort_01 (line 4) | def quick_sort_01(list)
  function quick_sort_02 (line 12) | def quick_sort_02(a)
  function quick_sort_performance (line 16) | def quick_sort_performance(size)

FILE: ebook/code/ruby/chapter04.rb
  class String (line 4) | class String
    method o_index (line 7) | def o_index(sub)
    method o_first_count_letter (line 25) | def o_first_count_letter(count = 1)
  class Array (line 35) | class Array
    method copy_to (line 37) | def copy_to(dest)
    method copy (line 44) | def copy(src, dest)

FILE: ebook/code/ruby/chapter05.findSum.rb
  class Array (line 5) | class Array
    method find_01 (line 6) | def find_01(sum)
    method find_02 (line 16) | def find_02(sum)
    method find_03 (line 23) | def find_03(sum)
    method find_with_sum (line 31) | def find_with_sum(sum, min = 1, max = nil)
  function find_sum_with_two (line 46) | def find_sum_with_two(array, sum)
  function minimum_differential (line 59) | def minimum_differential(a, b)

FILE: ebook/code/ruby/chapter06.amicableNumber.rb
  function amicable_number (line 4) | def amicable_number max

FILE: ebook/code/ruby/chapter07.findMaxSum.rb
  function max_sum (line 4) | def max_sum(arr)
  function max_sum_dp (line 17) | def max_sum_dp(arr)

FILE: ebook/code/ruby/chapter16.permutation.rb
  function permutation_recursive (line 3) | def permutation_recursive(ar)

FILE: ebook/code/ruby/chapter17.rb
  function fibonacci_solution (line 4) | def fibonacci_solution n

FILE: ebook/code/ruby/chapter18.rb
  function odd_even (line 4) | def odd_even(arr)
  function reorder_odd_even (line 8) | def reorder_odd_even(arr)
Condensed preview — 228 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (834K chars).
[
  {
    "path": ".gitignore",
    "chars": 538,
    "preview": "# Compiled source #\n###################\n*.com\n*.class\n*.dll\n*.exe\n*.o\n*.so\nebook/build/build\n\n# Packages #\n############\n"
  },
  {
    "path": "Readme.md",
    "chars": 9509,
    "preview": "## 程序员编程技艺(原编程艺术系列,脱胎于微软面试100题系列,后成书为编程之法)\n\n看过[结构之法算法之道blog](http://blog.csdn.net/v_july_v)的朋友可能知道,从2010年10月起,[July](htt"
  },
  {
    "path": "ebook/build/Makefile",
    "chars": 1822,
    "preview": "BUILD = build\nBOOKNAME = TAOP_July\nMETADATA = metadata.yaml\nSRC_DIR = ../zh/\nTOC = --toc --toc-depth=1\nLATEX_CLASS = rep"
  },
  {
    "path": "ebook/build/README.md",
    "chars": 633,
    "preview": "#Build Ebooks\n\n##Requirement\n*\t[pandoc](http://johnmacfarlane.net/pandoc/)\n*\t[mdtogh](https://github.com/marchtea/mdtogh"
  },
  {
    "path": "ebook/build/book.json",
    "chars": 129,
    "preview": "{\n    \"title\": \"The Art of Programming By July\",\n    \"description\": \"本书是July和他伙伴们的《程序员编程艺术》的电子书\",\n    \"coverimage\": \"TAO"
  },
  {
    "path": "ebook/build/metadata.yaml",
    "chars": 269,
    "preview": "---\ntitle:\n- type: main\n  text: The Art of Programming By July\n- type: subtitle\n  text: somestuff\ncreator:\n- role: autho"
  },
  {
    "path": "ebook/build/style.css",
    "chars": 456,
    "preview": "/* This defines styles and classes used in the book */\nbody { margin: 5%; text-align: justify; font-size: medium; }\ncode"
  },
  {
    "path": "ebook/code/c/1.1:左旋转字符串.c",
    "chars": 5975,
    "preview": "/*\n * Zaks Wang\n * ultimate010@gmail.com\n * ultimate010.tk\n * 2013-12-31\n */\n#include <stdio.h>\n#include <string.h>\n//字符"
  },
  {
    "path": "ebook/code/c/1.2:字符串是否包含问题.c",
    "chars": 6727,
    "preview": "/*\n * Zaks Wang\n * ultimate010@gmail.com\n * ultimate010.tk\n * 2014-1-2\n */\n//判断a字符串是否包含b字符串的字母,假定都没有重复字符出现\n#include <std"
  },
  {
    "path": "ebook/code/c/1.3:带通配符的字符串匹配问题.c",
    "chars": 3897,
    "preview": "//解法一\n//copyright@cao_peng 2013/4/23\nint str_len(char *a)\n{\n\t//字符串长度\n\tif (a == 0)\n\t{\n\t\treturn 0;\n\t}\n\tchar *t = a;\n\tfor ("
  },
  {
    "path": "ebook/code/c/1.4:字符串转换成整数.c",
    "chars": 786,
    "preview": "int StrToInt(const char* str)\n{\n\tstatic const int MAX_INT = (int)((unsigned)~0 >> 1);\n\tstatic const int MIN_INT = -(int)"
  },
  {
    "path": "ebook/code/c/1.7:字符串的全排列.c",
    "chars": 2258,
    "preview": "//解法一、代码①\n#include \"stdafx.h\"\n#include <algorithm>\n#include <iostream>\nusing namespace std;\n\nvoid calcAllPermutation(cha"
  },
  {
    "path": "ebook/code/c/10.1.3:教你一步一步用c语言实现sift算法、下.c",
    "chars": 44591,
    "preview": "//下采样原来的图像,返回缩小2倍尺寸的图像  \nCvMat * halfSizeImage(CvMat * im)   \n{  \n\tunsigned int i,j;  \n\tint w = im->cols/2;  \n\tint h = "
  },
  {
    "path": "ebook/code/c/2.1:寻找最小的 k 个数.c",
    "chars": 3529,
    "preview": "//解法四\n//copyright@ mark allen weiss  \n//July、updated,2011.05.05凌晨.  \n\n//q_select places the kth smallest element in a[k]"
  },
  {
    "path": "ebook/code/c/2.2:求给定区间的第K小元素.c",
    "chars": 1292,
    "preview": "//伴随数组解法\n//copyright@ 水 && July  \n//总的时间复杂度为O(N*logN+N)= O(N*logN)。  \n//July、updated,2011.05.28.凌晨。  \n#include<iostream>"
  },
  {
    "path": "ebook/code/c/2.3:求解500万以内的亲和数.c",
    "chars": 980,
    "preview": "//解法一\n//求解亲和数问题\n\n//第一个for和第二个for循环是logN*N(调和级数)次遍历,第三个for循环扫描O(N)。\n//所以总的时间复杂度为 O(N*logN) + O(n) =O(N*logN+N)(其中logN为调和级"
  },
  {
    "path": "ebook/code/c/2.4:寻找和为定值的两个数.c",
    "chars": 646,
    "preview": "#include <iostream>\n#include <algorithm>\nusing namespace std;\n\n//copyright@2014 July\nvoid twoSum(int data[], unsigned in"
  },
  {
    "path": "ebook/code/c/2.5:寻找和为定值的多个数.c",
    "chars": 2047,
    "preview": "//解法一\n//copyright@ July && yansha\n//updated@ 2014 July\n#include<list>\n#include<iostream>\nusing namespace std;\n\nlist<int>"
  },
  {
    "path": "ebook/code/c/2.6:求连续子数组的最大和.c",
    "chars": 1492,
    "preview": "//解法一\nint maxSubArray(int* A, int n)\n{\n    int maxSum = -INF;\n    int currSum = 0;\n    for (int i = 0; i < n; i++)\n    {"
  },
  {
    "path": "ebook/code/c/2.7:奇偶排序.c",
    "chars": 1635,
    "preview": "// 6.7 奇偶排序.cpp : 定义控制台应用程序的入口点。\n//实现一\n#include \"stdafx.h\"\n#include <iostream>\nusing namespace std;\n\n//判断是否为奇数\nbool isOd"
  },
  {
    "path": "ebook/code/c/2.7:荷兰国旗问题.c",
    "chars": 523,
    "preview": "//解法一\n//引用自gnuhpc  \nwhile( current<=end )        \n{             \n  if( array[current] ==0 )             \n   {           "
  },
  {
    "path": "ebook/code/c/2.8:矩阵相乘之Strassen算法.c",
    "chars": 327,
    "preview": "//解法一\n//矩阵乘法,3个for循环搞定    \nvoid Mul(int** matrixA, int** matrixB, int** matrixC)    \n{    \n\tfor(int i = 0; i < 2; ++i)  "
  },
  {
    "path": "ebook/code/c/3.1:二分查找实现.c",
    "chars": 779,
    "preview": "//二分查找V0.1实现版\n//copyright@2011 July\n\n//首先要把握下面几个要点:\n//right = n-1 => while(left <= right) => right = middle-1;\n//right ="
  },
  {
    "path": "ebook/code/c/3.2:杨氏矩阵查找.c",
    "chars": 631,
    "preview": "#include <stdio.h>\n#include <iostream>\nusing namespace std;\n\n#define ROW 4\n#define COL 4\n\nbool YoungMatrix(int array[][C"
  },
  {
    "path": "ebook/code/c/4.1:木块砌墙.c",
    "chars": 5062,
    "preview": "//copyright@红色标记 12/8/2013    \n//updated@July 13/8/2013  \nusing System;    \nusing System.Collections.Generic;    \nusing "
  },
  {
    "path": "ebook/code/c/4.2:格子取数问题.c",
    "chars": 4785,
    "preview": "//解法一\n//copyright@西芹_new 2013\n#include \"stdafx.h\"\n#include <iostream>\nusing namespace std;\n\n#define N 5\nint map[5][5] =\n"
  },
  {
    "path": "ebook/code/c/4.3:出现次数超过一半的数字.c",
    "chars": 515,
    "preview": "// 4.3 出现次数超过一半.cpp : 定义控制台应用程序的入口点。\n//\n\n#include \"stdafx.h\"\n#include <iostream>  \nusing namespace std;\n\n//a代表数组,length代"
  },
  {
    "path": "ebook/code/c/4.3:完美洗牌算法.c",
    "chars": 2157,
    "preview": "//解法二\n//2.1、位置置换pefect_shuffle1算法\n// 时间O(n),空间O(n) 数组下标从1开始\nvoid pefect_shuffle1(int *a, int n)\n{\n\tint n2 = n * 2, i, b["
  },
  {
    "path": "ebook/code/c/4.4:最近公共祖先LCA问题.LCAProblem.c",
    "chars": 3360,
    "preview": "/**\n * Copyright (c) 2014 The TAOPP book Authors. All rights reserved.\n * Use of this source code is governed by a BSD-s"
  },
  {
    "path": "ebook/code/c/4.5:打印螺旋矩阵.SpiralMatrix.c",
    "chars": 3117,
    "preview": "/**\n * Copyright (c) 2014 The TAOPP book Authors. All rights reserved.\n * Use of this source code is governed by a BSD-s"
  },
  {
    "path": "ebook/code/c/5.1:最长公共子序列(LCS)问题.c",
    "chars": 2551,
    "preview": "import java.util.Random;  \n\npublic class LCS{  \n    public static void main(String[] args){  \n\n        //设置字符串长度  \n     "
  },
  {
    "path": "ebook/code/c/5.2:最大连续乘积子串.c",
    "chars": 1080,
    "preview": "//解法一\n#include \"stdafx.h\"\n#include <algorithm>\n#include <iostream>\nusing namespace std;\n\ndouble maxProductSubstring(doub"
  },
  {
    "path": "ebook/code/c/5.3:字符串编辑距离.c",
    "chars": 1039,
    "preview": "// 5.3 字符串编辑距离.cpp : 定义控制台应用程序的入口点。\n//\n\n#include \"stdafx.h\"\n#include <iostream>\n#include <algorithm>\nusing namespace std"
  },
  {
    "path": "ebook/code/c/5.4:交替字符串.c",
    "chars": 494,
    "preview": "bool isInterleave(string s1, string s2, string s3)\n{\n\n\tint len1 = s1.size(), len2 = s2.size(), len3 = s3.size();\n\tif (le"
  },
  {
    "path": "ebook/code/c/6.11:最小操作数.c",
    "chars": 5276,
    "preview": "//解法一\n//copyright@caopengcs     \n//updated@July 08/12/2013    \nclass Solution    \n{    \npublic:    \n\t// help 函数负责找到所有的路径"
  },
  {
    "path": "ebook/code/c/6.4:回文判断.c",
    "chars": 1773,
    "preview": "//解法一\n/**  \n *check weather s is a palindrome, n is the length of string s \n *Copyright(C) fairywell 2011 \n */  \nbool Is"
  },
  {
    "path": "ebook/code/c/6.6:跳台阶问题.c",
    "chars": 183,
    "preview": "//解法一\nlong long Fibonacci_Solution1(unsigned int n)\n{\n\tint result[2] = {0, 1, 2};\n\tif (n <= 2)\n\t\treturn result[n];\n\n\tret"
  },
  {
    "path": "ebook/code/c/6.8:第一个只出现一次的字符.c",
    "chars": 1043,
    "preview": "//代码一\n#include <iostream>\nusing namespace std;\n\n//查找第一个只出现一次的字符,第1个程序\n//copyright@ Sorehead && July\n//July、updated,2011."
  },
  {
    "path": "ebook/code/c/6.9:Trie树.c",
    "chars": 2691,
    "preview": "/*\n * Trie树(字典树)\n * liuyang1 2014.06.25\n */\n\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n\n#define CHARSET"
  },
  {
    "path": "ebook/code/c/7.1:搜索引擎热门查询统计.c",
    "chars": 3652,
    "preview": "//copyright@yansha &&July\n//July、updated,2011.05.08\n\n//题目描述:\n//搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的\n//长度为1-255字节。假设目前有"
  },
  {
    "path": "ebook/code/c/7.2:最短摘要的生成.c",
    "chars": 773,
    "preview": "//July、updated,2011.10.21\nint nTargetLen = N + 1;           // 设置目标长度为总长度+1  \nint pBegin = 0;                     // 初始指"
  },
  {
    "path": "ebook/code/c/7.3:倒排索引关键词不重复Hash编码.c",
    "chars": 8836,
    "preview": "//24.4、暴雪的Hash算法\n//函数prepareCryptTable以下的函数生成一个长度为0x500(合10进制数:1280)的cryptTable[0x500]  \nvoid prepareCryptTable()  \n{   "
  },
  {
    "path": "ebook/code/c/7.4:倒排索引关键词 Hash 不重复编码实践.c",
    "chars": 2288,
    "preview": "#include <stdio.h>  \n#include <ctype.h>     //多谢citylove指正。  \n//crytTable[]里面保存的是HashString函数里面将会用到的一些数据,在prepareCryptTa"
  },
  {
    "path": "ebook/code/c/makefile",
    "chars": 224,
    "preview": "CC = gcc\nCPPFLAGS = -Wall\n\nFILE_SUFFIX = c\n\nSRCS := $(wildcard *.$(FILE_SUFFIX))\nEXES := $(patsubst %.$(FILE_SUFFIX),%,$"
  },
  {
    "path": "ebook/code/cpp/1.1:左旋转字符串.cpp",
    "chars": 7765,
    "preview": "#include <iostream>\n\nusing namespace std;\n\n/* brute force */\nvoid leftShiftOne(string &str) \n{\n    int n = str.length();"
  },
  {
    "path": "ebook/code/cpp/2.1:寻找最小的 k 个数.cpp",
    "chars": 2682,
    "preview": "#include <iostream>\n\nusing namespace std;\n\n//获取父节点指针\nint GetParent(int* pArray, int* pLast)\n{\n  if(pLast >= pArray)\n    "
  },
  {
    "path": "ebook/code/cpp/3.1:二分查找实现(Jon Bentley",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "ebook/code/cpp/4.2:完美洗牌算法.cpp",
    "chars": 1530,
    "preview": "//compiled with g++\n#include <iostream>\n#include <vector>\n#include <algorithm>\n#include <iterator>\n#include <cassert>\nus"
  },
  {
    "path": "ebook/code/cpp/7.4:倒排索引关键词 Hash 不重复编码实践.cpp",
    "chars": 2288,
    "preview": "#include <stdio.h>  \n#include <ctype.h>     //多谢citylove指正。  \n//crytTable[]里面保存的是HashString函数里面将会用到的一些数据,在prepareCryptTa"
  },
  {
    "path": "ebook/code/cpp/9.2:海量数据处理之Bit-map详解.cpp",
    "chars": 1240,
    "preview": "//定义每个Byte中有8个Bit位  \n#include <memory.h>  \n#define BYTESIZE 8  \nvoid SetBit(char *p, int posi)  \n{  \n    for(int i=0; i"
  },
  {
    "path": "ebook/code/cpp/chapter04.cpp",
    "chars": 429,
    "preview": "#include <stdio.h>\n#include <assert.h>\n#include <string.h>\n\nchar *mystrcpy(char* dest, const char *src)\n{\n\tassert(dest !"
  },
  {
    "path": "ebook/code/cpp/chapter06.cpp",
    "chars": 1291,
    "preview": "#include <iostream>\n#include <vector>\n\nusing namespace std;\n\nvoid createCounter(vector<int>& counter, int n)\n{\n    vecto"
  },
  {
    "path": "ebook/code/cpp/makefile",
    "chars": 226,
    "preview": "CC = g++\nCPPFLAGS = -Wall\n\nFILE_SUFFIX = cpp\n\nSRCS := $(wildcard *.$(FILE_SUFFIX))\nEXES := $(patsubst %.$(FILE_SUFFIX),%"
  },
  {
    "path": "ebook/code/erlang/1.1:左旋转字符串.erl",
    "chars": 715,
    "preview": "%%%-----------------------------------\n%%% @Module      : july_1_1\n%%% @Author      : hejavac\n%%% @Email       : hejavac"
  },
  {
    "path": "ebook/code/erlang/3.1:二分查找实现.erl",
    "chars": 2202,
    "preview": "%%%--------------------------------------\n%%% @Module  : binary_search\n%%% @Author  : hejavac@gmail\n%%% @Created : 2014."
  },
  {
    "path": "ebook/code/erlang/6.4:回文判断.erl",
    "chars": 1982,
    "preview": "%%%--------------------------------------\n%%% @Module  : ispalindrome\n%%% @Author  : hejavac@gmail.com\n%%% @Created : 20"
  },
  {
    "path": "ebook/code/go/1.1-左旋转字符串.go",
    "chars": 797,
    "preview": "//1.1 左旋转字符串\n//@author leiyonglin <leiyonglin@gmail.com>\n//http://play.golang.org/p/SxiFC1eRsE\n\npackage main\n\nimport (\n\t"
  },
  {
    "path": "ebook/code/go/1.2-字符串是否包含问题.go",
    "chars": 2553,
    "preview": "//1.2 字符串是否包含问题\n//@author leiyonglin <leiyonglin@gmail.com>\n//http://play.golang.org/p/sO4hYrRtYT\n\npackage main\n\nimport "
  },
  {
    "path": "ebook/code/go/1.5-回文判断.go",
    "chars": 835,
    "preview": "//1.5 回文判断\n//@author leiyonglin <leiyonglin@gmail.com>\n//http://play.golang.org/p/K4NyYq-Teo\npackage main\n\nimport (\n\t\"fm"
  },
  {
    "path": "ebook/code/go/2.1-寻找最小的k个数.go",
    "chars": 1834,
    "preview": "//2.1 寻找最小的k个数\n//@author leiyonglin <leiyonglin@gmail.com>\n//http://play.golang.org/p/41xfLFuTYq\n\npackage main\n\nimport ("
  },
  {
    "path": "ebook/code/go/2.2-求数组中给定下标区间内的第K小元素.go",
    "chars": 939,
    "preview": "//2.2 求数组中给定下标区间内的第K小元素\n//@author leiyonglin <leiyonglin@gmail.com>\n//http://play.golang.org/p/eGkDSKGnhq\n\npackage main\n"
  },
  {
    "path": "ebook/code/go/3.2-杨氏矩阵查找.go",
    "chars": 705,
    "preview": "// 3.2 杨氏矩阵查找\n// @author leiyonglin <leiyonglin@gmail.com>\n// http://play.golang.org/p/EcFyPADISb\n\npackage main\n\nimport "
  },
  {
    "path": "ebook/code/go/3.3:出现次数超过一半的数字.go",
    "chars": 741,
    "preview": "package main\n\nimport (\n\t\"fmt\"\n\n//\t\"math\"\n)\n\nfunc findNumberAppearEqualHalf(data []int) int {\n\tvar (\n\t\tc1 = findNumberApp"
  },
  {
    "path": "ebook/code/java/chapter1/1.1:左旋转字符串.java",
    "chars": 4450,
    "preview": "package org.yousharp.julycoding.string;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.yousharp.co"
  },
  {
    "path": "ebook/code/java/chapter1/1.2:字符串包含.java",
    "chars": 1404,
    "preview": "package org.yousharp.julycoding.string;\n\n/**\n * 1.2 字符串包含\n * (july github链接:https://github.com/julycoding/The-Art-Of-Pro"
  },
  {
    "path": "ebook/code/java/chapter1/Chapter1.java",
    "chars": 1414,
    "preview": "class Chapter1 {\n    \n    // Version 1\n    public void leftShiftV1 (char[] s, int m) {\n        while (m > 0) {\n         "
  },
  {
    "path": "ebook/code/java/chapter1/Palindrome.java",
    "chars": 1100,
    "preview": "/**\n * Check weather a string is a palindrome\n * @author WangTaoTheTonic\n */\npublic class Palindrome\n{\n\t// Solution 1, f"
  },
  {
    "path": "ebook/code/java/chapter1/StringToInt",
    "chars": 2183,
    "preview": "/**\n * 将String类型转为Integer类型\n * \n * @author gongyu.wang\n * \n */\npublic class Solution {\n    \tprivate static int radis = 1"
  },
  {
    "path": "ebook/code/java/chapter2/Chapter2.java",
    "chars": 1154,
    "preview": "class Chapter2 {\n    public static void main (String[] args) {\n        System.out.println(\"QuickSort and Compare:\");\n   "
  },
  {
    "path": "ebook/code/java/chapter2/CountAndCompare.java",
    "chars": 1221,
    "preview": "class CountAndCompare implements ICompare {\n    @Override\n    public boolean compare(String longString, String shortStri"
  },
  {
    "path": "ebook/code/java/chapter2/HashTableCompare.java",
    "chars": 744,
    "preview": "class HashTableCompare implements ICompare {\n    @Override\n    public boolean compare(String longString, String shortStr"
  },
  {
    "path": "ebook/code/java/chapter2/ICompare.java",
    "chars": 84,
    "preview": "interface ICompare {\n    public boolean compare(String longStr, String shortStr);\n}\n"
  },
  {
    "path": "ebook/code/java/chapter2/PrimeCompare.java",
    "chars": 891,
    "preview": "import java.math.BigInteger;\n\nclass PrimeCompare implements ICompare {\n    \n    @Override\n    public boolean compare(Str"
  },
  {
    "path": "ebook/code/java/chapter2/SortAndCompare.java",
    "chars": 782,
    "preview": "import java.util.Arrays;\n\nclass SortAndCompare implements ICompare {\n    @Override\n    public boolean compare(String lon"
  },
  {
    "path": "ebook/code/java/chapter2/TopK.java",
    "chars": 1885,
    "preview": "import java.util.Collections;\nimport java.util.List;\n\n/**\n * Select the K least numbers in a List\n * @author WangTaoTheT"
  },
  {
    "path": "ebook/code/java/chapter3/Chapter3.java",
    "chars": 505,
    "preview": "import java.util.Arrays;\n\npublic class Chapter3 {\n\n    public static void main(String[] args) {\n        int[] data = new"
  },
  {
    "path": "ebook/code/java/chapter3/HeapSolution.java",
    "chars": 248,
    "preview": "class HeapSolution implements IFindMinK {\n\n    @Override\n    public int[] findMinK(int[] data, int k) {\n        MaxHeap "
  },
  {
    "path": "ebook/code/java/chapter3/IFindMinK.java",
    "chars": 70,
    "preview": "interface IFindMinK {\n    public int[] findMinK(int[] data, int k);\n}\n"
  },
  {
    "path": "ebook/code/java/chapter3/MaxHeap.java",
    "chars": 1384,
    "preview": "/**\n * a simple max heap with fixed length\n **/\n\nimport java.util.Arrays;\n\npublic class MaxHeap {\n    \n    private int[]"
  },
  {
    "path": "ebook/code/java/chapter4/Chapter4.java",
    "chars": 5323,
    "preview": "import java.util.Arrays;\nimport java.util.HashMap;\n\npublic class Chapter4 {\n\n    // Solution 1. Brute force\n    public P"
  },
  {
    "path": "ebook/code/java/chapter6/Chapter6.java",
    "chars": 934,
    "preview": "public class Chapter6 {\n\n    // Solution 1. factor-array\n    public void findAmicableNumber_1() {\n        int[] sum = ne"
  },
  {
    "path": "ebook/code/js/1.1:左旋转字符串/1.1:左旋转字符串.js",
    "chars": 1420,
    "preview": "/*\n * By Frederick-S\n * 2014-01-22\n */\n\n// 1. 暴力移位法\n\n/*\n * @param {String} s 待左旋转的字符串\n * @param {Number} m 左旋转的位数\n * @ex"
  },
  {
    "path": "ebook/code/js/1.1:左旋转字符串/test.html",
    "chars": 408,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <title>Tests</title>\n    <link rel=\"stylesheet\" href=\"http:"
  },
  {
    "path": "ebook/code/js/1.1:左旋转字符串/tests.js",
    "chars": 813,
    "preview": "// 1. 暴力移位法\ntest('暴力移位法', function () {\n    ok(leftShift1('abcdef', 0) == 'abcdef', 'abcdef 左旋转 0 位变成 abcdef');\n    ok(l"
  },
  {
    "path": "ebook/code/js/1.2:字符串是否包含问题/1.2:字符串是否包含问题.js",
    "chars": 3265,
    "preview": "/*\n * By Frederick-S\n * 2014-01-23\n */\n\n// 1. 暴力轮询\n\n/*\n * @param {String} a 较长的字符串\n * @param {Number} b 较短的字符串\n * @examp"
  },
  {
    "path": "ebook/code/js/1.2:字符串是否包含问题/test.html",
    "chars": 411,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <title>Tests</title>\n    <link rel=\"stylesheet\" href=\"http:"
  },
  {
    "path": "ebook/code/js/1.2:字符串是否包含问题/tests.js",
    "chars": 2095,
    "preview": "// 1. 暴力轮询\ntest('暴力轮询', function () {\n    ok(compare1('ABCDEFGHLMNOPQRS', 'DCGSRQPO') == true, 'ABCDEFGHLMNOPQRS 包含 DCGS"
  },
  {
    "path": "ebook/code/js/2.4:寻找和为定值的两个数/2.4:寻找和为定值的两个数.js",
    "chars": 3030,
    "preview": "/*\n * By Frederick-S\n * 2014-03-08\n */\n\n// 1. 穷举\n\n/*\n * @param {Array} arr 目标数组\n * @param {Number} number 在数组中查找两个数,使得其和"
  },
  {
    "path": "ebook/code/js/2.4:寻找和为定值的两个数/test.html",
    "chars": 412,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <title>Tests</title>\n    <link rel=\"stylesheet\" href=\"http:"
  },
  {
    "path": "ebook/code/js/2.4:寻找和为定值的两个数/tests.js",
    "chars": 1888,
    "preview": "// 1. 穷举\ntest('穷举', function () {\n    ok(solution1([1, 2, 4, 7, 11, 15], 15).toString() == '4,11', '输入: [1, 2, 4, 7, 11,"
  },
  {
    "path": "ebook/code/php/chapter1.php",
    "chars": 1975,
    "preview": "<?php\n\nfunction LeftShiftOne($string){\n    assert(\"is_string('$string')\");\n    $len = mb_strlen($string,'utf-8');\n    re"
  },
  {
    "path": "ebook/code/php/chapter2.php",
    "chars": 3821,
    "preview": "<?php\n/**\n * 解法一、暴力轮询 \n *\n **/\nfunction compare_1($a,$b){\n    assert(\"is_string('$a')\");\n    assert(\"is_string('$b')\");\n"
  },
  {
    "path": "ebook/code/php/chapter3.php",
    "chars": 2499,
    "preview": "<?php\nclass Wildcard{\n    /**\n     * 拼接结果字符串 \n     *\n     **/\n    private static function str_join($a,$b,$lenb){\n       "
  },
  {
    "path": "ebook/code/python/1.1:字符的移动.py",
    "chars": 3159,
    "preview": "# -*- coding: utf-8 -*-\nimport copy\n\n# 整体函数接口说明:\n#\n# Args:\n#   s: 给定需要移位的list\n#   m: 需要移动的位数\n#\n# Returns:\n#   无。直接修改传入的l"
  },
  {
    "path": "ebook/code/python/1.2:字符串是否包含问题.py",
    "chars": 4503,
    "preview": "# coding=utf-8\ndef compare_1(long_string, short_string):\n    \"\"\"\n    code example for section 1.1\n\n    see https://githu"
  },
  {
    "path": "ebook/code/python/1.5:回文判断.py",
    "chars": 1430,
    "preview": "# code example for section 1.5\n# see https://github.com/julycoding/The-Art-Of-Programming-By-July/blob/master/ebook/zh/0"
  },
  {
    "path": "ebook/code/python/1.6:最长回文子串.py",
    "chars": 4197,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n\"\"\"\nTitle: 求最长回文子串\nAuthor: Fred Akalin\nLink: http://www.akalin.cx/longest"
  },
  {
    "path": "ebook/code/python/2.1:寻找最小的k个数.py",
    "chars": 1589,
    "preview": "# -*- coding: utf-8 -*-\n\n# bonus for Python\n# from heapq import nsmallest\n# nsmallest(n, iterable, key=None)\n\n# all exam"
  },
  {
    "path": "ebook/code/python/2.1:寻找最小的k个数_2.py",
    "chars": 495,
    "preview": "import heapq\n\n\nclass topk():\n    # support for dynamic push\n    def __init__(self, k):\n        self.k = k\n        self.h"
  },
  {
    "path": "ebook/code/python/2.3:求解500万以内的亲和数.py",
    "chars": 961,
    "preview": "import math\n\n\ndef prime_list(n):\n    lst = range(0, n + 1)\n    lst[1] = 0\n    thres = int(math.sqrt(n))\n    for i in xra"
  },
  {
    "path": "ebook/code/python/2.3:求解500万以内的亲和数_2.py",
    "chars": 360,
    "preview": "if __name__ == \"__main__\":\n    n = 10000 * 500\n    lst = [1 for i in xrange(n)]\n    # better locality\n    # using + basi"
  },
  {
    "path": "ebook/code/python/2.4:寻找和为定值的两个数.py",
    "chars": 579,
    "preview": "#!/usr/bin/python\n# -*- coding:utf-8 -*-\n\ndef find_sum(array, key):\n    if len(array) > 0:\n        array = sorted(array)"
  },
  {
    "path": "ebook/code/python/2.6:求连续子数组的最大和.py",
    "chars": 705,
    "preview": "# -*- coding: utf-8 -*-\n\n'''\nAuthor: tdoly\n'''\n\n\ndef max_sum(ls):\n    #判断列表\n    if len(ls) > 0:\n        #将列表的第一个元素赋值给res"
  },
  {
    "path": "ebook/code/python/3.1:二分查找实现.py",
    "chars": 397,
    "preview": "def binary_search(lst, n):\n    low, high = 0, len(lst) - 1\n    while low <= high:\n        mid = (low + high) / 2\n       "
  },
  {
    "path": "ebook/code/python/3.2:杨氏矩阵查找.py",
    "chars": 1516,
    "preview": "# -*- coding:utf-8 -*-\ndef young_matrix_1(matrix, key):\n    if len(matrix) == 0 or len(matrix[0]) == 0:\n        return F"
  },
  {
    "path": "ebook/code/python/3.3:出现次数超过一半的数字.py",
    "chars": 543,
    "preview": "# -*- coding:utf-8 -*-\n\n\ndef more_than_half_number(array):\n    if not array:\n        return False\n\n    count = 1\n    val"
  },
  {
    "path": "ebook/code/python/6.5:全排列.py",
    "chars": 168,
    "preview": "import itertools\nif __name__ == \"__main__\":\n    line = raw_input(\"please input some char:\\n\")\n    for i in itertools.per"
  },
  {
    "path": "ebook/code/python/6.6:跳台阶.py",
    "chars": 408,
    "preview": "def fib(n):\n    a, b, p, q = 1, 0, 0, 1\n    while n != 0:\n        if n % 2 == 0:\n            p, q = p * p + q * q, 2 * p"
  },
  {
    "path": "ebook/code/python/6.8:第一个只出现一次等问题.py",
    "chars": 424,
    "preview": "def find_first_unique_char(string):\n    if not string:\n        return None\n    chars = {}\n    for s in string:\n        i"
  },
  {
    "path": "ebook/code/python/6.9:Trie树.py",
    "chars": 1235,
    "preview": "from rcdtype import *\n\nTrieNode = recordtype(\"TrieNode\", [\"Char\", \"Counter\", \"next\"])\n\ndef newTrie():\n    return TrieNod"
  },
  {
    "path": "ebook/code/python/chapter04.py",
    "chars": 751,
    "preview": "def strstr(haystack, needle):\n    return any(\n        all((haystack[i + j] == needle[j] for j in xrange(0, len(needle)))"
  },
  {
    "path": "ebook/code/python/rcdtype.py",
    "chars": 5697,
    "preview": "__all__ = ['recordtype']\n\nimport sys\nfrom textwrap import dedent\nfrom keyword import iskeyword\n\n\ndef recordtype(typename"
  },
  {
    "path": "ebook/code/rebol/1.1:左旋转字符串.reb",
    "chars": 1448,
    "preview": "REBOL [\n\tTitle: \"字符串旋转问题,例如abcdef,左旋2位,变成 cdefab\"\n       Date: 2014-03-30\n       File:  %1.1:左旋转字符串.reb\n       Author: \""
  },
  {
    "path": "ebook/code/rebol/1.2:字符串是否包含问题.reb",
    "chars": 5724,
    "preview": "REBOL [\n       Title: \"判断a字符串是否包含b字符串的字母 假定都没有重复字符出现\"\n       Date: 2014-04-06\n       File:  %1.2:字符串是否包含问题.reb\n       Au"
  },
  {
    "path": "ebook/code/ruby/chapter01.rb",
    "chars": 1144,
    "preview": "#!/usr/bin/env ruby\n# -*- coding: UTF-8 -*-\n\ndef swap(s, i, j)\n  s[i], s[j] = s[j], s[i]\nend\n\ndef left_shift_one(s, i, j"
  },
  {
    "path": "ebook/code/ruby/chapter02.rb",
    "chars": 3259,
    "preview": "#!/usr/bin/env ruby\n# -*- coding: UTF-8 -*-\n\ndef compare_1(long_string, short_string)\n  short_string.each_char{|s| \n    "
  },
  {
    "path": "ebook/code/ruby/chapter03.rb",
    "chars": 283,
    "preview": "#!/usr/bin/env ruby\n# -*- coding: UTF-8 -*-\n\ndef top_minimum(list, k)\n  h = list[0...k]\n  list[k..-1].each{|v|\n    h.eac"
  },
  {
    "path": "ebook/code/ruby/chapter0301.searchTrend.rb",
    "chars": 943,
    "preview": "#!/usr/bin/env ruby\n# -*- coding: UTF-8 -*-\nrequire 'benchmark'\n\ndef create_hash(input)\n  hash = Hash.new(0)\n  File.open"
  },
  {
    "path": "ebook/code/ruby/chapter0302.quickSort.rb",
    "chars": 847,
    "preview": "#!/usr/bin/env ruby\n# -*- coding: UTF-8 -*-\nrequire 'benchmark'\ndef quick_sort_01(list)\n  return [] if list.empty?\n  x, "
  },
  {
    "path": "ebook/code/ruby/chapter04.rb",
    "chars": 1173,
    "preview": "#!/usr/bin/env ruby\n# -*- coding: UTF-8 -*-\nrequire 'benchmark'\nclass String\n  #find sub string start index\n  #String#in"
  },
  {
    "path": "ebook/code/ruby/chapter05.findSum.rb",
    "chars": 2176,
    "preview": "#!/usr/bin/env ruby\n# -*- coding: UTF-8 -*-\nrequire 'benchmark'\n\nclass Array\n  def find_01(sum)\n    new_arr = {}\n    sel"
  },
  {
    "path": "ebook/code/ruby/chapter06.amicableNumber.rb",
    "chars": 423,
    "preview": "#!/usr/bin/env ruby\n# -*- coding: UTF-8 -*-\n\ndef amicable_number max\n  half = max / 2 \n  sum = Array.new(max){1}\n  (2..."
  },
  {
    "path": "ebook/code/ruby/chapter07.findMaxSum.rb",
    "chars": 596,
    "preview": "#!/usr/bin/env ruby\n# -*- coding: UTF-8 -*-\n\ndef max_sum(arr)\n  max, max_sub, sum, sub = arr[0], [arr[0]], 0, [] \n  arr."
  },
  {
    "path": "ebook/code/ruby/chapter16.permutation.rb",
    "chars": 562,
    "preview": "#!/usr/bin/env ruby\n# -*- coding: UTF-8 -*-\ndef permutation_recursive(ar)\n  return [ar] if ar.length == 1\n  permutations"
  },
  {
    "path": "ebook/code/ruby/chapter17.rb",
    "chars": 273,
    "preview": "#!/usr/bin/env ruby\n# -*- coding: UTF-8 -*-\n\ndef fibonacci_solution n\n  return [0, 1, 2][n] if( n <= 2 )\n  fibonacci_sol"
  },
  {
    "path": "ebook/code/ruby/chapter18.rb",
    "chars": 498,
    "preview": "#!/usr/bin/env ruby\n# -*- coding: UTF-8 -*-\n\ndef odd_even(arr)\n  return arr.select{|x| x % 2 != 0 } +  arr.select{|x| x "
  },
  {
    "path": "ebook/code/ruby/chapter19.rb",
    "chars": 94,
    "preview": "#!/usr/bin/env ruby\n# -*- coding: UTF-8 -*-\n# see 'chapter04.rb'\n# String.o_first_count_letter"
  },
  {
    "path": "ebook/code/scheme/chapter01.scm",
    "chars": 293,
    "preview": "#!/usr/bin/guile -s\n!#\n\n(define (leftshift str n)\n    (display \n      (reverse (append (reverse (string->list (substring"
  },
  {
    "path": "ebook/code/scheme/chapter06.scm",
    "chars": 686,
    "preview": "(define (square x) (* x x))\n\n(define (factor n)\n  (define (helper r ret)\n    (if (> (square r) n) ret\n      (cond ((= 0 "
  },
  {
    "path": "ebook/code/scheme/chapter06v2.scm",
    "chars": 877,
    "preview": "#!/usr/bin/guile -s\n!#\n\n;author lmdyyh 3/6/2014\n;compiled with guile,executed the cod using 1m38.903s with array size of"
  },
  {
    "path": "ebook/code/scheme/chapter17.scm",
    "chars": 984,
    "preview": "; SICP ch1 exercise 19\n(define (fib n)\n  (fib-iter 1 0 0 1 n))\n\n(define (fib-iter a b p q count)\n  (cond ((= count 0)   "
  },
  {
    "path": "ebook/code/scheme/chapter25.scm",
    "chars": 460,
    "preview": "#!/usr/bin/guile -s\n!#\n(define (binary-search lst val)\n   (define (helper left right)\n      (if (> left right) (display "
  },
  {
    "path": "ebook/en/01.0.md",
    "chars": 65,
    "preview": "Chapter One - Left Rotating String\n=============================="
  },
  {
    "path": "ebook/en/03.0.md",
    "chars": 5189,
    "preview": "Chapter 3: Find Smallest K Numbers\n==========\n\n## Problem Description\n\nGiven n integers, output the smallest k numbers. "
  },
  {
    "path": "ebook/en/07.0.md",
    "chars": 7062,
    "preview": "Chapter 7: Maximum Subarray Problem\n========\n\n## 1. Introduction\n\nGiven an integer array, which contains positive and ne"
  },
  {
    "path": "ebook/en/11.0.md",
    "chars": 15122,
    "preview": "Chapter 11: Longest Common Subsequence \n===========\n\n## 1. Introduction\nWhat is this so-called longest common subsequenc"
  },
  {
    "path": "ebook/en/25.0.md",
    "chars": 6216,
    "preview": "Chapter 25: Binary Search \n========\n\n## 1.Introduction\n\nJon Bentley: More than 90% programmers are not able to correctly"
  },
  {
    "path": "ebook/en/28.0.md",
    "chars": 13298,
    "preview": "Chapter 28: Largest Product Continuous Substring\n========\n\n## Foreword\n\nThe questions introduced in this chapter and nex"
  },
  {
    "path": "ebook/en/35.0.md",
    "chars": 31747,
    "preview": "Chapter 35:Perfect shuffle algorithm\n========\n\nTopic Details:There is an array of length 2n {a1, a2, a3, ..., an, b1, b2"
  },
  {
    "path": "ebook/en/Readme.md",
    "chars": 690,
    "preview": "#Contents\n\n## Preliminary\n\n## Part I  Data Structures\n* Chapter 1  Feature of Charactors\n - [1.1 - Left Rotating String]"
  },
  {
    "path": "ebook/images/.directory",
    "chars": 86,
    "preview": "[Dolphin]\nSortOrder=1\nSortRole=date\nTimestamp=2014,3,23,15,31,14\nVersion=3\nViewMode=1\n"
  },
  {
    "path": "ebook/images/1/1.1.tex",
    "chars": 378,
    "preview": "\\documentclass[tikz, convert, multi=false]{standalone}\n\\usepackage{amsmath}\n\\usepackage{tikz}\n\\usetikzlibrary{shapes.mul"
  },
  {
    "path": "ebook/images/1/1.2.tex",
    "chars": 379,
    "preview": "\\documentclass[tikz, convert, multi=false]{standalone}\n\\usepackage{amsmath}\n\\usepackage{tikz}\n\\usetikzlibrary{shapes.mul"
  },
  {
    "path": "ebook/images/1/1.3.tex",
    "chars": 380,
    "preview": "\\documentclass[tikz, convert, multi=false]{standalone}\n\\usepackage{amsmath}\n\\usepackage{tikz}\n\\usetikzlibrary{shapes.mul"
  },
  {
    "path": "ebook/images/1/1.4.tex",
    "chars": 378,
    "preview": "\\documentclass[tikz, convert, multi=false]{standalone}\n\\usepackage{amsmath}\n\\usepackage{tikz}\n\\usetikzlibrary{shapes.mul"
  },
  {
    "path": "ebook/images/1/2.1.tex",
    "chars": 401,
    "preview": "\\documentclass[tikz, convert, multi=false]{standalone}\n\\usepackage{amsmath}\n\\usepackage{tikz}\n\\usetikzlibrary{shapes.mul"
  },
  {
    "path": "ebook/images/1/2.2.tex",
    "chars": 402,
    "preview": "\\documentclass[tikz, convert, multi=false]{standalone}\n\\usepackage{amsmath}\n\\usepackage{tikz}\n\\usetikzlibrary{shapes.mul"
  },
  {
    "path": "ebook/images/1/2.3.tex",
    "chars": 401,
    "preview": "\\documentclass[tikz, convert, multi=false]{standalone}\n\\usepackage{amsmath}\n\\usepackage{tikz}\n\\usetikzlibrary{shapes.mul"
  },
  {
    "path": "ebook/images/1/include.tex",
    "chars": 920,
    "preview": "\\tikzset{\n  text node/.style={\n    align=left,\n    text height=1em,text depth=.5em,\n    inner sep=0pt,\n    text width=\\t"
  },
  {
    "path": "ebook/images/3/3.1/.directory",
    "chars": 48,
    "preview": "[Dolphin]\nTimestamp=2014,1,3,16,32,46\nVersion=3\n"
  },
  {
    "path": "ebook/zh/00.01.md",
    "chars": 2816,
    "preview": "# 程序员如何准备面试中的算法 #\n\n## 备战面试中算法的五个步骤 ##\n对于立志进一线互联网公司,同时不满足于一辈子干纯业务应用开发,希望在后端做点事情的同学来说,备战面试中的算法,分为哪几个步骤呢?如下:\n\n### 1、掌握一门编程语"
  },
  {
    "path": "ebook/zh/01.00.md",
    "chars": 272,
    "preview": "## 本章导读\n\n字符串相关的问题在各大互联网公司笔试面试中出现的频率极高,比如微软经典的单词翻转题:输入“I am a student.”,则输出“student. a am I”。\n\n本章重点介绍6个经典的字符串问题,分别是旋转字符串、"
  },
  {
    "path": "ebook/zh/01.01.md",
    "chars": 2122,
    "preview": "## 1.1 旋转字符串\n\n### 题目描述\n\n给定一个字符串,要求把字符串前面的若干个字符移动到字符串的尾部,如把字符串“abcdef”前面的2个字符'a'和'b'移动到字符串的尾部,使得原字符串变成字符串“cdefab”。请写一个函数完"
  },
  {
    "path": "ebook/zh/01.02.md",
    "chars": 3404,
    "preview": "# 字符串包含\n\n## 题目描述\n\n给定两个分别由字母组成的字符串A和字符串B,字符串B的长度比字符串A短。请问,如何最快地判断字符串B中所有字母是否都在字符串A里?\n\n为了简单起见,我们规定输入的字符串只包含大写英文字母,请实现函数boo"
  },
  {
    "path": "ebook/zh/01.03.md",
    "chars": 3583,
    "preview": "# 字符串转换成整数\n\n## 题目描述\n输入一个由数字组成的字符串,把它转换成整数并输出。例如:输入字符串\"123\",输出整数123。\n\n给定函数原型`int StrToInt(const char *str)` ,实现字符串转换成整数的功"
  },
  {
    "path": "ebook/zh/01.04.md",
    "chars": 1479,
    "preview": "#回文判断\n\n\n## 题目描述\n\n回文,英文palindrome,指一个顺着读和反过来读都一样的字符串,比如madam、我爱我,这样的短句在智力性、趣味性和艺术性上都颇有特色,中国历史上还有很多有趣的回文诗。\n\n那么,我们的第一个问题就是:"
  },
  {
    "path": "ebook/zh/01.05.md",
    "chars": 2931,
    "preview": "## 最长回文子串\n\n### 题目描述\n给定一个字符串,求它的最长回文子串的长度。\n\n### 分析与解法\n最容易想到的办法是枚举所有的子串,分别判断其是否为回文。这个思路初看起来是正确的,但却做了很多无用功,如果一个长的子串包含另一个短一些"
  },
  {
    "path": "ebook/zh/01.06.md",
    "chars": 3222,
    "preview": "## 字符串的全排列\n\n### 题目描述\n\n输入一个字符串,打印出该字符串中字符的所有排列。\n\n例如输入字符串abc,则输出由字符a、b、c 所能排列出来的所有字符串\n\nabc、acb、bac、bca、cab 和 cba。\n\n### 分析与"
  },
  {
    "path": "ebook/zh/01.10.md",
    "chars": 5686,
    "preview": "## 本章字符串和链表的习题\n\n**1、第一个只出现一次的字符**\n\n在一个字符串中找到第一个只出现一次的字符。如输入abaccdeff,则输出b。\n\n**2、对称子字符串的最大长度**\n\n输入一个字符串,输出该字符串中对称的子字符串的最大"
  },
  {
    "path": "ebook/zh/02.00.md",
    "chars": 440,
    "preview": "##本章导读\n笔试和面试中,除了字符串,另一类出现频率极高的问题便是与数组相关的问题。在阅读完第1章和本第二章后,读者会慢慢了解到解决面试编程题的有几种常用思路。首先一般考虑“万能的”暴力穷举(递归、回溯),如求n个数的全排列或八皇后(N皇"
  },
  {
    "path": "ebook/zh/02.01.md",
    "chars": 2837,
    "preview": "# 寻找最小的k个数\n\n\n## 题目描述\n\n输入n个整数,输出其中最小的k个。  \n\n## 分析与解法\n### 解法一\n\n要求一个序列中最小的k个数,按照惯有的思维方式,则是先对这个序列从小到大排序,然后输出前面的最小的k个数。\n\n至于选取"
  },
  {
    "path": "ebook/zh/02.02.md",
    "chars": 3135,
    "preview": "# 寻找和为定值的两个数\n\n## 题目描述\n\n输入一个数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。\n\n要求时间复杂度是O(N)。如果有多对数字的和等于输入的数字,输出任意一对即可。\n\n例如输入数组1、2、4、7、1"
  },
  {
    "path": "ebook/zh/02.03.md",
    "chars": 4018,
    "preview": "# 寻找和为定值的多个数\n\n## 题目描述\n\n输入两个整数n和sum,从数列1,2,3.......n 中随意取几个数,使其和等于sum,要求将其中所有的可能组合列出来。\n\n## 分析与解法\n### 解法一\n注意到取n,和不取n个区别即可,"
  },
  {
    "path": "ebook/zh/02.04.md",
    "chars": 2204,
    "preview": "# 最大连续子数组和\n\n## 题目描述\n\n输入一个整形数组,数组里有正数也有负数。数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。\n求所有子数组的和的最大值,要求时间复杂度为O(n)。\n\n例如输入的数组为`1, -2, 3,"
  },
  {
    "path": "ebook/zh/02.05.md",
    "chars": 1964,
    "preview": "## 跳台阶问题\n\n\n### 题目描述\n一个台阶总共有n 级,如果一次可以跳1 级,也可以跳2 级。\n\n求总共有多少总跳法,并分析算法的时间复杂度。\n\n\n### 分析与解法\n\n#### 解法一\n首先考虑最简单的情况。如果只有1级台阶,那显然"
  },
  {
    "path": "ebook/zh/02.06.md",
    "chars": 3355,
    "preview": "#奇偶调序\n\n## 题目描述\n输入一个整数数组,调整数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。要求时间复杂度为O(n)。\n\n### 分析与解法\n\n最容易想到的办法是从头扫描这个数组,每碰到一个偶数,拿出这"
  },
  {
    "path": "ebook/zh/02.07.md",
    "chars": 1760,
    "preview": "# 荷兰国旗\n\n\n### 题目描述\n\n拿破仑席卷欧洲大陆之后,代表自由,平等,博爱的竖色三色旗也风靡一时。荷兰国旗就是一面三色旗(只不过是横向的),自上而下为红白蓝三色。\n\n![img](../images/41~42/41.1.jpg)\n"
  },
  {
    "path": "ebook/zh/02.08.md",
    "chars": 2279,
    "preview": "# 矩阵相乘\n\n## 题目描述\n\n请编程实现矩阵乘法,并考虑当矩阵规模较大时的优化方法。\n\n## 分析与解法\n\n根据wikipedia上的介绍:两个矩阵的乘法仅当第一个矩阵A的行数和另一个矩阵B的列数相等时才能定义。如A是m×n矩阵,B是n"
  },
  {
    "path": "ebook/zh/02.09.md",
    "chars": 12523,
    "preview": "#完美洗牌算法\n\n## 题目详情\n\n有个长度为2n的数组{a1,a2,a3,...,an,b1,b2,b3,...,bn},希望排序后{a1,b1,a2,b2,....,an,bn},请考虑有无时间复杂度o(n),空间复杂度0(1)的解法。"
  },
  {
    "path": "ebook/zh/02.10.md",
    "chars": 3103,
    "preview": "# K个最小和 (UVA 11997 K Smallest Sums)\n\n### 题目大意:\n\nYou're given k arrays, each array has k integers. There are k^k ways to "
  },
  {
    "path": "ebook/zh/02.15.md",
    "chars": 9823,
    "preview": "## 本章数组和队列的习题\n\n**1、不用除法运算**\n\n\n两个数组a[N],b[N],其中A[N]的各个元素值已知,现给b[i]赋值,b[i] = a[0]*a[1]*a[2]...*a[N-1]/a[i];\n要求:\n - 1.不准用除法"
  },
  {
    "path": "ebook/zh/03.00.md",
    "chars": 642,
    "preview": "## 本章导读\n\n想要更好地理解红黑树,可以先理解二叉查找树和2-3树。为何呢?首先,二叉查找树中的结点是2-结点(一个键两条链),引入3-结点(两个键三条链),即成2-3树;然后将2-3树中3-结点分解,即成红黑树,故结合二叉查找树易查找"
  },
  {
    "path": "ebook/zh/03.01.md",
    "chars": 13556,
    "preview": "# 教你透彻了解红黑树\n\n\n## 二叉查找树\n\n由于红黑树本质上就是一棵二叉查找树,所以在了解红黑树之前,咱们先来看下二叉查找树。\n\n二叉查找树(Binary Search Tree),也称有序二叉树(ordered binary tree"
  },
  {
    "path": "ebook/zh/03.02.md",
    "chars": 11580,
    "preview": "## B树\n\n#### 1.前言:\n\n动态查找树主要有:二叉查找树(Binary Search Tree),平衡二叉查找树(Balanced Binary Search Tree),[红黑树](http://blog.csdn.net/v_"
  },
  {
    "path": "ebook/zh/03.03.md",
    "chars": 11009,
    "preview": "# 最近公共祖先LCA问题\n\n## 问题描述\n\n求有根树的任意两个节点的最近公共祖先。\n\n## 分析与解法\n\n解答这个问题之前,咱们得先搞清楚到底什么是最近公共祖先。最近公共祖先简称LCA(Lowest Common Ancestor),所"
  },
  {
    "path": "ebook/zh/03.05.md",
    "chars": 8767,
    "preview": "## R树:处理空间存储问题\n\n#### R树简介\n\n984年,加州大学伯克利分校的Guttman发表了一篇题为“R-trees: a dynamic index structure for spatial searching”的论文,向世"
  },
  {
    "path": "ebook/zh/03.10.md",
    "chars": 4265,
    "preview": "## 本章堆栈树图相关的习题\n\n**1、附近地点搜索**\n\n找一个点集中与给定点距离最近的点,同时,给定的二维点集都是固定的,查询可能有很多次,例如,坐标(39.91, 116.37)附近500米内有什么餐馆,那么让你来设计,该怎么做?\n\n"
  },
  {
    "path": "ebook/zh/04.01.md",
    "chars": 1900,
    "preview": "## 有序数组的查找\n\n### 题目描述\n\n给定一个有序的数组,查找某个数是否在数组中,请编程实现。\n\n### 分析与解法\n\n一看到数组本身已经有序,我想你可能反应出了要用二分查找,毕竟二分查找的适用条件就是有序的。那什么是二分查找呢?\n\n"
  },
  {
    "path": "ebook/zh/04.02.md",
    "chars": 1205,
    "preview": "# 行列递增矩阵的查找\n\n## 题目描述\n在一个m行n列二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。\n\n例如下面的二维数组就"
  },
  {
    "path": "ebook/zh/04.03.md",
    "chars": 2833,
    "preview": "# 出现次数超过一半的数字\n\n\n## 题目描述\n\n题目:数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字。\n\n\n## 分析与解法\n一个数组中有很多数,现在我们要找出其中那个出现次数超过总数一半的数字,怎么找呢?大凡当我们碰到某一"
  },
  {
    "path": "ebook/zh/05.00.md",
    "chars": 361,
    "preview": "## 本章导读\n \n学习一个算法,可分为3个步骤:首先了解算法本身解决什么问题,然后学习它的解决策略,最后了解某些相似算法之间的联系。例如图算法中,\n\n- 广搜是一层一层往外遍历,寻找最短路径,其策略是采取队列的方法。\n- 最小生成树是最小"
  },
  {
    "path": "ebook/zh/05.01.md",
    "chars": 1828,
    "preview": "## 最大连续乘积子串\n\n### 题目描述\n给一个浮点数序列,取最大乘积连续子串的值,例如 -2.5,4,0,3,0.5,8,-1,则取出的最大乘积连续子串为3,0.5,8。也就是说,上述数组中,3 0.5 8这3个数的乘积3*0.5*8="
  },
  {
    "path": "ebook/zh/05.02.md",
    "chars": 3147,
    "preview": "# 字符串编辑距离\n\n## 题目描述\n\n给定一个源串和目标串,能够对源串进行如下操作:  \n1. 在给定位置上插入一个字符  \n2. 替换任意字符  \n3. 删除任意字符  \n\n写一个程序,返回最小操作数,使得对源串进行这些操作后等于目标串"
  },
  {
    "path": "ebook/zh/05.03.md",
    "chars": 5923,
    "preview": "# 格子取数问题\n\n\n## 题目描述\n有n\\*n个格子,每个格子里有正数或者0,从最左上角往最右下角走,只能向下和向右,一共走两次(即从左上角走到右下角走两趟),把所有经过的格子的数加起来,求最大值SUM,且两次如果经过同一个格子,则最后总"
  },
  {
    "path": "ebook/zh/05.04.md",
    "chars": 1177,
    "preview": "## 交替字符串\n\n### 题目描述\n输入三个字符串s1、s2和s3,判断第三个字符串s3是否由前两个字符串s1和s2交错而成,即不改变s1和s2中各个字符原有的相对顺序,例如当s1 = “aabcc”,s2 = “dbbca”,s3 = "
  },
  {
    "path": "ebook/zh/05.06.md",
    "chars": 865,
    "preview": "## 最长递增子序列\n\n### 题目描述\n\n给定一个长度为N的数组a0,a1,a2...,an-1,找出一个最长的单调递增子序列(注:递增的意思是对于任意的i<j,都满足ai<aj,此外子序列的意思是不要求连续,顺序不乱即可)。例如:给定一"
  },
  {
    "path": "ebook/zh/05.10.md",
    "chars": 1396,
    "preview": "## 本章动态规划的习题\n\n##### 1.子序列个数\n\n子序列的定义:对于一个序列a=a[1],a[2],......a[n],则非空序列a'=a[p1],a[p2]......a[pm]为a的一个子序列\n其中1<=p1<p2<....."
  },
  {
    "path": "ebook/zh/06.00.md",
    "chars": 587,
    "preview": "## 本章导读\n\n所谓海量数据处理,是指基于海量数据的存储、处理、和操作。正因为数据量太大,所以导致要么无法在较短时间内迅速解决,要么无法一次性装入内存。\n\n事实上,针对时间问题,可以采用巧妙的算法搭配合适的数据结构(如布隆过滤器、哈希、位"
  },
  {
    "path": "ebook/zh/06.01.md",
    "chars": 1775,
    "preview": "# 关联式容器\n\n一般来说,STL容器分为:\n\n - 序列式容器(vector/list/deque/stack/queue/heap),和关联式容器。\n- 其中,关联式容器又分为set(集合)和map(映射表)两大类,以及这两大类的衍生体"
  },
  {
    "path": "ebook/zh/06.02.md",
    "chars": 5647,
    "preview": "## 分而治之\n\n### 方法介绍\n\n对于海量数据而言,由于无法一次性装进内存处理,导致我们不得不把海量的数据通过hash映射分割成相应的小块数据,然后再针对各个小块数据通过hash_map进行统计或其它操作。\n\n那什么是hash映射呢?简"
  },
  {
    "path": "ebook/zh/06.03.md",
    "chars": 3808,
    "preview": "# simhash算法\n\n## 方法介绍\n\n### 背景\n\n如果某一天,面试官问你如何设计一个比较两篇文章相似度的算法?可能你会回答几个比较传统点的思路:\n - 一种方案是先将两篇文章分别进行分词,得到一系列特征向量,然后计算特征向量之间的"
  },
  {
    "path": "ebook/zh/06.04.md",
    "chars": 3174,
    "preview": "# 外排序\n\n## 方法介绍\n\n所谓外排序,顾名思义,即是在内存外面的排序,因为当要处理的数据量很大,而不能一次装入内存时,此时只能放在读写较慢的外存储器(通常是硬盘)上。\n\n外排序通常采用的是一种“排序-归并”的策略。\n- 在排序阶段,先"
  },
  {
    "path": "ebook/zh/06.05.md",
    "chars": 1869,
    "preview": "# 分布式处理之MapReduce\n\n## 方法介绍\n\nMapReduce是一种计算模型,简单的说就是将大批量的工作(数据)分解(MAP)执行,然后再将结果合并成最终结果(REDUCE)。这样做的好处是可以在任务被分解后,可以通过大量机器进"
  },
  {
    "path": "ebook/zh/06.06.md",
    "chars": 573,
    "preview": "# 多层划分\n\n## 方法介绍\n\n多层划分法,本质上还是分而治之的思想,因为元素范围很大,不能利用直接寻址表,所以通过多次划分,逐步确定范围,然后最后在一个可以接受的范围内进行。\n\n\n## 问题实例\n\n**1、2.5亿个整数中找出不重复的整"
  },
  {
    "path": "ebook/zh/06.07.md",
    "chars": 2463,
    "preview": "# Bitmap\n\n## 方法介绍\n### 什么是Bit-map\n所谓的Bit-map就是用一个bit位来标记某个元素对应的Value, 而Key即是该元素。由于采用了Bit为单位来存储数据,因此在存储空间方面,可以大大节省。\n\n来看一个具"
  },
  {
    "path": "ebook/zh/06.08.md",
    "chars": 4941,
    "preview": "# Bloom Filter\n\n## 方法介绍\n\n### 一、什么是Bloom Filter\n\nBloom Filter,被译作称布隆过滤器,是一种空间效率很高的随机数据结构,Bloom filter可以看做是对bit-map的扩展,它的原"
  },
  {
    "path": "ebook/zh/06.09.md",
    "chars": 2147,
    "preview": "# Trie树(字典树)\n\n## 方法介绍\n\n### 1.1、什么是Trie树\n\nTrie树,即字典树,又称单词查找树或键树,是一种树形结构。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。"
  },
  {
    "path": "ebook/zh/06.10.md",
    "chars": 72,
    "preview": "# 数据库\n\n## 方法介绍\n\n当遇到大数据量的增删改查时,一般把数据装进数据库中,从而利用数据的设计实现方法,对海量数据的增删改查进行处理。\n"
  },
  {
    "path": "ebook/zh/06.11.md",
    "chars": 577,
    "preview": "# 倒排索引(Inverted index)\n\n## 方法介绍\n\n倒排索引是一种索引方法,被用来存储在全文搜索下某个单词在一个文档或者一组文档中的存储位置的映射,常被应用于搜索引擎和关键字查询的问题中。\n\n以英文为例,下面是要被索引的文本:"
  },
  {
    "path": "ebook/zh/06.15.md",
    "chars": 2444,
    "preview": "## 本章海量数据的习题\n\n**1**\n有100W个关键字,长度小于等于50字节。用高效的算法找出top10的热词,并对内存的占用不超过1MB。\n\n提示:老题,与caopengcs讨论后,得出具体思路为:\n - 先把100W个关键字hash"
  }
]

// ... and 28 more files (download for full content)

About this extraction

This page contains the full source code of the julycoding/The-Art-Of-Programming-By-July-2nd GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 228 files (11.1 MB), approximately 361.5k tokens, and a symbol index with 417 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!