初阶算法(3):二分法的讲解与实现(C语言),以及二分不止光在有序数组中的应用

简介: 初阶算法(3):二分法的讲解与实现(C语言),以及二分不止光在有序数组中的应用

前言

      哇,转眼就到了第三章,在前两章内(如果想看前两章的内容,请点击系列文章目录的链接),我们主要讲解了时间复杂度为O(N^2)的排序算法(冒泡排序,选择排序,插入排序),不知道大家看的如何?


      在这一章,我们主要讲述二分法的使用,讲述有关二分法的三道编程题来打破大家对二分法只能用在有序数组的思想。


一、二分法的讲解与实现(C语言)

1.1 为什么在有序数组中用二分法查找?

      一般地,我们在一个有序数组中查找一个数字,如果我们一一查找是要根据数据量的,有时会很快,有时会很慢!这就比较麻烦,所以我们不能用一一查找。


      为什么说有时很快,有时很慢呢?假如,我们现在有一个有序数组(1,2,3,4,5,6,7,8,9,10,11,12,13),如果你要查找1的话, 一一查找只需遍历一位即可;但如果你要查找13的话,则需要将整个数组遍历完。


      此时,这个要查找的数组是一个有序数组,我们就可以利用有序数组的特性去使用二分查找去寻找我们所要查找的数字。


1.2 二分查找的讲解:

      在上面的引子中说在一个有序数组中使用二分查找,那么二分查找是如何实现的呢?


二分查找的基本思路是:先找到中间的数与要查找数进行比较,然后分情况:


      1)如果比要查找数小,那么就舍弃左边一半的数,在右边一半的数再找到中间的数与要查找数进行比较,重复此过程;


      2)如果比要查找数大,那么就舍弃右边一半的数,在左边一半的数再找到中间的数与要查找数进行比较,重复此过程;


      最后,直到查找到最后一个数。


      接下来,进行估算二分查找的时间复杂度,用最坏的数据进行计算,因为一次代码流程要舍弃一半的数,所以时间复杂度为O(logN)。


1.3 二分法的代码实现:

      经过上面的详细分析后,小编觉得各位看官已经充分了解了二分法的思路了,那么接下来,和小编进行二分法的实现吧!


实现二分法的代码如下:

    int left = 0;
    int right = n - 1;
    while (left <= (right - 1)){     //判断条件是左边指向的位置大于右边指向的位置
        int mid = (left + right) / 2;//中点的位置要随时更新,以便求出最新的中点坐标
        if(k > arr[n - 1])      //如果要查找的数大于数组的最后一个数时,则不需要继续查找
            break;
        if (arr[mid] == k){
            right = mid;
            if(arr[mid - 1] < arr[mid])  //与中间数进行比较
                ans = mid;
        }
        if(arr[mid] > k)     //随时更新中点坐标
            right = mid;  
        if(arr[mid] < k)
            left = mid;
    }

二、二分法的应用(不止在有序数组中)

2.1 常规用法

      在上面我们已经进行过在一个有序数组中查找某一个数,接下来,我们将写出一个变式:查找某个位置。


题目:你需要输入一个n,一个数k,然后输入一个长度为n个大小的数组arr,然后你需要在arr上找满足>=K的最左位置,并且输出这个位置,如果不存在这个位置就输出-1。


     看到这道题面,小编我的第一个反应是将这个有序数组进行遍历, 只要找到第一个数字等于k,则是我们所要查找的位置,那么这种方法就和上面小编写的第一道体题的思想一样,就是有时很慢。有时很快。


      这篇文章中,我们学习了二分法,就要利用二分法进行解题。基本思路是:先找到中间的数与要查找数进行比较,然后分情况:


      1)如果比要查找数小,>=K的最左位置应该在右边,那么就舍弃左边一半的数,在右边一半的数再找到中间的数与要查找数进行比较,重复此过程;


      2)如果比要查找数等于或大于,>=K的最左位置应该在右边,那么就舍弃右边一半的数,如果等于k的话进行标记,在左边一半的数再找到中间的数与要查找数进行比较,重复此过程;最后将整个数组进行遍历,找到第一个标记的数字。


      最后,直到查找到最后>=K一个数。


实现题目的代码如下:

int main()
{
  int n = 0, k = 0;
  scanf("%d %d", &n, &k);
  int a[1000000];
  for (int i = 0; i < n; i++)
    scanf("%d", &a[i]);
  int left = 0;
  int right = n - 1;
  int mid = 0;
  int reslut = -1;    //因为如果找不到,就输出-1
  while (left <= right){
    mid = (left + right) / 2;
    if (a[mid] >= k){
      reslut = mid;
      right = mid - 1;
    }
    else
      left = mid + 1;
  }
  printf("%d\n", reslut);
  return 0;
}

2.2 非常规做法(在无需数组中进行)

      二分法真的只能用在有序数组中吗?小编在了解完这个题目后,也是大吃一惊!答案是可以的!


      接下来,跟随小编的步伐进行学习吧!看这道题目:局部最小值问题。


局部最小的概念:1)数组中0位置的数比1位置的数要小;


                            2)数组中N-1位置的数比N-2位置的数要小;


                            3)数组中第i位置的数要比两边位置的数都要小。


