七、查找算法

七、查找

7.1 线性查找(顺序查找)

线性查找就是从前向后或者从后向前依次查找

7.2 二分查找(折半查找)

注意:二分法必须保证原数组是有序的

实现思路:

  • 首先要明确二分查找需要在有序数组中进行

  • 借用递归实现,明确没有找到的退出条件是right<left时进行退出递归

  1. 首先定义两个变量left和right 分别指向最左侧和最右侧下标,然后去下标中间值跟需要查找的数进行比较

  2. 如果小于比较值就进行右递归,将left指向 mid+1 (这里数一下为什么是mid+1 因为你找到了mid发现不是你要找的值,所以直接跳过这个值就好) ;如果大于这个mid就进行做递归

  3. 在最开始要声明递归没找到的退出的条件是 left >right

  4. 如果找到了就返回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>

先理解一下斐波拉契数的思路吧:

  1. 整个算法中要时刻记住有序表和斐波拉契数是如何联系起来的:有序表的长度 = 斐波拉契数的值 先别管这个值和长度是多少,记住这句话就行

  2. 首先获取有序表的长度,然后再斐波拉契数中去找,找到一个最接近有序表长度而且比这个长度大的斐波拉契数值,不能等于

    <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>
  3. 然后创建一个临时数组,长度为找到的这个斐波拉契数 将原数组拷贝进临时数组,后边多的长度用原数组最后一个数补齐

    <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>
  4. 你可能已经忘了第一条提醒过你的 有序表的长度 = 斐波拉契数的值 这里提醒一下

  5. 那么接下来是不是需要进行寻找中间值进行二分操作了? 别着急, 先来理解一下中间值:

    这个中间值并不是字面意义上的中间位置,他可以是任意位置,只是它将我整个有序表分成了两大段,当然你把这个中间值算进去也可以理解为是分成三段。那怎么用斐波拉契数找到这个中间值呢?

    还记得最开始用数学归纳法归纳出来的斐波那契数列公式吗: 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)理解

      image-20230510120839392

      用上面这个图理解的更加透彻一点,网上的图看着容易犯糊涂,在这里又有一点需要注意: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>
  6. 二分完算法就结束了

注意:通过递归思路写的不用辅助数组,只要时刻记住斐波拉契数等于数组的长度,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>

  • 17
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值