STL源码剖析 lower_bound | upper_bound | binary_search

lower_bound

  • 二分查找的一种版本,试图在已经排序的区间内查找元素value,如果区间内存在和value数值相等的元素,便返回一个迭代器,指向其中的第一个元素。
  • 如果没有数值相等的元素,会返回假设这个元素存在的前提下应该出现的位置,也就是返回一个指向第一个不小于value的元素的迭代器
  • 如果查询的数值value大于区间内任何一个元素则返回last
  • 综上所述:lower_bound返回的是不破坏排序状态的前提下,可插入value的第一个位置

  • 版本一使用operator<
  • 版本二使用仿函数 comp(*j,value)为true
template <class ForwardIterator,class T>
ForwardIterator lower_bound(ForwardIterator first,ForwardIterator last,const T& value){ForwardIterator it;typename std::iterator_traits<ForwardIterator>::difference_type count,step;count = std::distance(first,last);while (count > 0){it = first;step = count / 2;std::advance(it,step);if(*it < value){first = ++it;count = count - step+1;} else{count = step;}}return first;
}
// lower_bound/upper_bound example
#include <iostream>     // std::cout
#include <algorithm>    // std::lower_bound, std::upper_bound, std::sort
#include <vector>       // std::vectorint main () {int myints[] = {10,20,30,30,20,10,10,20};std::vector<int> v(myints,myints+8);           // 10 20 30 30 20 10 10 20std::sort (v.begin(), v.end());                // 10 10 10 20 20 20 30 30std::vector<int>::iterator low,up;low=std::lower_bound (v.begin(), v.end(), 20); //          ^up= std::upper_bound (v.begin(), v.end(), 20); //                   ^std::cout << "lower_bound at position " << (low- v.begin()) << '\n';std::cout << "upper_bound at position " << (up - v.begin()) << '\n';return 0;
}

upper_bound

  • 不破坏插入顺序的情况下返回可以插入的最后一个合适的位置
  • 即如果元素存在,返回的迭代器指向的是value的下一个数值,而不是指向value本身,类似于last
template <class ForwardIterator,class T>
ForwardIterator upper_bound(ForwardIterator first,ForwardIterator last,const T& value){ForwardIterator it;typename std::iterator_traits<ForwardIterator>::difference_type count,step;count = std::distance(first,last);while (count > 0){it = first;step = count / 2;std::advance(it,step);if(!(*it < value)){first = ++it;count = count - step+1;} else{count = step;}}return first;
}

binary_search

  • 二分查找
  • 利用lower_bound 如果value存在返回其应该出现的位置 ,对指定位置的迭代器进行解引用和value比较,确定元素是否存在
template <class ForwardIterator,class T>
ForwardIterator binary_search(ForwardIterator first,ForwardIterator last,const T& value){first = std::lower_bound(first,last,value);return (first!=last && !(*first > value));
}
// binary_search example
#include <iostream>     // std::cout
#include <algorithm>    // std::binary_search, std::sort
#include <vector>       // std::vectorbool myfunction (int i,int j) { return (i<j); }int main () {int myints[] = {1,2,3,4,5,4,3,2,1};std::vector<int> v(myints,myints+9);                         // 1 2 3 4 5 4 3 2 1// using default comparison:std::sort (v.begin(), v.end());std::cout << "looking for a 3... ";if (std::binary_search (v.begin(), v.end(), 3))std::cout << "found!\n"; else std::cout << "not found.\n";// using myfunction as comp:std::sort (v.begin(), v.end(), myfunction);std::cout << "looking for a 6... ";if (std::binary_search (v.begin(), v.end(), 6, myfunction))std::cout << "found!\n"; else std::cout << "not found.\n";return 0;
}

next_permutation 和 prev_permutation

  • 函数会取得first,last区间范围内所标示的序列的下一个组合,则返回true,否则false 

random_shuffle

  • 随机重排,N!可能性 N = last - first
  • 均匀分布 每种序列被选中的可能性均为1/N!
  • 版本一使用 内部随机数
  • 版本二使用 使用随机数仿函数,需要仿函数传递的方式是引用传递,因为这个考虑到随机数产生器拥有局部状态,每次调用都会被改变,从而保障数据的随机性
