c# 无处不在的二分搜索

        我们知道二分查找算法。二分查找是最容易正确的算法。我提出了一些我在二分搜索中收集的有趣问题。有一些关于二分搜索的请求。我请求您遵守准则:“我真诚地尝试解决问题并确保不存在极端情况”。阅读完每个问题后,最小化浏览器并尝试解决它。 
        问题陈述:给定一个由 N 个不同元素组成的排序数组,使用最少的比较次数在数组中找到一个键。 (您认为二分搜索是在排序数组中搜索键的最佳选择吗?)无需太多理论,这里是典型的二分搜索算法。

// C# program to implement
// the above approach
using System;
 
class GFG
{
 
// Returns location of key, or -1 if not found
static int BinarySearch(int[] A, int l, int r, int key)
{
    int m;
 
    while( l < r )
    {
        m = l + (r-l)/2;
 
        if( A[m] == key ) // first comparison
            return m;
 
        if( A[m] < key ) // second comparison
            l = m + 1;
        else
            r = m - 1;
    }
 
    return -1;
}
}
 
// This code is contributed by code_hunt. 

        理论上,最坏情况下我们需要进行log N + 1次比较。如果我们观察的话,我们会在每次迭代中使用两次比较,除非最终成功匹配(如果有)。在实践中,比较将是昂贵的操作,它不仅仅是原始类型比较。尽量减少与理论极限的比较更为经济。请参阅下图,了解下一个实现中索引的初始化。 

以下实现使用较少的比较次数。 

// C# conversion
 
// Invariant: A[l] <= key and A[r] > key
// Boundary: |r - l| = 1
// Input: A[l .... r-1]
int BinarySearch(int[] A, int l, int r, int key)
{
    int m;
 
    while (r - l > 1) {
        m = l + (r - l) / 2;
 
        if (A[m] <= key)
            l = m;
        else
            r = m;
    }
 
    if (A[l] == key)
        return l;
    if (A[r] == key)
        return r;
    else
        return -1;
}
 
// This code is contributed by akashish__

        在 while 循环中,我们仅依赖于一次比较。搜索空间收敛到将l和r指向两个不同的连续元素。我们需要再进行一次比较来跟踪搜索状态。您可以查看示例测试用例 http://ideone.com/76bad0。 (C++11 代码)。

        问题陈述:给定一个由 N 个不同整数组成的数组,找到输入“key”的下限值。假设 A = {-1, 2, 3, 5, 6, 8, 9, 10} 且 key = 7,我们应该返回 6 作为结果。我们可以使用上面的优化实现来找到键的下限值。只要不变量成立,我们就不断地将左指针移到最右边。最终左指针指向小于或等于 key 的元素(根据定义下限值)。以下是可能的极端情况, —> 如果数组中的所有元素都小于 key,则左指针移动到最后一个元素。 —> 如果数组中的所有元素都大于 key,则为错误情况。 —> 如果数组中的所有元素都相等且 <= key,则这是我们实现的最坏情况输入。
这是示例:

using System;
 
public class Floor {
    // This function returns the largest value in A that is
    // less than or equal to key. Invariant: A[l] <= key and
    // A[r] > key Boundary: |r - l| = 1 Input: A[l .... r-1]
    // Precondition: A[l] <= key <= A[r]
    static int floor(int[] A, int l, int r, int key)
    {
        int m;
 
        while (r - l > 1) {
            m = l + (r - l) / 2;
 
            if (A[m] <= key)
                l = m;
            else
                r = m;
        }
 
        return A[l];
    }
 
    // Initial call
    static int floor(int[] A, int size, int key)
    {
        // Add error checking if key < A[0]
        if (key < A[0])
            return -1;
 
        // Observe boundaries
        return floor(A, 0, size, key);
    }
 
    public static void Main(string[] args)
    {
        int[] arr = { 1, 2, 3, 4, 5 };
        Console.WriteLine(floor(arr, arr.Length - 1, 3));
    }
}
// This code is contributed by sarojmcy2e

