1 对数器,二分查找,

news2024/11/13 11:17:19

文章目录

    • 对数器
    • 二分查找
      • **1. 有序序列二分查找**
      • **2. 在一个有序数组中,找<=某个数最右侧的位置**
      • **3. 在一个有序数组中,找>=某个数最左侧的位置**
      • **4. 无序序列二分查找 ,求局部最小值**

对数器

对数器用于在自己的本地平台验证算法正确性,用于算法调试,无需online judge。

好处:

  • 没找到线上测试的online judge,则可以使用对数器。
  • 大数据样本出错时,快速找到出错地方。
  • 贪心策略使用,直接验证是否正确

实现原理:

  • 两个算法对比结果, 用一个无误的算法验证另一个算法, 无误的算法可能算法较差

代码实现:

  • 如下代码, insertSort 插入排序 用库排序sort 算法 来验证
  • 每次制造 随机长度随机值的数组.
#include <algorithm>
using namespace std;
void Swap(int &a, int &b)
{
    int temp = a;
    a = b;
    b = temp;
}
void insertSort(vector<int> &v)
{
    for (int i = 0; i < v.size() - 1; i++)
    {
        int end=i;
        while (end >= 0)
        {
            if (v[end + 1] < v[end])
            {
                Swap(v[end + 1], v[end]);
                end--;
            }
            else
            {
                break;
            }
        }
    }
}
void print(vector<int> &v)
{
    for (auto e : v)
    {
        cout << e << " ";
    }
    cout << endl;
}
void test1()
{
    //vector<int> v = {6, 5, 4, 3, 2, 1};
    vector<int> v = {6, 6, 9, 10, 2,2, 1};

    insertSort(v);
    print(v);
}


//准备一个随机数组(样本)生成器
//函数名:generateRandomVector
//函数功能描述:随机数组(样本)生成器
//函数参数: size    生成数组最大尺寸
//         value   数组每个元素的最大值
//返回值:  vector<int> 生成的数组
//for test
vector<int> generateRandomVector(int size, int value)
{
    //time 函数返回从 1970 年 1 月 1 日午夜开始到现在逝去的秒数,因此每次运行程序时,它都将提供不同的种子值。
    srand((int)time(NULL));//为随机数生成器产生随机种子
    //分配随机大小的数组,产生随机数的范围公式number = (rand()%(maxValue - minValue +1)) + minValue;
    vector<int> result(rand() % (size + 1));
    for (auto i = 0; i < result.size(); i++)
    {
        result[i] = rand() % (value + 1);
    }

    return result;

}

//大样本测试
//函数名:main
//函数功能描述:大样本测试
//函数参数: size    生成数组最大尺寸
//         value   数组每个元素的最大值
//返回值:  vector<int> 生成的数组
//for test
int main()
{
    auto test_time = 50000;//测试次数,设置比较大,排除特殊情况
    auto size = 10;//生成数组最大尺寸
    auto value = 30;//生成数组每个元素的最大值
    auto if_accept = true;//方法是否正确标志位
	for(auto i = 0; i < test_time; i++)
	{
        //拷贝初始化,生成新的数组向量
        vector<int> nums(generateRandomVector(size, value));
        //生成两个临时数组拷贝
        vector<int> nums1(nums);
        vector<int> nums2(nums);

		//绝对正确方法
        sort(nums1.begin(), nums1.end());
		//自己写的方法,想要测试的算法
        insertSort(nums2);
		//判断两个向量是否相同,vector类已经重载了比较运算符,不用自己实现,不相同说明算法不正确
		if(nums1 != nums2)
		{
            if_accept = false;
			//输出结果不相等的原始向量
			for(auto c: nums)
			{
                cout << c << " ";
			}
			break;
		}
		
	}
	//输出结果
    cout << (if_accept ? "nice!\n" : "false!\n");
    
}

二分查找

1. 有序序列二分查找

代码实现:

