工具函数algorithm
std::memset,对数据进行清零
Defined in header < cstring >
void* memset( void* dest, int ch, std::size_t count );
参数
dest - 指向要填充的对象的指针
ch - 填充字节
count - 要填充的字节数
返回值
dest
转换值 ch 为 unsigned char 并复制它到 dest 所指向对象的首 count 个字节。
作用是将某一块内存中的内容全部设置为指定的值ch, 这个函数通常为新申请的内存做初始化工作。作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法.
int a[20];
std::memset(a, 0, sizeof a);
for (int ai : a) std::cout << ai;
输出结果:
00000000000000000000
memset函数按字节对内存块进行初始化,所以不能用它将int数组初始化为0和-1之外的其他值(除非该值高字节和低字节相同)
memcpy(),内存拷贝函数
memcpy指的是C和C++使用的内存拷贝函数,函数原型为void *memcpy(void destin, void source, unsigned n);函数的功能是从源内存地址的起始位置开始拷贝若干个字节到目标内存地址中,即从源source中拷贝n个字节到目标destin中。
参数
destin-- 指向用于存储复制内容的目标数组,类型强制转换为 void 指针。
source-- 指向要复制的数据源,类型强制转换为 void 指针。
n-- 要被复制的字节数。
返回值
该函数返回一个指向目标存储区destin的指针。
功能
从源source所指的内存地址的起始位置开始拷贝n个字节到目标destin所指的内存地址的起始位置中。 [2]
所需头文件
C语言:#include<string.h>
C++:#include
#include <iostream>
using namespace std;
#include <string.h>
int main()
{
// memcpy()通用复制函数的使用
char src[10] = "012345678";
char dest[10];
char* pc = (char*)memcpy(dest, src, 10); //复制字节数据
cout << pc << endl;
int s1[3] = { 1,2,3 };
int d1[3];
int *pi = (int*)memcpy(d1, s1, 12);
cout << *pi << " " << *(pi + 1) << " " << *(pi + 2) << endl;
return 0;
}
std::fmin,比较求较小数
double fmin ( double x, double y );
返回两个浮点参数中的较小者,将NaN视为缺失数据(在NaN和数值之间选择数值)。
qsort()函数,快速排序
Defined in header
(1)
void qsort( void ptr, std::size_t count, std::size_t size, /compare-pred/ * comp );
void qsort( void ptr, std::size_t count, std::size_t size, /c-compare-pred/ * comp );
(2)
extern “C++” using /compare-pred/ = int(const void, const void); // exposition-only
extern “C” using /c-compare-pred/ = int(const void*, const void*); // exposition-only
Parameters
- ptr - pointer to the array to sort(指向待排序数组首元素的指针),ANSI C允许把指向任何数据类型的指针强制转换成指向void的指针,因此,qsort的第一个实际参数可以引用任何类型的数组
- count - number of elements in the array(待排序项的数量),函数原型把该值转换成size_t类型,是sizeof返回的整数类型。
- size - size of each element in the array in bytes(数组中每个元素的大小所占的内存大小,以字节为单位),由于qsort()函数把第一个参数转换为void指针,所以qsort不知道数组中每个元素的大小,例如,排序的数组时double类型,则size = sizeof(double)
- comp - comparison function which returns a negative integer value if the first argument is less than the second, a positive integer value if the first argument is greater than the second and zero if the arguments are equivalent.最后,还需要一个指向函数的指针,这个被指针指向的比较函数用于确定排序的顺序,该函数接收两个参数,分别指向待比较两项的指针a和b,如果a大于b,比较函数返回正数,相同返回0,a小于b则返回负数。
The signature of the comparison function should be equivalent to the following:
int cmp(const void *a, const void *b);
The function must not modify the objects passed to it and must return consistent results when called for the same objects, regardless of their positions in the array.(这个函数不能修改对象传递过来的值,必须在调用对象相同时返回相同的结果,并不考虑它们在数组中的位置)
#include <iostream>
#include <cstdlib>
#include <climits>
int main()
{
int a[] = {-2, 99, 0, -743, 2, INT_MIN, 4};
constexpr std::size_t size = sizeof a / sizeof *a;
std::qsort(a, size, sizeof *a, [](const void* a, const void* b)
{
//将void指针转换成int指针,再通过*取值
int arg1 = *static_cast<const int*>(a);
int arg2 = *static_cast<const int*>(b);
if(arg1 < arg2) return -1;
if(arg1 > arg2) return 1;
return 0;
// return (arg1 > arg2) - (arg1 < arg2); // possible shortcut
// return arg1 - arg2; // erroneous shortcut (fails if INT_MIN is present)
});
for(int ai : a)
std::cout << ai << ' ';
}
输出:
-2147483648 -743 -2 0 2 4 99
#include<iostream>
#include<cstdlib>
using namespace std;
#define NUM 10
void fillarray(double ar[], int n);
void showArray(const double*, int n);
int mycomp(const void *p1, const void *p2);
int main(void) {
double vals[NUM];
fillarray(vals, NUM);
cout << "Random list:" << endl;
showArray(vals, NUM);
qsort(vals, NUM, sizeof(double), mycomp);
cout << "Sorted list:" << endl;
showArray(vals, NUM);
return 0;
}
void fillarray(double ar[], int n) {
for (int i = 0; i < n; i++) {
ar[i] = (double)rand() / ((double)rand() + 0.1);
}
}
//从小到大的顺序
int mycomp(const void *p1, const void *p2) {
//要使用指向double的指针来访问这两个值
const double * a1 = (const double *)p1;
const double * a2 = (const double *)p2;
if (*a1 < *a2) {
return -1;
}
else if (*a1 == *a2) {
return 0;
}
else {
return 1;
}
}
void showArray(const double *ar, int size) {
for (int i = 0; i < size; i++) {
cout << ar[i] << " ";
if (i % 6 == 5) {
cout << endl;
}
}
cout << endl;
}
sort 容器快速排序
sort函数是C++的STL里面的一个强大的算法,是用来处理容器的非成员函数。它接受两个RandomAccessIterators(随机存取迭代器),然后将区间内的所有元素以渐增方式由小到大排序。另外一个版本则可以指定排序标准。
适用模板类概览
a) STL的所有关联性容器(例如map,set等)都有自动排序的功能(底层采用红黑树的结构),所以不需要用到sort算法。
b) 序列式容器中的stack、queue和priority-queue有特殊的出入口,不允许用户对元素排序。
c) 序列式容器中的vector、deque和list,前两者迭代器属于随机存取迭代器,适用,而list的迭代器为双向迭代器,不适用,如果要对list进行排序,可以使用它自己提供的成员函数sort()。
实现方法
数据量大的时候采用Quick Sort,分段递归排序。一旦分段后的数据量小于某个门槛,为避免Quick Sort的递归调用带来过大的额外符合,就该用Insertion Sort。如果递归层次太深,还会改用Heap Sort。
#include <algorithm>
#include <functional>
#include <array>
#include <iostream>
using namespace std;
bool cmp(int, int);
typedef struct student {
char name[20];
int math;
int english;
}Student;
bool studentCmp(Student a, Student b);
int main()
{
std::array<int, 10> s = { 5, 7, 4, 2, 8, 6, 1, 9, 0, 3 };
//使用默认的 < 符号,也就是从小到大排序
// sort using the default operator<
std::sort(s.begin(), s.end());
for (auto a : s) {
std::cout << a << " ";
}
std::cout << '\n';
//使用标准库中的比较函数,greater,从大到小;greater<int>() 递减, less<int>() 递增
// sort using a standard library compare function object
std::sort(s.begin(), s.end(), std::greater<int>());
for (auto a : s) {
std::cout << a << " ";
}
std::cout << '\n';
//使用结构体
// sort using a custom function object
struct {
bool operator()(int a, int b) const
{
return a < b;
}
} customLess;
std::sort(s.begin(), s.end(), customLess);
for (auto a : s) {
std::cout << a << " ";
}
std::cout << '\n';
//使用lambda匿名函数
// sort using a lambda expression
std::sort(s.begin(), s.end(), [](int a, int b) {
return a > b;
});
for (auto a : s) {
std::cout << a << " ";
}
std::cout << '\n';
cout << "也可以对普通数组排序" << endl;
int b[] = { 45,12,34,77,90,11,2,4,5,55 };
std::sort(b, b + 10);
for (int i = 0; i < 10; i++)
std::cout << b[i] << " ";
cout << "" << endl;
//第三个参数放入自己编写的比较函数
cout << "第三个参数放入自己编写的比较函数" << endl;
sort(b, b + 10, cmp);
for (int i = 0; i < 10; i++)
cout << b[i] << " ";
cout << "" << endl;
cout << "对结构体进行自定义排序" << endl;
Student student[4] = { {"apple",67,89},{"limei",90,56},{"apple",90,99} };
sort(student, student + 3, studentCmp);
for (int i = 0; i < 3; i++)
cout << student[i].name << " " << student[i].math << " " << student[i].english << endl;
}
//自定义函数
bool cmp(int a, int b) {
return a > b;
}
bool studentCmp(Student a, Student b) {
if (a.math > b.math)
return a.math < b.math;//按math从小到大排序
else if (a.math == b.math)
return a.english > b.english; //math相等,按endlish从大到小排序23
}
reverse函数的用法
reverse函数功能是逆序(或反转),多用于字符串、数组、容器。头文件是#include
reverse函数用于反转在[first,last)范围内的顺序(包括first指向的元素,不包括last指向的元素),reverse函数无返回值
string str="hello world , hi";
reverse(str.begin(),str.end());//str结果为 ih , dlrow olleh
vector<int> v = {5,4,3,2,1};
reverse(v.begin(),v.end());//容器v的值变为1,2,3,4,5
resize函数和reserve()
- resize(),设置大小(size);
- reserve(),设置容量(capacity);
函数原型:
void resize (size_type n);
void resize (size_type n, const value_type& val);
第一个参数是将容器的元素变成n个,第二个参数是将这n个元素变成val(没有就是默认值)
注意:resize不适用于array
如果当前大小大于所要求的n,容器后部的元素会被删除;如果当前大小小于n,会将新元素(默认为0)添加到容器后部。
copy()函数
元素复制算法copy。该算法主要用于容器之间元素的拷贝,即将迭代器区间[first,last)的元素复制到由复制目标result给定的区间[result,result+(last-first))中。下面我们来看看它的函数原型:
函数原形:
template<class InputIterator, class OutputIterator> OutputIterator
copy(
InputIterator _First,
InputIterator _Last,
OutputIterator _DestBeg );
参数
_First, _Last
指出被复制的元素的区间范围[ _First,_Last).
_DestBeg
指出复制到的目标区间起始位置
返回值
返回一个迭代器,指出已被复制元素区间的最后一个位置
#include <iostream>
#include <algorithm>
#include <vector>
#include<iterator>
using namespace std;
int main()
{
int myints[] = { 10, 20, 30, 40, 50, 60, 70 };
vector<int> myvector;
vector<int>::iterator it;
//使用迭代器
ostream_iterator<int> out(cout, " ");
myvector.resize(7); // 为容器myvector分配空间
//copy用法一:
//将数组myints中的七个元素复制到myvector容器中
copy(myints, myints + 7, myvector.begin());
cout << "myvector contains: ";
copy(myvector.begin(), myvector.end(), out);
cout << endl;
//copy用法二:
//将数组myints中的元素向左移动一位
copy(myints + 1, myints + 7, myints);
cout << "myints contains: ";
copy(myvector.begin(), myvector.end(), out);
cout << endl;
return 0;
}
/*
结果:
myvector contains: 10 20 30 40 50 60 70
myints contains: 10 20 30 40 50 60 70
*/
结合标准输入输出迭代器
#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
#include <string>
using namespace std;
int main ()
{
typedef vector<int> IntVector;
typedef istream_iterator<int> IstreamItr;
typedef ostream_iterator<int> OstreamItr;
typedef back_insert_iterator< IntVector > BackInsItr;
IntVector myvector;
// 从标准输入设备读入整数
// 直到输入的是非整型数据为止 请输入整数序列,按任意非数字键并回车结束输入
cout << "Please input element:" << endl;
copy(IstreamItr(cin), IstreamItr(), BackInsItr(myvector));
//输出容器里的所有元素,元素之间用空格隔开
cout << "Output : " << endl;
copy(myvector.begin(), myvector.end(), OstreamItr(cout, " "));
cout << endl;
return 0;
}
transform()函数
链接:transform.
将某操作应用于指定范围的每个元素。
transform函数有两个重载版本:
一元操作:
transform(first,last,result,op);
- first是容器的首迭代器
- last为容器的末迭代器
- result为存放结果的容器。
- op可以是函数指针或函数对象或lambda表达式。
对于一元操作,将op应用于[first, last)范围内的每个元素,并将每个操作返回的值存储在以result开头的范围内。给定的op将被连续调用last-first+1次。
二元操作:
transform(first1,last1,first2,result,binary_op); - first1是第一个容器的首迭代器
- last1为第一个容器的末迭代器
- first2为第二个容器的首迭代器
- result为存放结果的容器.
- binary_op可以是函数指针或函数对象或lambda表达式。
对于二元操作,使用[first1, last1)范围内的每个元素作为第一个参数调用binary_op,并以first2开头的范围内的每个元素作为第二个参数调用binary_op,每次调用返回的值都存储在以result开头的范围内。给定的binary_op将被连续调用last1-first1+1次。
注意:.第二个重载版本必须要保证两个容器的元素个数相等才行,否则会抛出异常。
#include <iostream>
#include <algorithm>
#include<string>
using namespace std;
char op(char ch)
{
if (ch >= 'a'&&ch <= 'z')
return ch - 32;
else
return ch;
}
int main()
{
string first="this is a test", second;
second.resize(first.size());
transform(first.begin(), first.end(), second.begin(), op);
cout << second << endl;//THIS IS A TEST
return 0;
}
// transform algorithm example
#include <iostream> // std::cout
#include <algorithm> // std::transform
#include <vector> // std::vector
#include <functional> // std::plus
int op_increase(int i) { return ++i; }
int main() {
std::vector<int> foo;
std::vector<int> bar;
// set some values:
for (int i = 1; i < 6; i++)
foo.push_back(i * 10); // foo: 10 20 30 40 50
bar.resize(foo.size()); // allocate space
std::transform(foo.begin(), foo.end(), bar.begin(), op_increase);
// bar: 11 21 31 41 51
// std::plus adds together its two arguments:
std::transform(foo.begin(), foo.end(), bar.begin(), foo.begin(), std::plus<int>());
// foo: 21 41 61 81 101
std::cout << "foo contains:";
for (std::vector<int>::iterator it = foo.begin(); it != foo.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
for_each()函数
for_each( InputIt first, InputIt last, UnaryFunction f );
first和last为两个输入迭代器,f为一个一元函数。
Applies the given function object f to the result of dereferencing
every iterator in the range [first, last), in order.
if the iterator type is mutable, f may modify the elements of the range through the dereferenced iterator. If f returns a result, the result is ignored.
在 [first, last)范围内,按照顺序将每个迭代器的解引用传入函数f,
如果迭代器 的类型为mutable,可变的,函数f可以通过迭代器的解引用修改原来的元素的值,如果有返回值,该返回值将会被忽略。
Unlike the rest of the parallel algorithms, for_each is not allowed to make copies of the elements in the sequence even if they are trivially copyable.
与其余并行算法不同,for each不允许复制序列中的元素,即使它们是可复制的。
参数解释:
first, last - the range to apply the function to
f - function object, to be applied to the result of dereferencing every iterator in the range [first, last)
The signature of the function should be equivalent to the following:
void fun(const Type &a);
The signature does not need to have const &.
The type Type must be such that an object of type InputIt can be dereferenced and then implicitly converted to Type.
如果不希望更改元素的值,建议使用 const &,如果要更改值使用引用符&。
#include <vector>
#include <algorithm>
#include <iostream>
struct Sum
{
void operator()(int n) { sum += n; }
int sum{0};
};
using namespace std;
int main()
{
vector<int> nums{3, 4, 2, 8, 15, 267};
//匿名函数
auto print = [](const int& n) { std::cout << " " << n; };
cout << "before:";
for_each(nums.cbegin(), nums.cend(), print);
cout << '\n';
std::for_each(nums.begin(), nums.end(), [](int &n){ n++; });
// calls Sum::operator() for each number
Sum s = std::for_each(nums.begin(), nums.end(), Sum());
std::cout << "after: ";
std::for_each(nums.cbegin(), nums.cend(), print);
std::cout << '\n';
std::cout << "before:";
std::for_each(nums.cbegin(), nums.cend(), print);
std::cout << '\n';
std::cout << "sum: " << s.sum << '\n';
}
accumulate()
版本一:T accumulate( InputIt first, InputIt last, T init );
版本二:T accumulate( InputIt first, InputIt last, T init, BinaryOperation op );
计算给定值init和范围内的元素[first, last]的总和。
版本一中是默认使用operator+来计算元素总和。
版本二中则使用一个二元函数op来指定操作元素计算总和。
first, last - 要求和的元素的范围
init - 求和的初始值
op - 将要应用的二进制运算函数对象, 二进制运算符获取当前累加值a(初始化为init)和当前元素b的值
Ret fun(const Type1 &a, const Type2 &b);
The signature does not need to have const &.
The type Type1 must be such that an object of type T can be implicitly converted to Type1. The type Type2 must be such that an object of type InputIt can be dereferenced and then implicitly converted to Type2. The type Ret must be such that an object of type T can be assigned a value of type Ret.
签名不需要具有const & 类型1必须使类型T的对象可以隐式转换为类型1 类型2必须使InputIt类型的对象可以解除引用,然后隐式地转换为类型2 类型Ret必须能够为类型T的对象分配类型Ret的值
#include <iostream>
#include <vector>
#include <numeric>
#include <string>
#include <functional>
int main()
{
std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
//累和
int sum = std::accumulate(v.begin(), v.end(), 0);
//累积
int product = std::accumulate(v.begin(), v.end(), 1, std::multiplies<int>());
auto dash_fold = [](std::string a, int b) {
return std::move(a) + '-' + std::to_string(b);
};
std::string s = std::accumulate(std::next(v.begin()), v.end(),
std::to_string(v[0]), // start with first element
dash_fold);
// Right fold using reverse iterators
std::string rs = std::accumulate(std::next(v.rbegin()), v.rend(),
std::to_string(v.back()), // start with last element
dash_fold);
std::cout << "sum: " << sum << '\n'
<< "product: " << product << '\n'
<< "dash-separated string: " << s << '\n'
<< "dash-separated string (right-folded): " << rs << '\n';
}