您可以看到一些测试用例 http://ideone.com/z0Kx4a。 

        问题陈述:给定一个可能有重复元素的排序数组。查找log N时间内输入“key”出现的次数。这里的想法是使用二分搜索查找数组中最左边和最右边出现的键。我们可以修改底函数来跟踪最右边的出现和最左边的出现。 
这是示例: 

using System;
 
public class OccurrencesInSortedArray
{
    // Returns the index of the leftmost occurrence of the
    // given key in the array
    private static int getLeftPosition(int[] arr, int left,
                                       int right, int key)
    {
        while (right - left > 1)
        {
            int mid = left + (right - left) / 2;
            if (arr[mid] >= key)
            {
                right = mid;
            }
            else
            {
                left = mid;
            }
        }
        return right;
    }
 
    // Returns the index of the rightmost occurrence of the
    // given key in the array
    private static int getRightPosition(int[] arr, int left,
                                        int right, int key)
    {
        while (right - left > 1)
        {
            int mid = left + (right - left) / 2;
            if (arr[mid] <= key)
            {
                left = mid;
            }
            else
            {
                right = mid;
            }
        }
        return left;
    }
 
    // Returns the count of occurrences of the given key in
    // the array
    public static int countOccurrences(int[] arr, int key)
    {
        int left = getLeftPosition(arr, -1, arr.Length - 1, key);
        int right = getRightPosition(arr, 0, arr.Length, key);
 
        if (arr[left] == key && key == arr[right])
        {
            return right - left + 1;
        }
        return 0;
    }
 
    public static void Main(string[] args)
    {
        int[] arr = { 1, 2, 2, 2, 3, 4, 4, 5, 5 };
        int key = 2;
        Console.WriteLine(countOccurrences(arr, key)); // Output: 3
    }

示例代码 zn6R6a - Online C++0x Compiler & Debugging Tool - Ideone.com。   

        问题陈述: 给定一个由不同元素组成的排序数组,并且该数组在未知位置旋转。找到数组中的最小元素。我们可以在下图中看到示例输入数组的图示。

        我们收敛搜索空间直到l和r 指向单个元素。如果中间位置落在第一个脉冲中,则不满足条件 A[m] < A[r],我们将搜索空间收敛到 A[m+1 … r]。如果中间位置落在第二个脉冲中,则满足条件 A[m] < A[r],我们将搜索空间收敛到 A[1 … m]。在每次迭代中,我们都会检查搜索空间大小,如果它是 1,我们就完成了。
        下面给出的是算法的实现。 你能想出不同的实施方案吗?   

using System;
 
public class Program
{
    public static int BinarySearchIndexOfMinimumRotatedArray(int[] A, int l, int r)
    {
        // Extreme condition, size zero or size two
        int m;
 
        // Precondition: A[l] > A[r]
        if (A[l] >= A[r])
        {
            return l;
        }
 
        while (l <= r)
        {
            // Termination condition (l will eventually fall on r, and r always
            // points to the minimum possible value)
            if (l == r)
            {
                return l;
            }
 
            m = l + (r - l) / 2;
 
            if (A[m] < A[r])
            {
                // Minimum can't be in the range
                // (m < i <= r), we can exclude A[m+1 ... r]
                r = m;
            }
            else
            {
                // Minimum must be in the range (m < i <= r),
                // we must search in A[m+1 ... r]
                l = m + 1;
            }
        }
 
        return -1;
    }
 
    public static int BinarySearchIndexOfMinimumRotatedArray(int[] A, int size)
    {
        return BinarySearchIndexOfMinimumRotatedArray(A, 0, size - 1);
    }
 
    public static void Main()
    {
        int[] A = { 6, 7, 8, 9, 1, 2, 3, 4, 5 };
        int size = A.Length;
 
        int minIndex = BinarySearchIndexOfMinimumRotatedArray(A, size);
 
        Console.WriteLine("The index of the minimum element in the rotated array is: " + minIndex);
    }