template <class RandomAccessIterator, class RandomNumberGenerator>void random_shuffle (RandomAccessIterator first, RandomAccessIterator last,RandomNumberGenerator& gen)
{iterator_traits<RandomAccessIterator>::difference_type i, n;n = (last-first);for (i=n-1; i>0; --i) {swap (first[i],first[gen(i+1)]);}
}
// random_shuffle example
#include <iostream>     // std::cout
#include <algorithm>    // std::random_shuffle
#include <vector>       // std::vector
#include <ctime>        // std::time
#include <cstdlib>      // std::rand, std::srand// random generator function:
int myrandom (int i) { return std::rand()%i;}int main () {std::srand ( unsigned ( std::time(0) ) );std::vector<int> myvector;// set some values:for (int i=1; i<10; ++i) myvector.push_back(i); // 1 2 3 4 5 6 7 8 9// using built-in random generator:std::random_shuffle ( myvector.begin(), myvector.end() );// using myrandom:std::random_shuffle ( myvector.begin(), myvector.end(), myrandom);// print out content:std::cout << "myvector contains:";for (std::vector<int>::iterator it=myvector.begin(); it!=myvector.end(); ++it)std::cout << ' ' << *it;std::cout << '\n';return 0;
}

partial_sort / partial_sort_copy

  • 函数接受一个middle迭代器,位于起始first和终止last迭代器内部,但是只对first到middle区间内的元素进行从小到大的排序,middle到last区间内的元素乱序
  • 这个函数的含义是 保证middle到first内的元素是按照从小到大排序的,但是middle到last是相较于middle之前的元素要大,但是没人有何特定的顺序
  • 第一版本使用 less-than操作符
  • 第二版本使用 仿函数comp,算法内部采用heap sort来完成任务 ,max_heap大根堆,将每一个元素和最大的数值进行比较,也就是第一个元素。

// partial_sort example
#include <iostream>     // std::cout
#include <algorithm>    // std::partial_sort
#include <vector>       // std::vectorbool myfunction (int i,int j) { return (i<j); }int main () {int myints[] = {9,8,7,6,5,4,3,2,1};std::vector<int> myvector (myints, myints+9);// using default comparison (operator <):std::partial_sort (myvector.begin(), myvector.begin()+5, myvector.end());// using function as compstd::partial_sort (myvector.begin(), myvector.begin()+5, myvector.end(),myfunction);// print out content:std::cout << "myvector contains:";for (std::vector<int>::iterator it=myvector.begin(); it!=myvector.end(); ++it)std::cout << ' ' << *it;std::cout << '\n';return 0;
}

sort  排序

  •  RandomAccessIterators(随机迭代器),将区间内的元素按照从小到大进行排序
  • 第二版本:仿函数作为排序的准则
  • STL关系型数据库内部使用红黑树,已经经过了排序,不需要sort
  • 序列式容器:stack queue  priority_queue元素按照特定的方式进行出入,不允许排序
  • vector 和 deque 迭代器属于RandomAccessIterators 可以使用迭代器 sort
  • list的迭代器的类型是Bidirectioinallterators 不适用,使用数据成员自带的sort排序算法
  • slist的迭代器的类型是ForwardIterators 不适用,使用数据成员自带的sort排序算法
  • 数据量很大 使用快速排序,一旦数据量少于某个阈值就改用 插入排序,避免快速排序带来的额外负载;如果递归层次过深,就改用 堆排序

插入排序

快速排序

 equal_range

  • 使用lower_bound和upper_bound两个函数返回的迭代器组成pair元祖的形式,first指向等于元素的区间起始点,second指向等于元素的下一个位置处
  • 如果不存在,那么first和second都指向的同一个位置

template <class ForwardIterator, class T>pair<ForwardIterator,ForwardIterator>equal_range (ForwardIterator first, ForwardIterator last, const T& val)
{ForwardIterator it = std::lower_bound (first,last,val);return std::make_pair ( it, std::upper_bound(it,last,val) );
}
// equal_range example
// equal_range example
#include <iostream>     // std::cout
#include <algorithm>    // std::equal_range, std::sort
#include <vector>       // std::vectorbool mygreater (int i,int j) { return (i>j); }int main () {int myints[] = {10,20,30,30,20,10,10,20};std::vector<int> v(myints,myints+8);                         // 10 20 30 30 20 10 10 20std::pair<std::vector<int>::iterator,std::vector<int>::iterator> bounds;// using default comparison:std::sort (v.begin(), v.end());                              // 10 10 10 20 20 20 30 30bounds=std::equal_range (v.begin(), v.end(), 20);            //          ^        ^// using "mygreater" as comp:std::sort (v.begin(), v.end(), mygreater);                   // 30 30 20 20 20 10 10 10bounds=std::equal_range (v.begin(), v.end(), 20, mygreater); //       ^        ^std::cout << "bounds at positions " << (bounds.first - v.begin());std::cout << " and " << (bounds.second - v.begin()) << '\n';return 0;
}

