默认计划
491人加入学习
(0人评价)
【研发工程师】C语言程序设计
价格 ¥ 970.00
该课程属于 名企研发核心能力课 请加入后再学习

二分查找:O(log 2 N)

基础的二分查找只管是否存在,不管是第几个。

 

算法提升:

在0000000001111111111 找第一个1

找最先满足的要求的位置

int binnary_search1(int *arr, int n) {
    int head = 0, tail = n, mid;   // n是虚拟位
    while (head < tail) {
        mid = (head + tail) >> 1;
        if (arr[mid] == 0)    head = mid + 1;
        else   tail = mid;   // 这个1可能就是第一个1,所以不能mid-1
    }
    return head == n ? -1 : head;  //如果头指向虚拟位,则没找到
}

 

在1111111111000000000 找最后一个1

找最后一个满足要求的位置

int binnary_search2(int *arr, int n) {
    int head = -1, tail = n - 1, mid;   // -1是虚拟位
    while (head < tail) {
        mid = (head + tail + 1) >> 1; // +1是为了上取整
        if (arr[mid] == 0)    tail = mid - 1;
        else   head = mid;   // 这个1可能就是最后一个1,所以不能mid+1
    }
    return head;  //如果尾指向虚拟位,则没找到
}

 

oj195

#include <cstdio>

int binary_search(int *arr, int n, int x) {
    int min = 0, max = n - 1, mid;
    while (min < max) {
        mid = (min + max + 1) >> 1;
        if (arr[mid] > x)   max = mid - 1;
        else    min = mid;
    }
    return arr[min];
}

int main() {
    int n, m, x;
    scanf("%d%d", &n, &m);
    int *nrr = new int[n]();
    for (int i = 0; i < n; i++) {
        scanf("%d", &nrr[i]);
    }
    for (int i = 0; i < m; i++) {
        scanf("%d", &x);
        i && printf(" ");
        printf("%d", binary_search(nrr, n, x));
    }
    delete(nrr);
    return 0;
}

 

二分查找实现开平方根(sqrt):

连续问题,离散问题

此问题属于连续问题:

#include <stdio.h>
#include <math.h>

double my_sqrt(double x) {
    double min = 0, max = x + 1.0, mid;
    #define EPSL 1e-7
    while (max - min > EPSL) {
        mid = (max + min) / 2.0;
        if (mid * mid < x) min = mid;
        else max = mid;
    }
    #undef EPSL
    return mid;
}

int main() {
    double x;
    while (~scanf("%lf", &x)) {
        printf("sqrt(%g) = %g\n", x, sqrt(x));
        printf("my_sqrt(%g) = %g\n", x, my_sqrt(x));
    }
    return 0;
}
  1. %g用于打印浮点型数据时,会去掉多余的零,至多保留六位有效数字(不同于%e的默认保留小数点后6位)

  2. 1e-7是10的-7次方

  3. max = x + 1.0是为了:如果开小于1的平方根的话,会导致寻找的数字根本不在范围。所以加上1,即可包含进查找范围

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

牛顿迭代算法(logN):是C语言sqrt底层实现的算法

牛顿迭代解决高阶(单调)方程求根问题

方程必须连续可导才能用牛顿迭代法

 

用牛顿迭代设计sqrt:

x = √n

x * x = n

原函数F(x) = x * x - n表示x与√n之间的误差值

f(x) = 2x表示斜率,用于求下一个迭代x的值

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

如求√5: f(x) = x^2 - 5

随便取一点初始值x0, 取x0 = 5

则点(x0, f(x0))的切线为f'(x0)

 

切线方程点斜式y-f(x0)=f'(x0)(x-x0),

其与x轴交于(x1, 0),带入切线方程得:

0-f(x0)=f'(x0)(x1-x0)

解得x1 = x0 - f(x0) / f'(x0)

即为1次迭代,下一次取(x1, f(x1)),取切线方程,交于x轴为x2,然后再取(x2, f(x2))...

 

直到x * x 与 n之间的差值即F(x, n)的返回值小于误差EPSL,输出其x为平方根。

 

#include <stdio.h>
#include <math.h>

// 原函数f(x) = x^2 - n, 因为x^2 = n, x=根号n
double F(double x, double n) {
    return x * x - n;
}

// 导函数f'(x) = 2x
double f(double x) {
    return 2 * x;
} 

double NewTon(double (*F)(double, double), double (*f)(double), double n) {
    double x = n;
    #define EPSL 1e-7
    while (fabs(F(x, n)) > EPSL) {
        x -= F(x, n) / f(x);
    }
    #undef EPSL
    return x;
}

double my_sqrt(double n) {
    return NewTon(F, f, n);
}

int main() {
    double n;
    while(~scanf("%lf", &n)) {
        printf("sqrt(%g) = %g\n", n, sqrt(n));
        printf("my_sqrt(%g) = %g\n", n, my_sqrt(n));
    }
    return 0;
}

 

PS:最快的sqrt是O(1)的,雷神之锤3的工程师设计的

[展开全文]

二分查找与牛顿迭代

    01二分,10二分。

int bunary_search01(int *arr, int n) {
  int head = 0, tail = n, mid;
  while (head < tail) {
   mid = (head + tail) >> 1;
   if(arr[mid] == 0) head = mid + 1;
   else tail = mid;
  }
  return head == n ? -1 : head;
}
int binary_search10(int *arr, int n) {
  int head = -1, tail = n - 1, mid;
  while (head < tail) {
    mid = (head + tail + 1) >> 1;
    if (arr[mid] == 0) tail = mid - 1;
    else head = mid;
  }
  return head;
}

    oj 195.报数游戏;

/*   sqrt() */
 
double my_sqrt(double n) {
  double head = 0, tail = n + 1, mid;
  #define EPSL 1e-6;
  while (tail - head > EPSL) {
    mid = (head + tail) /2.0;
    if (mid * mid < n) head = mid;
    else tail = mid;
  }
  #undef EPSL
  return head;
}

 

牛顿迭代:

double func(double x, double n) {
  return x*x - n;
}

double f(double x) {
  retrun 2 * x;
}

double NewTon(double (*F)(double, double), double (*f)(double), double n) {
  double x = 1.0;
  #define ESPL 1e-6;
  while (fabs(F(x, n)) > EPSL) {
   x -= F(x, n) / f(x);
  }
  #undef
  return x;
}

int main() {
  double x;
  while (~scanf("%lf", x)) {
    printf("%g: sqrt: %g", x, NewTon(func, f, x));
  return 0;
}

 

 

[展开全文]

授课教师

C++算法工程师

课程特色

视频(31)