bool binarySearch(vector<int>& v , int targer)
{
    if(v.empty())return false;
    int L=0;
    int R=v.size()-1;
    int mid=0;
   // while(L<=R)// 以 L和R之间至少一个数,二分的逻辑就不一样了
    while(L<R)  // 以L和R之间至少两个数, 最后一次需要判断一下L的位置,已经验证过了,边界条件就是这样.
    {
        mid=L + (R-L>>1);
        if(v[mid] == targer)
        {
            return true;
        }
        else if(v[mid] > targer)
        {
            R = mid - 1;
        }
        else
        {
            L = mid + 1;
        }
    }
    return v[L] == targer; // 最后一次没有判断, 两种情况 L==R , R == L-1 -- R已经判断了,所以两种情况都是需要判断L的,有点难理解这个边界条件;
}

边界控制:
在这里插入图片描述

2. 在一个有序数组中,找<=某个数最右侧的位置

解题步骤:

  • 两种方式可能就是边界不一样,代码二每次都要检查最后的L下标。
  • 算法分析:
  • 找到<=某个数时使用index记录,继续往右找。

代码一:

int nearestIndexR1(vector<int>& v,int targer)
{
    int L=0;
    int R=v.size()-1;
    int index=-1;
    while(L<=R)
    {
        int mid = L + ((R-L)>>1);
        if(v[mid]<=targer)
        {
            index=mid;
            L=mid+1;
        }
        else
        {
            R = mid -1;
        }
    }
    return index;
}

代码二:

int nearestIndexR2(vector<int>& v,int targer)
{
    int L=0;
    int R=v.size()-1;
    int index=-1;
    while(L<R)
    {
        int mid = L + ((R-L)>>1);
        if(v[mid]<=targer)
        {
            index=mid;
            L=mid+1;
        }
        else
        {
            R = mid -1;
        }
    }
    if(v[L]<=targer)index=L;
    return index;
}

3. 在一个有序数组中,找>=某个数最左侧的位置

解题步骤:

  • 与2类似。
int nearestIndexL(vector<int>& v,int targer)
{
    int L=0;
    int R=v.size()-1;
    int index=-1;
    while(L<=R)
    {
        int mid= L + ((R-L)>>1);
        if(v[mid]>=targer)
        {
            index = mid ;
            R = mid -1 ;
        }
        else
        {
            L = mid +1;
        }
    }    
    return index;
}

4. 无序序列二分查找 ,求局部最小值

在一个无序数组中, 值有可能正, 负, 或者零, 数组中任由两个相邻的数一定不相等.
定义局部最小:
1.长度为1,arr[0]就是局部最小;
2.数组的开头,如果arr[0] < arr[1] ,arr[0]被定义为局部最小。
3.数组的结尾,如果arr[N-1] < arr[N-2] ,arr[N-1]被定义为局部最小。
任何一个中间位置i, 即数组下标1~N-2之间, 必须满足arr[i-1] < arr[i] <arr[i+1] ,叫找到一个局部最小。
请找到任意一个局部最小并返回。

需要注意:

  • 二分不一定要有序才能二分。
    1. 数据状况特殊。(无序的)
    1. 问题特殊 。(局部最小值)
  • 1和2结合分析,就有可能找出最优解,这种能力需要锻炼。
  • 二分最优解,就是找出具有排他性的规律。

解题步骤:

任意两个都相邻是不相等的,所以中间必有存在一个变化曲线, 但是为什么先往下降,最后是上扬
中间我不管你怎么连这个变化曲线一定存在局部最小
在这里插入图片描述

  • 局部最小值一定存在,好像是什么定理。
  • begin是数组首元素下标,end是数组尾元素下标,nums是数组。
  • if nums[begin] < nums[begin+1] ,找到了,返回bgein。
  • if nums[end] < nums[end-1] ,找到了, 返回end。
  • else
  • nums[begin] > nums[begin+1] 和 nums[end] > nums[end-1]
    • 往begin+1 和 end-1 之间找, nums[i] < nums[i-1] && nums[i]< nums[i+1]
  • 查找步骤:
  • 看代码把,有点难解释,就是找上扬和下趋

如图:
四种情况
在这里插入图片描述