inplace_merge (应用于有序区间)

  •  将两个排好顺序的子序列 合并形成一个单调递增的序列
  • 稳定排序
  • 如果使用额外的内存空间速度会很快,没有多余的内存空间也是可以进行元素的合并的

// inplace_merge example
#include <iostream>     // std::cout
#include <algorithm>    // std::inplace_merge, std::sort, std::copy
#include <vector>       // std::vectorint main () {int first[] = {5,10,15,20,25};int second[] = {50,40,30,20,10};std::vector<int> v(10);std::vector<int>::iterator it;std::sort (first,first+5);std::sort (second,second+5);it=std::copy (first, first+5, v.begin());std::copy (second,second+5,it);std::inplace_merge (v.begin(),v.begin()+5,v.end());std::cout << "The resulting vector contains:";for (it=v.begin(); it!=v.end(); ++it)std::cout << ' ' << *it;std::cout << '\n';return 0;
}

nth_element

  • 算法会重新排列[first ,last)区间 ,使得迭代器nth指向的元素于经过排序之后同一位置的元素数值相等,这个其实就是快速排序的思路一样,确定一个元素的位置,他的左边都是比他小的元素,他的右边都是比他大的元素

  • nth_element 比 partial_sort保证的更少,不保证左边和右边序列有序
  • 只支持随机访问迭代器

merge sort

  • 合并排序
  • 分而治之 
  • 需要额外内存

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

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

相关文章

java 匿名对象

