首页 > 编程语言 >42. 查找算法

42. 查找算法

时间:2023-07-07 18:44:07浏览次数:35  
标签:int 42 value middle 算法 查找 param 数组

一、线性查找算法

  线性查找是逐一比对,发现有相同值,就返回下标,否则返回 -1。这里,我们实现的线性查找是找到一个满足条件的值就返回。

/**
 * @brief 线性查找
 * 
 * @param A 待查找的数组
 * @param N 数组的长度
 * @param value 待查找的元素
 * @return int 如果找到返回数组下标,否则返回-1
 */
int OrderSearch(int A[],int N,int value)
{
    int i = 0;

    for(i = 0; i < N; i++)
    {
        if(A[i] == value)
        {
            return i;
        }
    }

    return -1;
}

二、二分查找法

  二分查找 要求待找到的数组必须 有序。这里假设待查找的数组是升序的。它的思路如下:

  1. 首先确定该数组的中间的下标 middle = (left + right) / 2;
  2. 然后让需要查找的数 findVal 和 A[middle] 比较,确定要查找的数在哪一边
    1. 如果 findVal > A[middle],说明你要找到的数在 middle 的右边,因此需要递归的向右查找
    2. 如果 findVal < A[middle],说明你要找到的数在 middle 的左边,因此需要递归的向左查找
    3. 如果 findVal == A[middle],说明你找到,找到就返回

  那我们需要在什么时候结束递归呢?当我们找到元素时就结束递归;当递归完整个数组,仍然没有找到 findVal,也需要结束递归,即当 left > right 是就需要结束递归;

/**
 * @brief 二分查找
 * 
 * @param A 待查找的数组
 * @param N 数组的长度
 * @param value 待查找的元素
 * @return int 如果找到返回数组下标,否则返回-1
 */
int BinarySearch(int A[],int N,int value)
{
    Binary(A,0,N-1,value);
}
/**
 * @brief 二分查找核心算法
 * 
 * @param A 待查找的数组
 * @param left 递归的左边的索引
 * @param right 递归的右边的索引
 * @param value 待查找的元素
 * @return int 如果找到返回数组下标,否则返回-1
 */
int Binary(int A[],int left,int right,int value)
{
    int middle = (right - left) / 2 + left;
    int middleVal = A[middle];

    // 当left>right时,说明递归整个数组,但是没有找到
    if(left > right)
    {
        return -1;
    }

    if(value > middleVal)
    {
        Binary(A,middle+1,right,value);             // 向右递归
    }
    else if(value < middleVal)
    {
        Binary(A,left,middle-1,value);              // 向左递归
    }
    else
    {
        return middle;
    }
}

  我们也可以用非递归的方式来实现二分查找:

/**
 * @brief 二分查找
 * 
 * @param A 待查找的数组
 * @param N 数组的长度
 * @param value 待查找的元素
 * @return int 如果找到返回数组下标,否则返回-1
 */
int Binary(int A[],int N,int value)
{
    int left =0;
    int right = N-1;
    int middle = 0;
  
    while(left <= right)
    {
        middle = (right - left) / 2 + left;
        if(A[middle] ==  value)                     // 如果找到则返回
        {
            return middle;
        }
        else if(A[middle] < value)                  // 需要向右边查找
        {
            left = middle + 1;
        }
        else
        {
            right = middle - 1;                     // 需要向左边查找
        }
    }

    return -1;
}

三、插值查找法

  差值查找算法类似于二分查找也要求待查找的数组是有序的,不同的是差值查找每次从自适应 minddle 处开始查找。此时,\(middle = low + \frac{key- a[low]}{a[high] - a[low]}(high - low)\)。其中,key 就是待查找的值 value。

/**
 * @brief 插值查找
 * 
 * @param A 待查找的数组
 * @param N 数组的长度
 * @param value 待查找的元素
 * @return int 如果找到返回数组下标,否则返回-1
 */
int InsertValueSearch(int A[],int N,int value)
{
    if(value < A[0] || value > A[N-1])
    {
        return -1;
    }

    InsertValue(A,0,N-1,value);
}
/**
 * @brief 插值查找核心算法
 * 
 * @param A 待查找的数组
 * @param left 递归的左边的索引
 * @param right 递归的右边的索引
 * @param value 待查找的元素
 * @return int 如果找到返回数组下标,否则返回-1
 */
int InsertValue(int A[],int left,int right,int value)
{
    int middle = 0;
    int middleVal = 0;

    if(left > right)
    {
        return -1;
    }

    middle = left + (right - left) * (value - A[left]) / (A[right] - A[left]);
    middleVal = A[middle];

    if(value > middleVal)
    {
        InsertValue(A,middle+1,right,value);        // 向右递归
    }
    else if(value < middleVal)
    {
        InsertValue(A,left,middle-1,value);         // 向左递归
    }
    else
    {
        return middle;
    }
}