题目: 给定无序数组arr,已知arr中任意两个相邻的数都不相等,只需要返回arr中任意一个局部最小出现的位置即可,如果不存在这个位置就输出-1。

      小编进行分析可得:


      先判断0位置的数和1位置的数,再判断N-1位置的数和N-2位置的数。如果这两种情况都不成立,那么一定会出现一开始是下降的,在最后是上扬的,又因为数组中每两个数都不相同,所以在1到N-2中一定有局部最小。


      接下来,我们就可以利用二分进行舍弃数字。找到中间位置的数与两边位置的数进行比较,如果都小于,则返回中间位置的数;如果有一边不小于,则舍弃一半,在另一半继续寻找。


实现题目的代码如下:

int main() {
    int n = 0;
    scanf("%d", &n);
    int a[100000];
    for (int i = 0; i < n; i++) {
        scanf("%d", a + i);
    }
    int left = 0;
    int right = n - 1;
    int mid = -1;
    if (n == 1 || a[0] < a[1]) {
        printf("%d\n", 0);
        return 0;
    }
    else if (a[n - 1] < a[n - 2]) {
        printf("%d\n", n - 1);
        return 0;
    } else {
        while (left <= right) {
            mid = (left + right) / 2;
            if (a[mid] > a[mid - 1]) {
                right = mid - 1;
            }
            else if (a[mid] > a[mid + 1]) {
                left = mid + 1;
            } else {
                //flag = 1;
                printf("%d\n", mid);
                return 0;
            }
        }
    }
    return 0;
}

总结

      以上就是今天要讲的内容,本文介绍了二分法及其在无序数组中的应用,过几天小编会进行编写关于二分法的一些习题,希望大家看完以后,进行点评,谢谢大家!

相关文章
|
2月前
|
存储 监控 算法
员工上网行为监控中的Go语言算法:布隆过滤器的应用
在信息化高速发展的时代,企业上网行为监管至关重要。布隆过滤器作为一种高效、节省空间的概率性数据结构,适用于大规模URL查询与匹配,是实现精准上网行为管理的理想选择。本文探讨了布隆过滤器的原理及其优缺点,并展示了如何使用Go语言实现该算法,以提升企业网络管理效率和安全性。尽管存在误报等局限性,但合理配置下,布隆过滤器为企业提供了经济有效的解决方案。
95 8
员工上网行为监控中的Go语言算法:布隆过滤器的应用
|
3月前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
99 5
|
2月前
|
存储 缓存 算法
探索企业文件管理软件:Python中的哈希表算法应用
企业文件管理软件依赖哈希表实现高效的数据管理和安全保障。哈希表通过键值映射,提供平均O(1)时间复杂度的快速访问,适用于海量文件处理。在Python中,字典类型基于哈希表实现,可用于管理文件元数据、缓存机制、版本控制及快速搜索等功能,极大提升工作效率和数据安全性。
74 0
|
3月前
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
3月前
|
机器学习/深度学习 人工智能 算法
探索人工智能中的强化学习:原理、算法与应用
探索人工智能中的强化学习:原理、算法与应用
|
3月前
|
机器学习/深度学习 算法 数据挖掘
C语言在机器学习中的应用及其重要性。C语言以其高效性、灵活性和可移植性,适合开发高性能的机器学习算法,尤其在底层算法实现、嵌入式系统和高性能计算中表现突出
本文探讨了C语言在机器学习中的应用及其重要性。C语言以其高效性、灵活性和可移植性,适合开发高性能的机器学习算法,尤其在底层算法实现、嵌入式系统和高性能计算中表现突出。文章还介绍了C语言在知名机器学习库中的作用,以及与Python等语言结合使用的案例,展望了其未来发展的挑战与机遇。
77 1
|
3月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
99 1
|
3月前
|
网络协议 物联网 数据处理
C语言在网络通信程序实现中的应用,介绍了网络通信的基本概念、C语言的特点及其在网络通信中的优势
本文探讨了C语言在网络通信程序实现中的应用,介绍了网络通信的基本概念、C语言的特点及其在网络通信中的优势。文章详细讲解了使用C语言实现网络通信程序的基本步骤,包括TCP和UDP通信程序的实现,并讨论了关键技术、优化方法及未来发展趋势,旨在帮助读者掌握C语言在网络通信中的应用技巧。
81 2
|
3月前
|
存储 C语言 计算机视觉
在C语言中指针数组和数组指针在动态内存分配中的应用
在C语言中,指针数组和数组指针均可用于动态内存分配。指针数组是数组的每个元素都是指针,可用于指向多个动态分配的内存块;数组指针则指向一个数组,可动态分配和管理大型数据结构。两者结合使用,灵活高效地管理内存。
|
3月前
|
存储 NoSQL 编译器
C 语言中指针数组与数组指针的辨析与应用
在C语言中,指针数组和数组指针是两个容易混淆但用途不同的概念。指针数组是一个数组,其元素是指针类型;而数组指针是指向数组的指针。两者在声明、使用及内存布局上各有特点,正确理解它们有助于更高效地编程。

热门文章

最新文章