概念 代码 package lesson.l10_oop;/*** Illustration** author DengQing* version 1.0* datetime 2022/7/1 13:39* function 匿名对象*/ public class Anonymous {public static void main(String[] args) { // 用法1new Teacher().say("dq");new Teacher()…

STL源码剖析 第七章 仿函数(函数对象)

函数对象&#xff1a;具有函数性质的对象使得用户像使用函数一样使用它一般函数提供两个版本&#xff0c;第一个版本使用operator < ;第二版本需要用户 指定某种操作第二版本就是设计一个函数&#xff0c;将函数指针作为算法的一个参数&#xff1b;或者将函数操作设计成为一…

开源合同管理系统_「物联网架构」最适合物联网的开源数据库

物联网产生大量的数据&#xff0c;包括流数据、时间序列数据、RFID数据、传感数据等。要有效地管理这些数据&#xff0c;就需要使用数据库。物联网数据的本质需要一种不同类型的数据库。以下是一些数据库&#xff0c;当与物联网一起使用时&#xff0c;会给出非常好的结果。物联…

java 方法重载

概念 代码 package lesson.l10_oop;/*** Illustration** author DengQing* version 1.0* datetime 2022/7/1 14:31* function 方法重载*/ public class Load {public static void main(String[] args) {Load load new Load();load.mOL(4);load.mOL(4, 5);load.mOL("ff&qu…

STL源码剖析 第八章 配接器

设计模式&#xff1a;将一个类的接口转化为另外一个类的接口 配接器的概观和分类 改变仿函数接口 函数配接器 &#xff1b;queue和stack 通过修饰deque函数接口来实现改变容器接口 容器配接器 &#xff1b; insert、reverse、iostream 等iterators他们的接口可以由ite…

python中random库_python标准库之random模块

Python中的random模块用于生成随机数。 下面具体介绍random模块的功能&#xff1a; 1.random.random() #用于生成一个0到1的 随机浮点数&#xff1a;0< n < 1.0 1 import random 2 a random.random() 3 print (a)2.random.uniform(a,b) #用于生成一个指定范围内的随机符…

java 可变个数形参

概念 案例 package lesson.l10_oop;/*** Illustration** author DengQing* version 1.0* datetime 2022/7/1 14:53* function 可变个数形参*/ public class ChangeableFormalParameter {public static void main(String[] args) {ChangeableFormalParameter parameter new Ch…

C++标准库 第七章 STL迭代器

迭代器 能力&#xff1a;行进和存取的能力Input迭代器 一次一个向前读取元素&#xff0c;按此顺序一个一个返回元素例子&#xff1a;从标准输入装置(键盘) 读取数据&#xff0c;同一个数据不会被读取两次&#xff0c;流水一样&#xff0c;指向的是逻辑位置使用前置式递增运算…

nacos集群的ap cp切换_阿里Nacos-配置-多环境

多环境的配置隔离是配置中心最基础的一个功能之一。不同的环境配置的值不一样&#xff0c;比如数据库的信息&#xff0c;业务的配置等。Spring Boot 多环境配置首先我们来回顾下在Spring Boot中用配置文件的方式怎么进行环境的隔离。默认我们都会创建一个application.propertie…

java 值传递机制

说明 案例1 案例2 案例3 案例4 案例5 案例6 package lesson.l11_oop2;/*** Illustration** author DengQing* version 1.0* datetime 2022/7/2 21:24* function 将对象作为参数传递给方法*/ public class Circle {double radius;public double findArea() {return Math.PI * Ma…

密码学专题 非对称加密算法指令概述 RSA

非对称加密算法也称为公开密钥算法&#xff0c;其解决了对称加密算法密钥需要预分配的难题&#xff0c;使得现代密码学的研究和应用取得了重大发展。非对称加密算法的基本特点如下: 加密密钥和解密密钥不相同;密钥对中的一个密钥可以公开(称为公开密钥);根据公开密钥很难推算出…

python元胞自动机模拟交通_结构专栏 | 解析DEFORM软件中的元胞自动机法

点击上方蓝色字体&#xff0c;关注我们导语金属材料的性能取决于内部的微观组织结构&#xff0c;而好的材料性能和价格是产品最大的优势。随着现代物理冶金、热成形技术、热处理技术和计算机技术的兴起与发展&#xff0c;使预测和控制金属材料热加工过程中的组织演变成为可能。…

java 递归

概念 代码 package lesson.l11_oop2;/*** Illustration** author DengQing* version 1.0* datetime 2022/7/2 21:42* function 递归&#xff1a;求n个数的和、乘积*/ public class Recursion {public static void main(String[] args) {Recursion recursion new Recursion();S…

密码学专题 非对称加密算法指令概述 DH算法指令

DH概述 用于密钥交换的公开算法&#xff0c;广泛应用于各种安全协议SSL协议同样支持DH算法DH算法使用之前需要预先共享两个参数&#xff0c;本原元g和模n&#xff0c;这两个参数影响到算法的安全性&#xff0c;因此需要预先生成并检测其安全性生成这些必要参数和管理这些参数的…

java 封装和隐藏 权限修饰符

概念 问题的引入 封装性的体现 权限修饰符 案例 package lesson.l11_oop2;/*** Illustration** author DengQing* version 1.0* datetime 2022/7/3 15:28* function*/ public class Person {private int age;public void setAge(int age) { /* if (age<0||age>…

密码学专题 非对称加密算法指令概述 DSA算法指令

DSA算法和DSA指令概述 DSA算法是美国国家标准的数字签名算法&#xff0c;只具备数字签名的功能不具备密钥交换的功能生成DSA参数然后生成DSA密钥&#xff0c;DSA参数决定了DSA密钥的长度三个指令首先是dsaparam指令&#xff0c;该指令主要用来生成DSA密钥参数&#xff0c;并提…

每天定时打开某个网页_Python科普帖定时通知

0 复习上一关我们学习了selenium&#xff0c;它有可视模式与静默模式这两种浏览器的设置方法&#xff0c;二者各有优势。然后学习了使用.get(URL)获取数据&#xff0c;以及解析与提取数据的方法。在这个过程中&#xff0c;我们操作对象的转换过程&#xff1a;除了上面的方法&am…

java 构造器

概念 案例1 package lesson.l11_oop2;/*** Illustration** author DengQing* version 1.0* datetime 2022/7/3 15:28* function*/ public class Person {private int age;private String name;public Person() {this.age 18;}public Person(int age, String name) {this.age …

密码学专题 信息摘要和数字签名指令

信息摘要 区别于对称加密和非对称加密&#xff0c;信息摘要算数是一种不可逆的操作&#xff0c;无论输入数据的大小输出的数据长度是固定的信息摘要算数对输入很敏感&#xff0c;即使数据变化很细微&#xff0c;输出的结果会出现很大的差异从不同输入得到相同的输出的概率非常…

dataframe 筛选_Spark.DataFrame与Spark.ML简介

本文是PySpark销量预测系列第一篇&#xff0c;后面会陆续通过实战案例详细介绍PySpark销量预测流程&#xff0c;包含特征工程、特征筛选、超参搜索、预测算法。在零售销量预测领域&#xff0c;销售小票数据动辄上千万条&#xff0c;这个量级在单机版上进行数据分析/挖掘是非常困…