对于数据量较大,关键字分布比较均匀的查找表来说,采用插值查找,速度较快;关键字分布不均匀的情况下,该方法不一定比折半查找要好;

四、斐波那契查找法

  斐波那契查找法 也叫 黄金分割法黄金分割点 是指把一条线段分割为两部分,是其中一部分与全长之比等于另一部分与这部分之比。取其前三位数字的近似值是 0.618。由于按此比例设计的造型十分美丽,因此称为 黄金分割,也称为 中外比。斐波那契数列 {1,1,2,3,5,8,13,21,34,55} 发现斐波那契数列的两个相邻数的比例,无线接近 黄金分割值 0.618。

  斐波那契查找法原理与前面两种相似,仅仅改变了中间值(middle)的位置,middle 不再是中间或插值得到的,而是位于黄金分割点附近,即 \(middle = low + F[K-1] -1(F 代表斐波那契数列)\)。

  由斐波那契数列 \(F[K] = F[K-1] + F[K-2]\) 的性质,可以得到 \((F[K-1]) = (F[K-1] -1) + (F[K-2]-1) +1\)。该式说明:只要顺序表的长度为 \(F[K]-1\),则可以将该表分成长度为 \(F[K-1]-1\) 和 \(F[K-2]-1\) 的两段,从而中间位置为 \(middle = low + F[K-1]} -1\)。

img

  类似的,每一字段也可以用相同的方式分割。但顺序表的长度 N 不一定恰好等于 F[K],所以需要将原来的顺序表的长度 n 增加至 F[K]-1。这里的 K 值只要能使的 F[K-1] 恰好大于或等于 N 即可。顺序表长度增加后,新增的位置(从 N+1 到 F[K]-1 位置),都赋为 N 位置的元素即可。

/**
 * @brief 斐波那契查找
 * 
 * @param A 待查找的数组
 * @param N 数组的长度
 * @param value 待查找的元素
 * @return int 如果找到返回数组下标,否则返回-1
 */
int FibonacciSearch(int *A,int N,int value)
{
    int low = 0, high = N-1, middle = 0;
    int *temp;
    int k = 0,i = 0;
    int number = getFibonacciSize(N);
    int fib[number];

    getFibonacci(fib,number);                       // 获取斐波那契数列
  
    // 获取斐波那契分割数值的下标
    while(high > fib[k]-1)
    {
        k++;
    }

    // 因为fib[k]值可能大于A的长度,
    // 因此,我们需要构造一个新的数组
    temp = (int *)calloc(fib[k]-1,sizeof(int));
    memcpy(temp,A,N * sizeof(int));                 // 将源数组的数据拷贝到临时数组中
    // 如果源数组小于临时数组,则用源数组的最后一个元素填充临时数组后面的元素
    for(i = N; i < fib[k]-1; i++)
    {
        temp[i] = A[N-1];
    }

    // 使用while循环找到value
    while(low <= high)
    {
        middle = low + fib[k-1] - 1;
        // 向数组的前面查找(左边)
        if(value < temp[middle])
        {
            high = middle - 1;
            // 全部元素 = 前面的元素 + 后面的元素
            // F[K] = F[K-1] + F[K-2]
            // 因为,前面有F[K-1]个元素,所以可以继续拆分 F[K-1] = F[K-2] + F[K-3]
            // 即在F[K-1]前面继续查找
            // 下次循环的时候middle=low+F[K-1-1]-1
            k -= 1;
        }
        // 向数组的后面查找(右边)
        else if(value > temp[middle])
        {
            low = middle + 1;
            // 全部元素 = 前面的元素 + 后面的元素
            // F[K] = F[K-1] + F[K-2]
            // 因为,前面有F[K-2]个元素,所以可以继续拆分 F[K-2] = F[K-3] + F[K-4]
            // 即在F[K-2]的前面继续查找
            // 下次循环的时候middle=low+F[K-1-2]-1
            k -= 2;
        }
        else
        {
            free(temp);

            // 需要确定的返回的是哪个小标
            return (middle <= high) ? middle : high;
        }
    }

    free(temp);

    return -1;
}
/**
 * @brief 获取斐波那契数列
 * 
 * @param fib 待获取的斐波那契数列
 * @param N 待获取的斐波那契数列的长度
 */