int getLessIndex(vector<int>& nums)
{
    if(nums.empty())return -1;
    if(1<nums.size() && nums[0]<nums[1])return 0;
    if(nums[nums.size()-2]<nums[nums.size()-1])return nums.size()-1;

    int left = 1;
    int right = nums.size()-2;
    int mid=0;
    while(left<right)
    {
        mid=left+ (right-left>>1);
        if(nums[mid]>nums[mid+1])
        {
            left = mid +1 ;
        }
        else if (nums[mid]>nums[mid-1])
        {
            right = mid -1;
        }
        else{
            return mid;
        }
    }
    if(nums[left]nums[left+1] && nums[left]< nums[left-1]) return left;
    return -1;
}
void testgetLessIndex()
{
    vector<int> v = {5,4,3,2,1,10,9};
    cout<< v[getLessIndex(v)]<<endl;
}
int main()
{
    testgetLessIndex();
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

百度、谷歌等搜索引擎高效搜索方法 —— 更快速搜索到你想要内容

一、常用搜索方法 1、限定标题 intitle 又被称为去广告搜索法&#xff0c;intitle命令&#xff0c;即in title&#xff08;在标题里&#xff09;返回的的结果是网页的标题包含该关键词。一般情况下搜索的关键词都会在标题里出现&#xff0c;使用intitle命令一般是在特殊需求下…

极乐迪斯科(风格) | Disco Elysium – Style LoRA

目录 What is this ❓How to use / 使用方法 &#x1f4dd;其他信息与参数: 模型演示&#xff08;多图预警&#xff09; 正面tag 负面tag What is this LoRA版本的极乐迪斯科风格模型, 使用共计15张图片, 分辨率为1024*1024, 用Anything v4.5训练. 其他模型没有经过测试,…

Linux之【多线程】生产者与消费者模型BlockQueue(阻塞队列)

生产者与消费者模型 一、了解生产者消费者模型二、生产者与消费者模型的几种关系及特点三、BlockQueue&#xff08;阻塞队列&#xff09;3.1 基础版阻塞队列3.2 基于任务版的阻塞队列3.3 进阶版生产消费模型--生产、消费、保存 四、小结 一、了解生产者消费者模型 举个例子&am…

计算机组成原理第五章(3)DMA处理

三种控制方式&#xff1a;程序查询程序中断DMA方式 回顾一下 之前的中断控制方式&#xff0c;如果是输入命令&#xff0c;先启动命令&#xff0c;通过地址总线选择相应的接口&#xff0c;通过地址译码之后的到选择电路&#xff0c;这个接口准备开始工作。 启动外部设备&#…

网络编程总结一:

一、网络基础&#xff1a; 概念&#xff1a;1> 网络编程的本质就是进程间的通信&#xff0c;只不过进程分布在不同的主机上 2>在跨主机传输过程中&#xff0c;需要确定通信协议后&#xff0c;才可以通信 1. OSI体系结构&#xff08;重点&#xff09; 定义7层模型&…

类和对象(上篇)【C++】

C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解问题的步骤&#xff0c;通过函数调用逐步解决问题。 C是基于面向对象的&#xff0c;关注的是对象&#xff0c;将一件事拆分成不同的对象&#xff0c;靠对象之间的交互完成。 目录 一、类的定义 二、访问限定符…

【小样本分割 2020 TPAMI 】PFENet

文章目录 【小样本分割 2020 TPAMI 】PFENet1. 简介1.1 问题1) 高级特征误用造成的泛化损失2) 查询样本和空间样本之间的空间不一致 1.2 方法 2. 网络2.1 整体架构2.2 先验掩膜生成2.3 FEM模块 3. 代码 【小样本分割 2020 TPAMI 】PFENet 论文题目&#xff1a;Prior Guided Fea…

flinkCDC相当于Delta.io中的什么 delta.io之CDF

类似flink CDC databricks 官方文档: How to Simplify CDC With Delta Lakes Change Data Feed - The Databricks Blog delta.io 官方文档: Change data feed — Delta Lake Documentation 概述 更改数据馈送 (CDF) 功能允许 Delta 表跟踪 Delta 表版本之间的行级更改 在…

C语言函数与递归

目录&#x1f60a; 1. 函数是什么&#x1f43e; 2. 库函数&#x1f43e; 3. 自定义函数&#x1f43e; 4. 函数参数&#x1f43e; 5. 函数调用&#x1f43e; 6. 函数的嵌套调用和链式访问&#x1f43e; 7. 函数的声明和定义&#x1f43e; 8. 函数递归&#x1f43e; 1. 函…

