一 二分法
二分法也为折半搜索,我一般叫对半查找,大致意思是将数组分为两半,比较中间元素和目标值,对比后决定是从左半部分还是右半部分查找,直到找到目标为止。
条件:数组得是有序的。
我们直接上例子
#include<stdio.h>
//定义二分查找函数
int binarySearch(int arr[],int left,int right,int target)
{
while(left<=right){
int mid =left+(right-left)/2;//防止溢出
if(arr[mid]==target){
return mid;//若为目标值直接返回
}
else if(arr[mid]<target)
{left=mid+1;若mid小于目标值将在右半边查找
}
else{
right=mid-1;//mid若大于目标值将在左边查找
}
return -1;//若没有找到目标值返回-1
}
要实现二分查找我们得先确定查找的范围,其次在查找范围内,计算索引mid,同时可能会有人询问为什么是mid=left+(right-left)/2,而不是mid=(left+right)/2,这里我们需要了解的是当其定义的数很大的时候它有可能超出了int可定义的范围(我们可以试试INT_MAX这个代码求出int的最大值为2147483647),当left=INT_MAX-1的时候它们相加会溢出,导致乱码,所以我们用的是我们这个例子,防止溢出。
二分查找的时间复杂度为O(log n),其中n为数组的长度,比起线性查找高效,但是它必须是有序的。
二 递归
递归需要函数直接或间接调用自身解决问题,它通常有两个主要部分:
基本情况:其终止的条件,阻止其无限递归。
递归情况:调用自身解决问题。
递归代码简洁,但是会导致大内存消耗和性能开销,它每次调用都会在调用栈上增加一层。
我们简单举一个递归例子
#include<stdio.h>
//递归求阶乘
int factorial(int n){
if(n<=1)
{return 1;//基本情况
}
else {
return n*factorial(n-1);//递归情况
}
}
三 迭代
迭代通过反复使用循环结构(for,while和do while循环)来解决问题,其通过控制循环变量来控制函数的执行。
其通常比递归高效,因为它不要额外的函数调用开销,但是它会比递归更复杂,更难理解和1维护。
举相同的例子,但用迭代。
#incude<stdio.h>
int factorial(int n)
{
int result=1;
for(int i=2;i<=n;i++)
{result*=i;
}
return result;
}
最后我们实现一下递归和迭代分别实现二分查找
递归
#include<stdio.h>
int erfenchazhao(int arr[],int left,int right,int target){
if(right>=letf){
int mid=left+(right-left)/2;
//目标在中间直接返回
if (arr[mid]==target)
return mid;
//目标值小于中间值,在左边查找
if(arr[mid]>target)
return erfenchazhao(arr,left,mid-1,target);
else
//否则目标在右边
return erfenchazhao(arr,mid+1,right,target);
}
//找不到
return -1;
}
迭代
include<stdio.h>
int erfenchazhao(int arr[],int left,int right,int target){
whlie(left<=right){
int mid=left+(right-left)/2;
//若目标值在中间
if(arr[mid]==target)
return mid;
//若目标值小于中间值则在左边查找
if(arr[mid]>target)
right=mid-1;
//否则在右边
else
left=mid+1;
}
//找不到返回-1
return -1;
}