 请参阅示例测试用例 KbwDrk - Online C++0x Compiler & Debugging Tool - Ideone.com。 

练习: 
1. 称为signum(x, y)的函数 定义为,

Signum(x, y) = -1 如果 x < y 
             = 0 如果 x = y 
             = 1 如果 x > y

您是否遇到过比较行为类似于符号函数的指令集?它能让二分搜索的第一个实现变得最优吗? 

2. 实现floor函数的ceil函数复制品。 

3. 与你的朋友讨论“二分查找是否是最优的(比较次数最少)?为什么不在排序数组上进行三元搜索或插值搜索?与二分搜索相比,您什么时候更喜欢三元搜索或插值搜索?” 

4. 画出二分搜索的树表示(相信我,这对你理解二分搜索的内部原理有很大帮助)。  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/544682.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

NSL-KDD数据集详细介绍及下载

链接&#xff1a;https://pan.baidu.com/s/1hX4xpVPo70vwLIo0gdsM8A?pwdq88b 提取码&#xff1a;q88b 一般认为数据质量决定了机器学习性能的上限,而机器学习模型和算法的优化最多 只能逼近这个上限。因此在数据采集阶段需要对采集任务进行规划。在数据采集之前, 主要是从数据…

第十二讲 查询计划 优化

到目前为止&#xff0c;我们一直在说&#xff0c;我们得到一个 SQL 查询&#xff0c;我们希望可以解析它&#xff0c;将其转化为某种逻辑计划&#xff0c;然后生成我们可以用于执行的物理计划。而这正是查询优化器【Optimizer】的功能&#xff0c;对于给定的 SQL &#xff0c;优…

.net框架和c#程序设计第三次测试

目录 一、测试要求 二、实现效果 三、实现代码 一、测试要求 二、实现效果 数据库中的内容&#xff1a; 使用数据库中的账号登录&#xff1a; 若不是数据库中的内容&#xff1a; 三、实现代码 login.aspx文件&#xff1a; <% Page Language"C#" AutoEventW…

DB schema表中使用全局变量及在DB组件中查询

DB schema表中使用全局变量及在DB组件中查询 规则如下&#xff1a; 使用如下&#xff1a; 如果在unicloud-db组件上不加判断条件&#xff0c;就会报错&#xff0c;并进入到登录页。 那么就会进入到登录页&#xff0c;加上了判断条件&#xff0c;有数据了就不会了。 因为在sc…

TQ15EG开发板教程:在MPSOC上运行ADRV9371(vivado2018.3)

首先需要在github上下载两个文件&#xff0c;本例程用到的文件以及最终文件我都会放在网盘里面&#xff0c; 地址放在本文最后。首先在github搜索hdl选择第一个&#xff0c;如下图所示 GitHub网址&#xff1a;https://github.com/analogdevicesinc/hdl/releases 点击releases…

【Maven工具】

maven Maven是一个主要用于Java项目的构建自动化工具。它有助于管理构建过程&#xff0c;包括编译源代码、运行测试、将编译后的代码打包成JAR文件以及管理依赖项。Maven使用项目对象模型&#xff08;POM&#xff09;文件来描述项目配置和依赖关系。 Maven通过提供标准的项目…

分布式系统中的唯一ID生成方法

通常在分布式系统中&#xff0c;有生成唯一ID的需求&#xff0c;唯一ID有多种实现方式。我们选择其中几种&#xff0c;简单阐述一下实现原理、适用场景、优缺点等信息。 目录 数据库多主复制UUID工单服务器雪花算法总结 数据库多主复制 数据库通常有自增属性&#xff0c;在单机…

解决vue启动项目报错:npm ERR! Missing script: “serve“【详细清晰版】

目录 问题描述问题分析和解决情况一解决方法情况二&#xff08;常见于vue3&#xff09;解决方法情况三解决方法 问题描述 在启动vue项目时通常在控制台输入npm run serve 但是此时出现如下报错&#xff1a; npm ERR! Missing script: "serve" npm ERR! npm ERR! T…

80% 的人都不会的 15 个 Linux 实用技巧

熟悉 Linux 系统的同学都知道&#xff0c;它高效主要体现在命令行。通过命令行&#xff0c;可以将很多简单的命令&#xff0c;通过自由的组合&#xff0c;得到非常强大的功能。 命令行也就意味着可以自动化&#xff0c;自动化会使你的工作更高效&#xff0c;释放很多手工操作&…

纸制品ERP怎么样

在纸制品行业中&#xff0c; ERP系统的应用已经成为提升企业竞争力的关键因素。本文将探讨万达宝ERP系统在制造成本控制、商品生命周期管理以及自动对接主流平台方面的作用&#xff0c;并分析其在业务流程优化、高效调节各类关系以及多种模式生产方面的特点和益处。 制造成本控…

【数据结构(六)】队列

❣博主主页: 33的博客❣ ▶️文章专栏分类:数据结构◀️ &#x1f69a;我的代码仓库: 33的代码仓库&#x1f69a; &#x1faf5;&#x1faf5;&#x1faf5;关注我带你学更多数据结构知识 目录 1.前言2.概念3.队列的使用4.循环队列5.双端队列6.经典习题6.1队列实现栈6.2栈实现队…

【学习笔记十】EWM自动产品包装配置

一、确定包装物料建议的程序 1.定义内向交货处理的凭证类型 2.确定包装物料建议的程序确定原理 使用可以确定包装材料建议的过程来指定业务代码。系统使用这些业务代码查找包装规格。包装期间&#xff0c;系统可建议包装材料。如果系统确定包装规格并建议包装材料&#xff0c;…

Maven创建项目

目录 1.创建项目 2.从Maven Repository: Search/Browse/Explore (mvnrepository.com)链接&#xff0c;下载API 3.1.0 3.在main文件内创建webapp文件夹&#xff0c;再webapp文件夹内创建WEB-INF文件夹&#xff0c;在WEB-INF文件夹内创建web.xml 4.网络编程 5.打包 6.部署 …

Python学习笔记16 - 函数

函数的创建和调用 函数调用的参数传递 函数的返回值 函数的参数定义 变量的作用域 递归函数 斐波那契数列 总结

网络编程套接字(二)之UDP服务器简单实现

目录 一、服务端UdpServer 1、udp_server.hpp 1、服务器的初始化 2、服务器的运行 2、udp_server.cc 二、客户端UdpClient udp_client.cc 三、完整代码 一、服务端UdpServer 1、udp_server.hpp 首先&#xff0c;我们在该文件中&#xff0c;将服务器封装成一个类&#…

网络抓包工具使用

一、下载安装 &#xff08;1&#xff09; linux&#xff1a; ① 使用 yum install tcpdump -y 安装 **tcpdump**工具 ② 编译安装 yum -y install gcc-c yum -y install flex yum -y install bison官网下载tcpdump和libpcap 官网地址:https://www.tcpdump.org/index.html#lat…

网红天水海英麻辣烫改名:还是商标的问题!

近日火爆网络的天水海英麻辣烫改名&#xff0c;改成“哈海英麻辣烫”&#xff0c;并打了TM&#xff0c;表示此商标名称商标局已经受理并下发通知书&#xff0c;普推知产老杨检索分析&#xff0c;改名的主要原因还是商标。 对于餐饮店和麻辣烫核心类别就在43类别及30类方便食品&…

表格单列相同字段值合并

用specName(el.specName row.specName)和id的区别(el.id row.id)&#xff0c;使用id的时候id是唯一值&#xff0c;判断的时候不会出现重复情况&#xff0c;使用specName的时候&#xff0c;如果有重复的值&#xff0c;会出现合并错位的情况。 解决方案&#xff1a;先按照specT…

【树哈希】CF1182D Complete Mirror

CF1182D - Complete Mirror Description 给定一个 n n n 个点的无根树&#xff0c;求一个树根 r o o t root root,使得对于任意两个节点 v 1 , v 2 v_1,v_2 v1​,v2​&#xff0c;若满足 d i s t ( v 1 , r o o t ) d i s t ( v 2 , r o o t ) dist(v_1,root)dist(v_2,ro…

CUDA编程---全局内存

CUDA内存模型概述 内存的访问和管理是所有编程语言的重要部分。在现代加速器中&#xff0c;内存管理对高性能计算有着很大的影响。因为多数工作负载被加载和存储数据的速度所限制&#xff0c;所以有大量低延迟、高带宽的内存对性能是十分有利的。 然而&#xff0c;大容量、高性…