二叉搜索树(内含AVL树的旋转操作的详细解释)

二叉搜索树 二叉搜索树的概念二差搜索树结构设计二叉搜索树的操作以及实现遍历判空插入查找删除(☆☆☆)二叉搜索树的其他方法 二叉搜索树的应用二叉搜索树的性能分析二叉树习题练习AVL树AVL树的概念AVL树的结构设计AVL树的插入(非常重要)AVL树的旋转(☆☆☆☆☆)AVL树的插入操…

基于STATCOM的风力发电机稳定性问题仿真分析(Simulink)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

网页三剑客之 HTML

本章开始我们来介绍一下网页前端部分&#xff0c;我们只是简单的介绍一些常用的各种标签&#xff0c;其目的在于为我们后面的项目做准备。 我们并不要求能完全掌握前端的语法&#xff0c;但是在见到以后能够认识这些代码就可以了。 想走后端开发的&#xff0c;前端不需要多么…

【C++】哈希和unordered系列封装

1.哈希 1.1 哈希概念 顺序结构以及平衡树中&#xff0c;元素关键码与其存储位置之间没有对应的关系&#xff0c;因此在查找一个元素时&#xff0c;必须要经过关键码的多次比较。顺序查找时间复杂度为O(N)&#xff0c;平衡树中为树的高度&#xff0c;即O( l o g 2 N log_2 N l…

CSAPP学习笔记 2 浮点数(自用)

1. 首先 我们回忆一下计算机思维导论的编码问题 小白鼠问题 (107条消息) 小白鼠喝水问题------计算机思维 编码思想(自用)_和光同尘463的博客-CSDN博客 2. 对于一些可表示的浮点数比如 101.11可以用二进制精确表示 因为是2的倍数 但是 对于一些不可整除的浮点数 我们又如何…

阿里云服务器部署node项目笔记

阿里云部署node项目笔记 此过程中全部安装都按照B站教程实现本篇是个人笔记&#xff0c;许多细节并未陈述比如开发阿里云对应端口等&#xff0c;不是完整的过程&#xff0c;如有误导在此致歉。 安装node报错linux查看nginx配置文件 使用 nginx -t mongodb数据库安装解决&#x…

【JAVA】#详细介绍!!! 文件操作之File对象(1)!

本文内容不涉及文件内容操作&#xff0c;主要是对指定文件元信息的获取&#xff0c;以及通过java代码如何创建一个文件或者删除文件 目录 文件操作的File对象 File对象的基本操作方法 得到文件&#xff08;夹&#xff09;对象的信息元 1.getParent 2. getName 3.getPath 4…

CentOS 安装与配置Nginx【含修改配置文件】

1.安装Nginx yum install nginx -y2.启动Nginx systemctl start nginx查询是否启动nginx systemctl status nginx3.尝试访问 这是默认的配置文件 # For more information on configuration, see: # * Official English Documentation: http://nginx.org/en/docs/ # * …

wordcloud制作词云图

wordcloud制作词云图 wordcloud中文方框问题 jieba&#xff08;分词&#xff09;jieba库分词的三种模式 wordcloud WordCloud(font_pathNone, width400, height-200,margin2,maskNone, max_words200, min_font_size4, stopwordsNone,background_colorblack, max_font_sizeNone…

js中setinterval怎么用?怎么才能让setinterval停下来?

setinterval()是定时调用的函数&#xff0c;可按照指定的周期&#xff08;以毫秒计&#xff09;来调用函数或计算表达式。 setinterval()的作用是在播放动画的时&#xff0c;每隔一定时间就调用函数&#xff0c;方法或对象。 setInterval() 方法会不停地调用函数&#xff0c;…

浙大数据结构与算法一些有意思的理论基础题

堆栈 有人给出了堆栈用数组实现的另一种方式&#xff0c;即直接在函数参数中传递数组和top变量&#xff08;而不是两者组成的结构指针&#xff09;&#xff0c;其中Push操作函数设计如下。这个Push函数正确吗&#xff1f;为什么&#xff1f; #define MaxSize 100 ElementTyp…