七、查找
7.1 线性查找(顺序查找)
线性查找就是从前向后或者从后向前依次查找
7.2 二分查找(折半查找)
注意:二分法必须保证原数组是有序的
实现思路:
首先要明确二分查找需要在有序数组中进行
借用递归实现,明确没有找到的退出条件是right<left时进行退出递归
首先定义两个变量left和right 分别指向最左侧和最右侧下标,然后去下标中间值跟需要查找的数进行比较
如果小于比较值就进行右递归,将left指向 mid+1 (这里数一下为什么是mid+1 因为你找到了mid发现不是你要找的值,所以直接跳过这个值就好) ;如果大于这个mid就进行做递归
在最开始要声明递归没找到的退出的条件是 left >right
如果找到了就返回mid
<span style="background-color:#333333"><span style="color:#da924a">/**</span> <span style="color:#da924a">* @param list 传入的原数组</span> <span style="color:#da924a">* @param left 查找的起始位置</span> <span style="color:#da924a">* @param right 查找的终止位置</span> <span style="color:#da924a">* @param aim 查找的目标值</span> <span style="color:#da924a">*/</span> <span style="color:#c88fd0">public</span> <span style="color:#1cc685">void</span> <span style="color:#8d8df0">binarySearch</span>(<span style="color:#1cc685">int</span>[] <span style="color:#b8bfc6">list</span>, <span style="color:#1cc685">int</span> <span style="color:#b8bfc6">left</span>, <span style="color:#1cc685">int</span> <span style="color:#b8bfc6">right</span>, <span style="color:#1cc685">int</span> <span style="color:#b8bfc6">aim</span>) { <span style="color:#da924a">// 首先声明递归没找到目标值退出条件</span> <span style="color:#c88fd0">if</span> (<span style="color:#b8bfc6">left</span> <span style="color:#b8bfc6">></span> <span style="color:#b8bfc6">right</span>) { <span style="color:#b8bfc6">System</span>.<span style="color:#b8bfc6">out</span>.<span style="color:#b8bfc6">println</span>(<span style="color:#d26b6b">"没找到,退出"</span>); <span style="color:#c88fd0">return</span>; } <span style="color:#1cc685">int</span> <span style="color:#b8bfc6">mid</span> <span style="color:#b8bfc6">=</span> (<span style="color:#b8bfc6">right</span> <span style="color:#b8bfc6">+</span> <span style="color:#b8bfc6">left</span>) <span style="color:#b8bfc6">/</span> <span style="color:#64ab8f">2</span>;<span style="color:#da924a">//中间位置</span> <span style="color:#1cc685">int</span> <span style="color:#b8bfc6">midValue</span> <span style="color:#b8bfc6">=</span> <span style="color:#b8bfc6">list</span>[<span style="color:#b8bfc6">mid</span>];<span style="color:#da924a">//中间值</span> <span style="color:#c88fd0">if</span> (<span style="color:#b8bfc6">midValue</span> <span style="color:#b8bfc6">></span> <span style="color:#b8bfc6">aim</span>) {<span style="color:#da924a">//左递归</span> <span style="color:#b8bfc6">binarySearch</span>(<span style="color:#b8bfc6">list</span>, <span style="color:#b8bfc6">left</span>, <span style="color:#b8bfc6">mid</span> <span style="color:#b8bfc6">-</span> <span style="color:#64ab8f">1</span>, <span style="color:#b8bfc6">aim</span>); } <span style="color:#c88fd0">else</span> <span style="color:#c88fd0">if</span> (<span style="color:#b8bfc6">midValue</span> <span style="color:#b8bfc6"><</span> <span style="color:#b8bfc6">aim</span>) {<span style="color:#da924a">//右递归</span> <span style="color:#b8bfc6">binarySearch</span>(<span style="color:#b8bfc6">list</span>, <span style="color:#b8bfc6">mid</span> <span style="color:#b8bfc6">+</span> <span style="color:#64ab8f">1</span>, <span style="color:#b8bfc6">right</span>, <span style="color:#b8bfc6">aim</span>); } <span style="color:#c88fd0">else</span> {<span style="color:#da924a">//找到了</span> <span style="color:#b8bfc6">System</span>.<span style="color:#b8bfc6">out</span>.<span style="color:#b8bfc6">println</span>(<span style="color:#d26b6b">"找到了,下标为:"</span> <span style="color:#b8bfc6">+</span> <span style="color:#b8bfc6">mid</span>); <span style="color:#c88fd0">return</span>; } } </span>
拓展: 如果想要找到所有符合要求的值就需要在返回mid前进行判断,在mid左右两侧进行寻找有没有符合要求的值,最终封装到一个List中进行返回。
<span style="background-color:#333333"> <span style="color:#da924a">/**</span> <span style="color:#da924a">* @param list 传入的原数组</span> <span style="color:#da924a">* @param left 查找的起始位置</span> <span style="color:#da924a">* @param right 查找的终止位置</span> <span style="color:#da924a">* @param aim 查找的目标值</span> <span style="color:#da924a">* 拓展,找到所有符合要求的值</span> <span style="color:#da924a">*/</span> <span style="color:#c88fd0">public</span> <span style="color:#1cc685">void</span> <span style="color:#8d8df0">binarySearch</span>(<span style="color:#1cc685">int</span>[] <span style="color:#b8bfc6">list</span>, <span style="color:#1cc685">int</span> <span style="color:#b8bfc6">left</span>, <span style="color:#1cc685">int</span> <span style="color:#b8bfc6">right</span>, <span style="color:#1cc685">int</span> <span style="color:#b8bfc6">aim</span>) { <span style="color:#da924a">// 首先声明递归没找到目标值退出条件</span> <span style="color:#c88fd0">if</span> (<span style="color:#b8bfc6">left</span> <span style="color:#b8bfc6">></span> <span style="color:#b8bfc6">right</span>) { <span style="color:#b8bfc6">System</span>.<span style="color:#b8bfc6">out</span>.<span style="color:#b8bfc6">println</span>(<span style="color:#d26b6b">"没找到,退出"</span>); <span style="color:#c88fd0">return</span>; } <span style="color:#1cc685">int</span> <span style="color:#b8bfc6">mid</span> <span style="color:#b8bfc6">=</span> (<span style="color:#b8bfc6">right</span> <span style="color:#b8bfc6">+</span> <span style="color:#b8bfc6">left</span>) <span style="color:#b8bfc6">/</span> <span style="color:#64ab8f">2</span>;<span style="color:#da924a">//中间位置</span> <span style="color:#1cc685">int</span> <span style="color:#b8bfc6">midValue</span> <span style="color:#b8bfc6">=</span> <span style="color:#b8bfc6">list</span>[<span style="color:#b8bfc6">mid</span>];<span style="color:#da924a">//中间值</span> <span style="color:#c88fd0">if</span> (<span style="color:#b8bfc6">midValue</span> <span style="color:#b8bfc6">></span> <span style="color:#b8bfc6">aim</span>) {<span style="color:#da924a">//左递归</span> <span style="color:#b8bfc6">binarySearch</span>(<span style="color:#b8bfc6">list</span>, <span style="color:#b8bfc6">left</span>, <span style="color:#b8bfc6">mid</span> <span style="color:#b8bfc6">-</span> <span style="color:#64ab8f">1</span>, <span style="color:#b8bfc6">aim</span>); } <span style="color:#c88fd0">else</span> <span style="color:#c88fd0">if</span> (<span style="color:#b8bfc6">midValue</span> <span style="color:#b8bfc6"><</span> <span style="color:#b8bfc6">aim</span>) {<span style="color:#da924a">//右递归</span> <span style="color:#b8bfc6">binarySearch</span>(<span style="color:#b8bfc6">list</span>, <span style="color:#b8bfc6">mid</span> <span style="color:#b8bfc6">+</span> <span style="color:#64ab8f">1</span>, <span style="color:#b8bfc6">right</span>, <span style="color:#b8bfc6">aim</span>); } <span style="color:#c88fd0">else</span> {<span style="color:#da924a">//找到了</span> <span style="color:#da924a">// 找到所有符合要求的只需要在这一步寻找,不要急着返回</span> <span style="color:#b8bfc6">ArrayList</span><span style="color:#b8bfc6"><</span><span style="color:#1cc685">Object</span><span style="color:#b8bfc6">></span> <span style="color:#b8bfc6">objects</span> <span style="color:#b8bfc6">=</span> <span style="color:#c88fd0">new</span> <span style="color:#b8bfc6">ArrayList</span><span style="color:#b8bfc6"><></span>(); <span style="color:#da924a">// 在左侧寻找有没有符合要求的</span> <span style="color:#1cc685">int</span> <span style="color:#b8bfc6">temp</span> <span style="color:#b8bfc6">=</span> <span style="color:#b8bfc6">mid</span> <span style="color:#b8bfc6">-</span> <span style="color:#64ab8f">1</span>; <span style="color:#c88fd0">while</span> (<span style="color:#b8bfc6">temp</span> <span style="color:#b8bfc6">></span> <span style="color:#64ab8f">0</span> <span style="color:#b8bfc6">&&</span> <span style="color:#b8bfc6">list</span>[<span style="color:#b8bfc6">temp</span>] <span style="color:#b8bfc6">==</span> <span style="color:#b8bfc6">aim</span>) { <span style="color:#b8bfc6">objects</span>.<span style="color:#b8bfc6">add</span>(<span style="color:#b8bfc6">temp</span>); <span style="color:#b8bfc6">temp</span> <span style="color:#b8bfc6">-=</span> <span style="color:#64ab8f">1</span>; } <span style="color:#da924a">// 将找到的中间值添加进去</span> <span style="color:#b8bfc6">objects</span>.<span style="color:#b8bfc6">add</span>(<span style="color:#b8bfc6">mid</span>); <span style="color:#da924a">// 在右侧寻找</span> <span style="color:#b8bfc6">temp</span> <span style="color:#b8bfc6">=</span> <span style="color:#b8bfc6">mid</span> <span style="color:#b8bfc6">+</span> <span style="color:#64ab8f">1</span>; <span style="color:#c88fd0">while</span> (<span style="color:#b8bfc6">temp</span> <span style="color:#b8bfc6"><</span> <span style="color:#b8bfc6">list</span>.<span style="color:#b8bfc6">length</span> <span style="color:#b8bfc6">&&</span> <span style="color:#b8bfc6">list</span>[<span style="color:#b8bfc6">temp</span>] <span style="color:#b8bfc6">==</span> <span style="color:#b8bfc6">aim</span>) { <span style="color:#b8bfc6">objects</span>.<span style="color:#b8bfc6">add</span>(<span style="color:#b8bfc6">temp</span>); <span style="color:#b8bfc6">temp</span> <span style="color:#b8bfc6">+=</span> <span style="color:#64ab8f">1</span>; } <span style="color:#b8bfc6">System</span>.<span style="color:#b8bfc6">out</span>.<span style="color:#b8bfc6">println</span>(<span style="color:#d26b6b">"找到了,下标为:"</span> <span style="color:#b8bfc6">+</span> <span style="color:#b8bfc6">objects</span>); <span style="color:#c88fd0">return</span>; } } </span>
7.3 插值查找(基于二分查找)
插值查找只是对二分查找的寻找mid的公式进行了一个优化,将其公式变为了自适应的
-
二分查找中间值公式:(left + right)/ 2
-
插值查找的中间值公式: left + (right - left)* ( aimValue - list[left] )/ ( list[right] - list[left] )
-
注意这个条件不能少:
list[left] > aimValue || list[right] < aimValue
注意:在进行插值查找时其递归退出条件必须加上新的,因为当查找目标值太大而不再原数组中时此时mid就可能会越界
(1)对于数据量较大,关键字分布比较均匀的查找表来说,采用插值查找时速度较快。 (2)在关键字分布不均匀的情况下,插值查找不一定比折半查找好。
<span style="background-color:#333333"><span style="color:#b8bfc6"> <span style="color:#da924a">/**</span>
<span style="color:#da924a">*</span>
<span style="color:#da924a">* @param list 原数组</span>
<span style="color:#da924a">* @param left 开始左侧下标</span>
<span style="color:#da924a">* @param right 开始右侧下标</span>
<span style="color:#da924a">* @param aimValue 查找的目标值</span>
<span style="color:#da924a">*</span>
<span style="color:#da924a">* 求中间值公式:mid = left + ( right - left) * (aimValue - list[left]) / (list[right] - list[left])</span>
<span style="color:#da924a">*/</span>
<span style="color:#c88fd0">public</span> <span style="color:#1cc685">void</span> <span style="color:#8d8df0">interpolationSearch</span>(<span style="color:#1cc685">int</span> []<span style="color:#b8bfc6">list</span>,<span style="color:#1cc685">int</span> <span style="color:#b8bfc6">left</span>,<span style="color:#1cc685">int</span> <span style="color:#b8bfc6">right</span>,<span style="color:#1cc685">int</span> <span style="color:#b8bfc6">aimValue</span>){
<span style="color:#b8bfc6">System</span>.<span style="color:#b8bfc6">out</span>.<span style="color:#b8bfc6">println</span>(<span style="color:#d26b6b">"循环次数"</span>);
<span style="color:#da924a">// 递归退出条件</span>
<span style="color:#da924a">// list[left] > aimValue || list[right] < aimValue 这个判断条件必须加,因为防止查找目标值过大导致mid过大,会出现数组下标越界</span>
<span style="color:#c88fd0">if</span>(<span style="color:#b8bfc6">left</span> <span style="color:#b8bfc6">></span> <span style="color:#b8bfc6">right</span> <span style="color:#b8bfc6">||</span> <span style="color:#b8bfc6">list</span>[<span style="color:#b8bfc6">left</span>] <span style="color:#b8bfc6">></span> <span style="color:#b8bfc6">aimValue</span> <span style="color:#b8bfc6">||</span> <span style="color:#b8bfc6">list</span>[<span style="color:#b8bfc6">right</span>] <span style="color:#b8bfc6"><</span> <span style="color:#b8bfc6">aimValue</span>){
<span style="color:#b8bfc6">System</span>.<span style="color:#b8bfc6">out</span>.<span style="color:#b8bfc6">println</span>(<span style="color:#d26b6b">"找不到目标值,退出"</span>);
<span style="color:#c88fd0">return</span>;
}
<span style="color:#1cc685">int</span> <span style="color:#b8bfc6">mid</span> <span style="color:#b8bfc6">=</span> <span style="color:#b8bfc6">left</span> <span style="color:#b8bfc6">+</span> (<span style="color:#b8bfc6">right</span> <span style="color:#b8bfc6">-</span> <span style="color:#b8bfc6">left</span>)<span style="color:#b8bfc6">*</span> (<span style="color:#b8bfc6">aimValue</span> <span style="color:#b8bfc6">-</span> <span style="color:#b8bfc6">list</span>[<span style="color:#b8bfc6">left</span>]) <span style="color:#b8bfc6">/</span> (<span style="color:#b8bfc6">list</span>[<span style="color:#b8bfc6">right</span>] <span style="color:#b8bfc6">-</span> <span style="color:#b8bfc6">list</span>[<span style="color:#b8bfc6">left</span>]);
<span style="color:#c88fd0">if</span> (<span style="color:#b8bfc6">list</span>[<span style="color:#b8bfc6">mid</span>] <span style="color:#b8bfc6">></span> <span style="color:#b8bfc6">aimValue</span>){<span style="color:#da924a">//左递归</span>
<span style="color:#b8bfc6">interpolationSearch</span>(<span style="color:#b8bfc6">list</span>,<span style="color:#b8bfc6">left</span>,<span style="color:#b8bfc6">mid</span><span style="color:#b8bfc6">-</span><span style="color:#64ab8f">1</span>,<span style="color:#b8bfc6">aimValue</span>);
}<span style="color:#c88fd0">else</span> <span style="color:#c88fd0">if</span> (<span style="color:#b8bfc6">list</span>[<span style="color:#b8bfc6">mid</span>] <span style="color:#b8bfc6"><</span> <span style="color:#b8bfc6">aimValue</span>){<span style="color:#da924a">//右递归</span>
<span style="color:#b8bfc6">interpolationSearch</span>(<span style="color:#b8bfc6">list</span>,<span style="color:#b8bfc6">mid</span><span style="color:#b8bfc6">+</span><span style="color:#64ab8f">1</span>,<span style="color:#b8bfc6">right</span>,<span style="color:#b8bfc6">aimValue</span>);
}<span style="color:#c88fd0">else</span> {<span style="color:#da924a">//找到了</span>
<span style="color:#b8bfc6">System</span>.<span style="color:#b8bfc6">out</span>.<span style="color:#b8bfc6">println</span>(<span style="color:#d26b6b">"找到了下标为:"</span><span style="color:#b8bfc6">+</span><span style="color:#b8bfc6">mid</span>);
}
}</span></span>
7.4 斐波拉契查找法(个人认为很难理解)
对于斐波拉契数做一个理解:黄金分割率是近似0.618,而斐波拉契数越大,其前一个数比上后一个数的比值就越接近0.618,当然是从带二个数开始算起.
用数学方法归纳斐波拉契数就是:n=1时值为1,n=2时值为1,n=3时值为2,n=4是值为3,所以当n为n时值为:f(n) = f(n-1) + f(n-2)
<span style="background-color:#333333"><span style="color:#b8bfc6"><span style="color:#b8bfc6">斐波拉契数:</span>{<span style="color:#64ab8f">1</span>,<span style="color:#64ab8f">1</span>,<span style="color:#64ab8f">2</span>,<span style="color:#64ab8f">3</span>,<span style="color:#64ab8f">5</span>,<span style="color:#64ab8f">8</span>,<span style="color:#64ab8f">13.</span>......}</span></span>
说了斐波拉契数,那斐波拉契数到底怎么和查找挂钩呢?我一开始看见这个算法根本看不懂,网上的资料视频讲的都是模模糊糊的,后面看了很多不同人的博客,然后自己在纸上推了一遍,最后才理解。
首先我要明确一点:那就是斐波拉契查找算法和二分查找算法是类似的,二者不同点就是二分的这个中间值不一样 ,所以二者排序的对象都是有序表。 这也是我一开始摸不着头绪的原因,通过斐波拉契数这个0.618的特性可以提高普通二分查找的效率,这里又有些不好理解,怎么就可以通过0.618提高效率呢?
<span style="background-color:#333333"><span style="color:#da924a">//解释一下: 普通二分是直接在数组的中间位置找,但是斐波拉契数使在0.618位置开始找,这样可以将前后两段分为不对等的两段,总有一部分查找效率是优于二分的,但是彼此时间复杂度也是半斤八两 都是log2n</span></span>
先理解一下斐波拉契数的思路吧:
整个算法中要时刻记住有序表和斐波拉契数是如何联系起来的:有序表的长度 = 斐波拉契数的值 先别管这个值和长度是多少,记住这句话就行
首先获取有序表的长度,然后再斐波拉契数中去找,找到一个最接近有序表长度而且比这个长度大的斐波拉契数值,不能等于
<span style="background-color:#333333"><span style="color:#b8bfc6">比如长度为6的有序表:</span>[<span style="color:#64ab8f">1</span>,<span style="color:#64ab8f">3</span>,<span style="color:#64ab8f">4</span>,<span style="color:#64ab8f">8</span>,<span style="color:#64ab8f">9</span>,<span style="color:#64ab8f">10</span>] <span style="color:#b8bfc6">斐波拉契数:</span>[<span style="color:#64ab8f">1</span>,<span style="color:#64ab8f">1</span>,<span style="color:#64ab8f">2</span>,<span style="color:#64ab8f">3</span>,<span style="color:#64ab8f">5</span>,<span style="color:#64ab8f">8</span>,<span style="color:#64ab8f">13</span>] <span style="color:#b8bfc6">----></span> <span style="color:#b8bfc6">那么找到的这个值就是</span> <span style="color:#64ab8f">8</span> <span style="color:#b8bfc6">比如长度为5的有序表:</span>[<span style="color:#64ab8f">1</span>,<span style="color:#64ab8f">3</span>,<span style="color:#64ab8f">4</span>,<span style="color:#64ab8f">8</span>,<span style="color:#64ab8f">9</span>] <span style="color:#b8bfc6">斐波拉契数:</span>[<span style="color:#64ab8f">1</span>,<span style="color:#64ab8f">1</span>,<span style="color:#64ab8f">2</span>,<span style="color:#64ab8f">3</span>,<span style="color:#64ab8f">5</span>,<span style="color:#64ab8f">8</span>,<span style="color:#64ab8f">13</span>] <span style="color:#b8bfc6">----></span> <span style="color:#b8bfc6">那么找到的这个值就是</span> <span style="color:#64ab8f">8</span></span>
然后创建一个临时数组,长度为找到的这个斐波拉契数 将原数组拷贝进临时数组,后边多的长度用原数组最后一个数补齐
<span style="background-color:#333333"><span style="color:#b8bfc6">比如长度为5的有序表:</span>[<span style="color:#64ab8f">1</span>,<span style="color:#64ab8f">3</span>,<span style="color:#64ab8f">4</span>,<span style="color:#64ab8f">8</span>,<span style="color:#64ab8f">9</span>] <span style="color:#b8bfc6">斐波拉契数:</span>[<span style="color:#64ab8f">1</span>,<span style="color:#64ab8f">1</span>,<span style="color:#64ab8f">2</span>,<span style="color:#64ab8f">3</span>,<span style="color:#64ab8f">5</span>,<span style="color:#64ab8f">8</span>,<span style="color:#64ab8f">13</span>] <span style="color:#b8bfc6">----></span> <span style="color:#b8bfc6">那么找到的这个值就是</span> <span style="color:#64ab8f">8</span> <span style="color:#b8bfc6">拷贝完成的临时数组就为:</span>[<span style="color:#64ab8f">1</span>,<span style="color:#64ab8f">3</span>,<span style="color:#64ab8f">4</span>,<span style="color:#64ab8f">8</span>,<span style="color:#64ab8f">9</span>,<span style="color:#64ab8f">9</span>,<span style="color:#64ab8f">9</span>,<span style="color:#64ab8f">9</span>]</span>
你可能已经忘了第一条提醒过你的 有序表的长度 = 斐波拉契数的值 这里提醒一下
那么接下来是不是需要进行寻找中间值进行二分操作了? 别着急, 先来理解一下中间值:
这个中间值并不是字面意义上的中间位置,他可以是任意位置,只是它将我整个有序表分成了两大段,当然你把这个中间值算进去也可以理解为是分成三段。那怎么用斐波拉契数找到这个中间值呢?
还记得最开始用数学归纳法归纳出来的斐波那契数列公式吗:
f(n) = f(n-1) + f(n-2)
你可能已经忘了第一条提醒过你的 有序表的长度 = 斐波拉契数的值 这里再提醒一下 , ok,既然f(n) 是斐波拉契数,也就是有序表的长度啊,所以这个公式不就可以帮助我们把有序表分成两段吗,而且这个公式是斐波拉契数列的推到公式啊,那不就满足了黄金分割率吗,恍然大悟!!!
别高兴太早,虽然将有序表分为了两部分但是你知道这个中间值是多少吗?你可能回想:那中间值下标不就是 f(n-1) 吗,这么想你是对的。但是算法是错的,因为这里有一个难点(网上都说是这个算法最难理解的一点)
这里再提醒一便:你可能已经忘了第一条提醒过你的 有序表的长度 = 斐波拉契数的值 ,既然有序表的长度 = 斐波拉契数的值了,那你直接就另中间值为f(n-1)那不就越界了吗,数组下标最大本来是5,但是你用的是数组长度来表明下标那就是6,这不就错了吗!!!有的人可能会说,那变为 f(n-1) -1 这么做也是可以的,但是不是最好,最好是直接将上面的推导式变为f(n)-1的格式那不就完事儿了吗!
<span style="background-color:#333333"><span style="color:#b8bfc6">原式子:f</span>(<span style="color:#b8bfc6">n</span>) <span style="color:#b8bfc6">=</span> <span style="color:#b8bfc6">f</span>(<span style="color:#b8bfc6">n</span><span style="color:#b8bfc6">-</span><span style="color:#64ab8f">1</span>) <span style="color:#b8bfc6">+</span> <span style="color:#b8bfc6">f</span>(<span style="color:#b8bfc6">n</span><span style="color:#b8bfc6">-</span><span style="color:#64ab8f">2</span>) <span style="color:#b8bfc6">变形为:f</span>(<span style="color:#b8bfc6">n</span>)<span style="color:#b8bfc6">-</span><span style="color:#64ab8f">1</span> <span style="color:#b8bfc6">=</span> <span style="color:#b8bfc6">f</span>(<span style="color:#b8bfc6">n</span><span style="color:#b8bfc6">-</span><span style="color:#64ab8f">1</span>) <span style="color:#b8bfc6">+</span> <span style="color:#b8bfc6">f</span>(<span style="color:#b8bfc6">n</span><span style="color:#b8bfc6">-</span><span style="color:#64ab8f">2</span>)<span style="color:#b8bfc6">-</span><span style="color:#64ab8f">1</span> <span style="color:#b8bfc6">变形为:f</span>(<span style="color:#b8bfc6">n</span>)<span style="color:#b8bfc6">-</span><span style="color:#64ab8f">1</span> <span style="color:#b8bfc6">=</span> <span style="color:#b8bfc6">f</span>(<span style="color:#b8bfc6">n</span><span style="color:#b8bfc6">-</span><span style="color:#64ab8f">1</span>) <span style="color:#b8bfc6">+</span> <span style="color:#b8bfc6">f</span>(<span style="color:#b8bfc6">n</span><span style="color:#b8bfc6">-</span><span style="color:#64ab8f">2</span>)<span style="color:#b8bfc6">-</span><span style="color:#64ab8f">1</span> <span style="color:#b8bfc6">变形为:f</span>(<span style="color:#b8bfc6">n</span>)<span style="color:#b8bfc6">-</span><span style="color:#64ab8f">1</span> <span style="color:#b8bfc6">=</span> (<span style="color:#b8bfc6">f</span>(<span style="color:#b8bfc6">n</span><span style="color:#b8bfc6">-</span><span style="color:#64ab8f">1</span>)<span style="color:#b8bfc6">-</span><span style="color:#64ab8f">1</span>) <span style="color:#b8bfc6">+</span> <span style="color:#64ab8f">1</span> <span style="color:#b8bfc6">+</span>(<span style="color:#b8bfc6">f</span>(<span style="color:#b8bfc6">n</span><span style="color:#b8bfc6">-</span><span style="color:#64ab8f">2</span>)<span style="color:#b8bfc6">+</span><span style="color:#64ab8f">1</span>)<span style="color:#da924a">//变为3部分,左中右 中间的1就是我们找的中间值,记住这个1表示在数组中占了一个位置</span></span>
f(n)-1 = (f(n-1)-1) + 1 +(f(n-2)+1)理解 用上面这个图理解的更加透彻一点,网上的图看着容易犯糊涂,在这里又有一点需要注意:f(n)-1 = (f(n-1)-1) + 1 +(f(n-2)+1) 中等号右边的每一个式子都表示占了数组多少个位置
low就是最左的下标,默认为0,middle就是中间值 height 就是数组最右位置 这三个值在算法中都是动态的,因为可能涉及到 左递归 或者 右递归 。
middle = low + f(n-1) - 1 中间值计算公式就是这个,自己想想是不是这个理,先别想递归的情况
在上面我们已经找到了中间值,基本思路也梳理了一遍,拿到中间值不就可以进行二分操作了吗,个二分查找类似,指定退出条件
<span style="background-color:#333333"><span style="color:#c88fd0">if</span>(<span style="color:#b8bfc6">high</span><span style="color:#b8bfc6"><</span><span style="color:#b8bfc6">low</span>){ <span style="color:#c88fd0">return</span>;<span style="color:#b8bfc6">没找到</span> } <span style="color:#c88fd0">if</span>(<span style="color:#b8bfc6">aimValue</span> <span style="color:#b8bfc6"><</span> <span style="color:#b8bfc6">arr</span>[<span style="color:#b8bfc6">mid</span>]){ <span style="color:#da924a">//左递归</span> }<span style="color:#c88fd0">else</span> <span style="color:#c88fd0">if</span> (<span style="color:#b8bfc6">aimValue</span> <span style="color:#b8bfc6">></span> <span style="color:#b8bfc6">arr</span>[<span style="color:#b8bfc6">mid</span>]){ <span style="color:#da924a">//右递归</span> }<span style="color:#c88fd0">else</span>{ <span style="color:#da924a">//找到了,下标为mid</span> }</span>
二分完算法就结束了
注意:通过递归思路写的不用辅助数组,只要时刻记住斐波拉契数等于数组的长度,mid将数组长度分为两段,两段长度构成0.618
<span style="background-color:#333333"><span style="color:#c88fd0">package</span> <span style="color:#8d8df0">com</span>.<span style="color:#b8bfc6">hubei</span>.<span style="color:#b8bfc6">didi</span>.<span style="color:#b8bfc6">search</span>; <span style="color:#c88fd0">import</span> <span style="color:#b8bfc6">org</span>.<span style="color:#b8bfc6">junit</span>.<span style="color:#b8bfc6">Test</span>; <span style="color:#c88fd0">import</span> <span style="color:#b8bfc6">java</span>.<span style="color:#b8bfc6">util</span>.<span style="color:#b8bfc6">Arrays</span>; <span style="color:#da924a">/**</span> <span style="color:#da924a">* @Author: 大空</span> <span style="color:#da924a">* @Data: 2023-05-11 8:26</span> <span style="color:#da924a">* @Description: 斐波拉契排序</span> <span style="color:#da924a">* @Version:1.0.0 时刻记住菲薄拉起数的值就是数组的长度</span> <span style="color:#da924a">*/</span> <span style="color:#c88fd0">public</span> <span style="color:#c88fd0">class</span> <span style="color:#8d8df0">fibonacciSearch</span> { <span style="color:#c88fd0">public</span> <span style="color:#c88fd0">static</span> <span style="color:#1cc685">void</span> <span style="color:#b8bfc6">main</span>(<span style="color:#1cc685">String</span>[] <span style="color:#b8bfc6">args</span>) { <span style="color:#1cc685">int</span>[] <span style="color:#b8bfc6">arr</span> <span style="color:#b8bfc6">=</span> {<span style="color:#64ab8f">1</span>, <span style="color:#64ab8f">2</span>, <span style="color:#64ab8f">3</span>, <span style="color:#64ab8f">4</span>, <span style="color:#64ab8f">5</span>, <span style="color:#64ab8f">6</span>, <span style="color:#64ab8f">9</span>, <span style="color:#64ab8f">10</span>, <span style="color:#64ab8f">12</span>, <span style="color:#64ab8f">16</span>, <span style="color:#64ab8f">30</span>, <span style="color:#64ab8f">90</span>, <span style="color:#64ab8f">100</span>, <span style="color:#64ab8f">150</span>, <span style="color:#64ab8f">160</span>}; <span style="color:#b8bfc6">fibonacciSearch</span> <span style="color:#b8bfc6">fibonacciSearch</span> <span style="color:#b8bfc6">=</span> <span style="color:#c88fd0">new</span> <span style="color:#b8bfc6">fibonacciSearch</span>(); <span style="color:#da924a">// Arrays.stream(fibonacciSearch.fibonacci(20)).forEach(m->{System.out.print(m+" ");});</span> <span style="color:#b8bfc6">fibonacciSearch</span>.<span style="color:#b8bfc6">fibonacciSearch</span>(<span style="color:#b8bfc6">arr</span>, <span style="color:#b8bfc6">fibonacciSearch</span>.<span style="color:#b8bfc6">fibonacci</span>(<span style="color:#b8bfc6">arr</span>.<span style="color:#b8bfc6">length</span>), <span style="color:#64ab8f">0</span>, <span style="color:#b8bfc6">arr</span>.<span style="color:#b8bfc6">length</span> <span style="color:#b8bfc6">-</span> <span style="color:#64ab8f">1</span>, <span style="color:#64ab8f">10</span>); } <span style="color:#da924a">/**</span> <span style="color:#da924a">* @param n 表示数组长度</span> <span style="color:#da924a">* @return 产生斐波拉契数组</span> <span style="color:#da924a">*/</span> <span style="color:#c88fd0">public</span> <span style="color:#1cc685">int</span>[] <span style="color:#b8bfc6">fibonacci</span>(<span style="color:#1cc685">int</span> <span style="color:#b8bfc6">n</span>) { <span style="color:#1cc685">int</span>[] <span style="color:#b8bfc6">f</span> <span style="color:#b8bfc6">=</span> <span style="color:#c88fd0">new</span> <span style="color:#1cc685">int</span>[<span style="color:#b8bfc6">n</span>]; <span style="color:#b8bfc6">f</span>[<span style="color:#64ab8f">0</span>] <span style="color:#b8bfc6">=</span> <span style="color:#64ab8f">1</span>; <span style="color:#b8bfc6">f</span>[<span style="color:#64ab8f">1</span>] <span style="color:#b8bfc6">=</span> <span style="color:#64ab8f">1</span>; <span style="color:#c88fd0">for</span> (<span style="color:#1cc685">int</span> <span style="color:#b8bfc6">i</span> <span style="color:#b8bfc6">=</span> <span style="color:#64ab8f">2</span>; <span style="color:#b8bfc6">i</span> <span style="color:#b8bfc6"><</span> <span style="color:#b8bfc6">n</span>; <span style="color:#b8bfc6">i</span><span style="color:#b8bfc6">++</span>) { <span style="color:#b8bfc6">f</span>[<span style="color:#b8bfc6">i</span>] <span style="color:#b8bfc6">=</span> <span style="color:#b8bfc6">f</span>[<span style="color:#b8bfc6">i</span> <span style="color:#b8bfc6">-</span> <span style="color:#64ab8f">1</span>] <span style="color:#b8bfc6">+</span> <span style="color:#b8bfc6">f</span>[<span style="color:#b8bfc6">i</span> <span style="color:#b8bfc6">-</span> <span style="color:#64ab8f">2</span>]; } <span style="color:#c88fd0">return</span> <span style="color:#b8bfc6">f</span>; } <span style="color:#c88fd0">public</span> <span style="color:#1cc685">void</span> <span style="color:#b8bfc6">fibonacciSearch</span>(<span style="color:#1cc685">int</span>[] <span style="color:#b8bfc6">arr</span>, <span style="color:#1cc685">int</span>[] <span style="color:#b8bfc6">fibonacci</span>, <span style="color:#1cc685">int</span> <span style="color:#b8bfc6">low</span>, <span style="color:#1cc685">int</span> <span style="color:#b8bfc6">high</span>, <span style="color:#1cc685">int</span> <span style="color:#b8bfc6">aimValue</span>) { <span style="color:#b8bfc6">System</span>.<span style="color:#b8bfc6">out</span>.<span style="color:#b8bfc6">println</span>(<span style="color:#d26b6b">"进来循环"</span>); <span style="color:#da924a">//首先获取一下斐波拉契数列,长度就按数字长度计算</span> <span style="color:#c88fd0">if</span> (<span style="color:#b8bfc6">low</span> <span style="color:#b8bfc6">></span> <span style="color:#b8bfc6">high</span>) {<span style="color:#da924a">//如果左下标值大于右下标值就直接退出</span> <span style="color:#b8bfc6">System</span>.<span style="color:#b8bfc6">out</span>.<span style="color:#b8bfc6">println</span>(<span style="color:#d26b6b">"没找到"</span>); <span style="color:#c88fd0">return</span>; } <span style="color:#da924a">// 创建一个临时数组存放扩容后的值</span> <span style="color:#1cc685">int</span> <span style="color:#b8bfc6">index</span> <span style="color:#b8bfc6">=</span> <span style="color:#64ab8f">0</span>; <span style="color:#c88fd0">for</span> (<span style="color:#1cc685">int</span> <span style="color:#b8bfc6">i</span> <span style="color:#b8bfc6">=</span> <span style="color:#64ab8f">0</span>; <span style="color:#b8bfc6">i</span> <span style="color:#b8bfc6"><</span> <span style="color:#b8bfc6">fibonacci</span>.<span style="color:#b8bfc6">length</span> <span style="color:#b8bfc6">-</span> <span style="color:#64ab8f">1</span>; <span style="color:#b8bfc6">i</span><span style="color:#b8bfc6">++</span>) { <span style="color:#c88fd0">if</span> (<span style="color:#b8bfc6">fibonacci</span>[<span style="color:#b8bfc6">i</span>] <span style="color:#b8bfc6">></span> (<span style="color:#b8bfc6">high</span> <span style="color:#b8bfc6">-</span> <span style="color:#b8bfc6">low</span> <span style="color:#b8bfc6">+</span> <span style="color:#64ab8f">1</span>)) {<span style="color:#da924a">//创建一个仅仅大于数组长度的数组</span> <span style="color:#b8bfc6">index</span> <span style="color:#b8bfc6">=</span> <span style="color:#b8bfc6">i</span>; <span style="color:#c88fd0">break</span>; } } <span style="color:#da924a">// int[] ints = Arrays.copyOfRange(arr, low, low+fibonacci[index]+1);</span> <span style="color:#da924a"> int[] ints = Arrays.copyOf(arr, index);</span> <span style="color:#da924a">// Arrays.fill(ints,high-low,ints.length,arr[high]);//填充扩充的空间</span> <span style="color:#da924a">// System.out.println(Arrays.toString(ints));</span> <span style="color:#da924a">// 计算中间值 mid = low + f(k-1)-1 f(k)-1 = [f(k-1)-1] +1+[f(k-2)-1]</span> <span style="color:#da924a">// 这个k就是理我扩充的斐波拉契数的下标</span> <span style="color:#1cc685">int</span> <span style="color:#b8bfc6">mid</span> <span style="color:#b8bfc6">=</span> <span style="color:#b8bfc6">low</span> <span style="color:#b8bfc6">+</span> <span style="color:#b8bfc6">fibonacci</span>[<span style="color:#b8bfc6">index</span> <span style="color:#b8bfc6">-</span> <span style="color:#64ab8f">1</span>] <span style="color:#b8bfc6">-</span> <span style="color:#64ab8f">1</span>; <span style="color:#c88fd0">if</span> (<span style="color:#b8bfc6">arr</span>[<span style="color:#b8bfc6">mid</span>] <span style="color:#b8bfc6">></span> <span style="color:#b8bfc6">aimValue</span>) { <span style="color:#da924a">// 左递归</span> <span style="color:#b8bfc6">fibonacciSearch</span>(<span style="color:#b8bfc6">arr</span>, <span style="color:#b8bfc6">fibonacci</span>, <span style="color:#b8bfc6">low</span>, <span style="color:#b8bfc6">mid</span> <span style="color:#b8bfc6">-</span> <span style="color:#64ab8f">1</span>, <span style="color:#b8bfc6">aimValue</span>); } <span style="color:#c88fd0">else</span> <span style="color:#c88fd0">if</span> (<span style="color:#b8bfc6">arr</span>[<span style="color:#b8bfc6">mid</span>] <span style="color:#b8bfc6"><</span> <span style="color:#b8bfc6">aimValue</span>) { <span style="color:#da924a">// 右递归</span> <span style="color:#b8bfc6">fibonacciSearch</span>(<span style="color:#b8bfc6">arr</span>, <span style="color:#b8bfc6">fibonacci</span>, <span style="color:#b8bfc6">mid</span> <span style="color:#b8bfc6">+</span> <span style="color:#64ab8f">1</span>, <span style="color:#b8bfc6">high</span>, <span style="color:#b8bfc6">aimValue</span>); } <span style="color:#c88fd0">else</span> { <span style="color:#da924a">// 找到了</span> <span style="color:#b8bfc6">System</span>.<span style="color:#b8bfc6">out</span>.<span style="color:#b8bfc6">println</span>(<span style="color:#d26b6b">"找到了,下表为:"</span> <span style="color:#b8bfc6">+</span> <span style="color:#b8bfc6">mid</span>); <span style="color:#c88fd0">return</span>; } } } </span>