void getFibonacci(int *fib,int N)
{
    int i = 0;

    fib[0] = 1;
    fib[1] = 1;

    for(i = 2; i < N; i++)
    {
        fib[i] = fib[i-1] + fib[i-2];
    }
}
/**
 * @brief 找到第几个斐波那契数大于number
 * 
 * @param number 待比较的数
 * @return int 返回大于number的那个斐波那契数的序号
 */
int getFibonacciSize(int number) 
{
	int i = 2;
    int temp = 0;
	int num[2] = {1,1};
	while (num[1] < number)
	{
		temp = num[1];
		num[1] += num[0];
		num[0] = temp;
		i++;
	}
	return i;
}

标签:int,42,value,middle,算法,查找,param,数组
From: https://www.cnblogs.com/kurome/p/17535828.html

相关文章

  • C++黑马程序员——P189-192. string容器 构造函数,赋值,拼接,查找和替换
    P189.string容器——构造函数P190....——赋值操作P191....——字符串拼接P192....——字符串查找和替换P189.构造函数———————————————————————————————————————————————————————————————......
  • 游戏AI-寻路-A*寻路算法
    算法介绍:作用:在一个图中,提供一个起点A与一个终点B,给你找出一条估算出来较短的路时间复杂度:n*log(m),n表示图中的节点数,m表示总边的数量时间复杂度分析:一般游戏中的图是一个二维矩阵,所以每个点的方向也就上下左右这么几个,所以每个点枚举方向的时间为常数虽然复杂度为:n*lo......
  • 数据结构与算法(一)
    需要点Java编程基础常见的数据结构栈(Stack):栈是一种特殊的线性表,它只能在一个表的一个固定端进行数据结点的插入和删除操作。队列(Queue):队列和栈类似,也是一种特殊的线性表。和栈不同的是,队列只允许在表的一端进行插入操作,而在另一端进行删除操作。数组(Array):数组是一种聚合数据......
  • C/C++数据结构与算法课程设计[2023-07-06]
    C/C++数据结构与算法课程设计[2023-07-06]数据结构与算法课程设计一、课程设计的目的、要求和任务 本课程设计是为了配合《数据结构与算法》课程的开设,通过设计完整的程序,使学生掌握数据结构的应用、算法的编写等基本方法。1.课程的目的(1)使学生进一步理解和掌握课堂上所学......
  • BZOJ 3942: [Usaco2015 Feb]Censoring KMP
    3942:[Usaco2015Feb]CensoringTimeLimit: 10Sec  MemoryLimit: 128MBSubmit: 476  Solved: 260[Submit][Status][Discuss]DescriptionFarmerJohnhaspurchasedasubscriptiontoGoodHooveskeepingmagazineforhiscows,sotheyhaveplentyofmateria......
  • BZOJ 4247: 挂饰 背包dp
    4247:挂饰TimeLimit: 10Sec  MemoryLimit: 256MBSubmit: 999  Solved: 387[Submit][Status][Discuss]DescriptionJOI君有N个装在手机上的挂饰,编号为1...N。JOI君可以将其中的一些装在手机上。JOI君的挂饰有一些与众不同——其中的一些挂饰附有可以挂其他挂件......
  • BZOJ 2427: [HAOI2010]软件安装 树形背包
    2427:[HAOI2010]软件安装TimeLimit: 10Sec  MemoryLimit: 128MBSubmit: 1275  Solved: 492[Submit][Status][Discuss]Description现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi。我们希望从中选择一些软件安装到一台磁盘容量为M计算机......
  • BZOJ 1042:[HAOI2008]硬币购物 容斥原理 背包dp
    1042:[HAOI2008]硬币购物TimeLimit: 10Sec  MemoryLimit: 162MBSubmit: 2505  Solved: 1505[Submit][Status][Discuss]Description硬币购物一共有4种硬币。面值分别为c1,c2,c3,c4。某人去商店买东西,去了tot次。每次带di枚ci硬币,买si的价值的东西。请问每次......
  • 万能欧几里得算法学习笔记
    万能欧几里得算法万能欧几里得算法用于解决一类与\(\left\lfloor\frac{p\cdotx+r}{q}\right\rfloor\)有关的和式求解问题,例如类欧几里得算法中提到的和式就属于此类问题。但万能欧几里得算法从几何意义出发能处理更广泛的和式类型。例如\(\sum_{x=0}^{l}A^xB^{\left\lfloor\f......
  • 常用算法记录
    二叉树遍历https://leetcode.cn/problems/binary-tree-preorder-traversal/solutions/87526/leetcodesuan-fa-xiu-lian-dong-hua-yan-shi-xbian-2/递归解法前序遍历publicstaticvoidpreOrderRecur(TreeNodehead){if(head==null){return;}......