C/C++常用函数

C/C++常用函数

      • find、count、find_if、any_of 查找元素
      • for_each() 修改区间内元素
      • reverse逆序(反转)函数
      • max_element()、 max({a, b, c}) 找最大值
      • copy(begin, end, container) 复制函数
      • abs() 绝对值函数
      • 取整函数 ceil、floor和round
      • advance(it, n) 迭代器进退n位
      • prev(it, n) 迭代器向左移动n位
      • distance(first, last) 计算元素个数
      • INT_MAX/MIN 最大最小整型
      • next_permutation() 数组全排列
      • shuffle() 打乱顺序
      • accumulate() 累加函数
      • iota() 区间内赋增量为1的连续值
      • stoi() 字符串转整型
      • to_string()整型转字符串
      • append() 字符串尾插其他字符串
      • replace() 替换字符串中的给定值
      • acos() 函数
      • tolower() 大写字母转小写
      • toupper() 小写转大写
      • transform(first,last,result,op) 操作作用每个元素
      • isalpha() 判断是否是字母
      • isdigit() 判断是否十进制数
      • isalnum() 判断是否字母或数字
      • islower() 判断是否小写字母
      • isupper() 判断是否大写字母
      • __builtin_popcount(x) 统计二进制下“1”的个数

大部分为C++ STL函数,并且大多需要添加头文件#include(C语言的头文件)或者#include
常用函数一览:

swap(nums[i], nums[ptr]); //交换函数
max(merged.back()[1], R); //大小比较选取
max_element(myvector.begin(),myvector.end());//返回向量中最大元素的迭代器,注意返回的是迭代器,头文件是algorithm
reverse(ans.begin(), ans.end());//答案反转
rand函数,C语言中用来产生一个随机数的函数。
int a = round(11.5); //四舍五入,得到a=12
sqrt(5); //根号5
pow(a,2); //a的平方
num = abs(num);//取绝对值,abs是针对于int类型的
//distance() 函数用于计算两个迭代器表示的范围内包含元素的个数
rand();  //返回一个从0到最大随机数的任意整数
int result = accumulate(nums.begin(), nums.end(), 0);//序列求和

find、count、find_if、any_of 查找元素

头文件 #include

  1. count(v.begin(), v.end(), key) 函数
    对于只需要知道包含特定元素的数量的应用来说,这是最简单的方式。如果count返回0,则表示不存在该元素。
vector<int> v{ 4, 7, 9, 1, 2, 5 };
int key = 2;
if (count(v.begin(), v.end(), key)){
	cout << "Element found" << endl;
}
  1. find(v.begin(), v.end(), key) 函数
    find会在查找到指定值后立即返回,所以它一般比count更快(因为count总是要遍历整个容器)。
    上述代码只需要更改条件判断语句:
if (std::find(v.begin(), v.end(), key) != v.end())
  1. find_if(v.begin(), v.end(), [] () { } )
    find_if需要一个判别式。如果查找的值需要满足特定的条件时,比如查找小于3且大于1的值时,适合该方式。
    如果有多个值符合条件,则返回查找到符合条件的第一个值的迭代器。

条件判断语句:

if (std::find_if(v.begin(), v.end(), [] (int i) { return i < 3 && i > 1 } ) != v.end())
  1. any_of (v.begin(), v.end(), [] () { } )
    与find_if类似,但它返回bool值。
    如果判断式返回true,则它也返回true。否则返回false。

条件判断语句:

if (std::any_of(v.begin(), v.end(), [] (int i) { return i < 3 && i > 1 } ))

扩展:std::none_of,是any_of的反面。也就是,当判断式是false时它返回true,否则返回flase。

小结
方法虽多,侧重各不相同。选择适合的算法有助于提高代码可读性和执行效率,简单总结如下:

对于已经排序的vector,使用binary_search
仅判断是否存在某元素,使用find
需要某元素总个数时,使用count
支持复杂条件的查找时,使用any_of(仅知道是否存在)或者find_if(返回了第一个元素的迭代器)

for_each() 修改区间内元素

头文件:#include
常用用法: for_each(v.begin(), v.end(), 全局函数名);
for_each() 函数,允许对区间内的元素进行修改,当然transform也可以实现相同的操作,只是transform效率较低,因为transform是通过拷贝函数返回值实现。 当然 C++ 11之后 for_each 变得不再重要,因为range-based for更加直观简单。这里仅作为了解。
for_each()事实上是個function template,其实质如下[effective STL item 41],for_each()只能配合global function和function object。

template<typename InputIterator, typename Function>
Function for_each(InputIterator beg, InputIterator end, Function f) {
  while(beg != end) 
    f(*beg++);
}

经常和 vector 容器搭配使用,在vector容器中 for_each 遍历算法如下:

	void MyPrint(int val){
		cout << val << endl;
	}
	for_each(v.begin(), v.end(), MyPrint);	

相对于使用for循环来遍历容器来说,使用for_each算法更实用一些,而且代码简短,可读性更强,但不如range-based for更加直观简单。

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

max_element()、 max({a, b, c}) 找最大值

① max_element() 找有前向迭代器序列区间中的最大值,如数组、列表等。
头文件:#include
返回【前闭后开)序列区间中指向最大值的迭代器,输出值的话要在max_element前面加星号,第三个参数cmp可写可不写。
max_element() 和 min_element() 默认是从小到大排列,然后
max_element() 输出最后一个值, min_element() 输出第一个值。如果自定义的 cmp函数写的是从大到小排列,那么会导致 max_element() 和min_element() 的两个结果是对调的。
可以用于 vector< int > 或者 vector< string > 等,也可以用于 int arr[4] 或者string arr[4] ,也可以用于结构体vector或者结构体数组。
用法举例:

int a[5] = {0, 3, 9, 4, 5};
int *b;
b = max_element(a, a+5);
cout << *b;
//也适用于向量
vector<int> myvector;
vector<int>::iterator it;
it = max_element(myvector.begin(),myvector.end());
cout<<*max_element(myvector.begin(),myvector.end());
//或者自己写一个比较函数,作为第三个参数
static bool cmp(int& a, int& b)
{
	return abs(a)<abs(b);
}
it = max_element(myvector.begin(),myvector.end(),cmp);	
cout<<*it<<end;

②max({a, b, c}) 利用 initializer_list 来找多个元素中的最大值
在C++11中有了initializer_list(初始化列表)后,max函数可以传递更多的参数,如下:

cout << max({ 54,16,48,5 }) << endl;   //输出54

【注意】max 函数中的参数类型需要一致,不一致时需要进行类型转换,如下,size()函数返回值为 unsigned int 类型,不是int类型,类型不一致时会报错!

int maxlen = 0;
maxlen = max(maxlen, (int)word.size()); 
//word.size()不是int,max 函数需要参数类型统一

【补充-初始化列表】
c++11中统一了初始化列表(Uniform Initiaization),即均可以使用{}来对对象进行初始化。例如:

int value[]{1,2,3};
vector<int> v{2,3,4,5,6,7};
vector<string> cities{"Beijing","Dezhou"};
int i;         //i has undefined value
int j{};       //j is initialized by 0
int *p;        //p has undfined value
int *q{};      //q is initialized by nullptr

我们使用{}可以给上面进行赋值,那如果是结构体呢?

struct Peo
{
	std::string name;
	int pos;
};
Peo p[2]{ {"abo",1},{"abo2",2} };

综上,上面的初始化列表背后就是使用initializer_list来进行实现的,initializer_list背后是由array实现的。
array中的元素可被编译器分解逐一传给参数:

	for(auto x:{1,2,3,4,5})
		cout << x << endl;	

copy(begin, end, container) 复制函数

作用:
把一个序列(sequence)拷贝到一个容器(container)中去,复制任何具有迭代器对象的元素。

函数原型:

std::copy(start, end, container);

start,end是需要复制的源文件的头地址和尾地址,container是接收器的起始地址,该容器的接口包含函数push_back。
copy只负责复制,不负责申请空间,所以复制前必须要有足够的空间。

用法样例:
① 覆盖复制
在一个已有的元素上直接copy覆盖,往往比较高效。但注意需要足够的空间。

	int arr[] = {1,2,3,4,5,6,7,8,9,10};
    int newArr[12] = {0};
    copy(arr,arr+10,newArr); 

② 在已有元素之后复制
只需要改变copy函数第三个参数为需要开始插入的元素地址(接收数组的起始地址加上原有数据的长度)

	int arr[] = {1,2,3,4,5,6,7,8,9,10};
	int newArr[12] = {11,12,0};
	copy(arr,arr+10,newArr+2); //从11,12,0之后复制

③ 使用标准库提供的模板函数
包括inserter或者front_inserter或者back_inserter模板函数。

inserter,注意需要两个参数。此函数接受第二个参数,这个参数必须是一个指向给定容器的迭代器。元素将被正序插入到给定迭代器所表示的元素之前,并且为覆盖复制。

front_inserter和back_inserter分别为头插法和尾插法,只有一个参数(接收容器)。头插法会导致被复制元素倒序插入接收容器头部,尾插法会让被复制元素正序插入接收容器尾部

	list<int> lst = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    list<int> lst2 ={10}, lst3={10},lst4={10};
    
    //lst被正序复制插入到迭代器lst2.begin()之前
    //list类型里面迭代器不能加减,也不能使用下标运算符[]
    //lst2包含1,2,3,4,5,6,7,8,9,10
    copy(lst.cbegin(), lst.cend(), inserter(lst2, lst2.begin())); //在lst2首部插入复制元素
    //insert函数通常可以与copy函数(结合inserter)实现相同的效果,等价于下面这句
    lst2.insert(lst2.begin(), lst.begin(), lst.end()); //在lst2首部插入元素

    //lst3是头插法,lst每个元素都插在lst3的前面,注意插完变成倒序了
    //lst3包含9,8,7,6,5,4,3,2,1,10
    copy(lst.cbegin(), lst.cend(), front_inserter(lst3));
    
    //lst4使用尾插法,lst中每个元素都插在了lst4末尾,而且保持了正序。
    //lst4包含10,1,2,3,4,5,6,7,8,9
    copy(lst.cbegin(), lst.cend(), back_inserter(lst4));

【注】

  1. list类型里面迭代器不能加减,也不能使用下标运算符[ ]
  2. copy函数与insert函数的区别:
    从效果上来看,copy需要多次调用inserter函数,申请一段内存,每一次申请成功就复制数据;区间型insert则是在一个循环中申请够内存后再通过move_backward以逆向的方式一次性复制数据。
    此外,copy每次调用inserter都会发生移动,而insert因为是申请区间内存,所以仅发生一次大的移动。
    故从效率上看insert更好。

abs() 绝对值函数

C语言的abs函数:

#include 
#include  //用这个头文件
//abs是针对于int类型取绝对值
num = abs(num);
//针对long类型使用labs()
long b=-2;
b = labs(b);
//针对float,double 类型
float d = -4.12;         
//float总有效位数一般为7位,例如12.34总有效位位数为5
d = fabs(d);

C++的abs则可以自然支持对整数和浮点数两个版本,在cmath头文件中定义,#include
【注】math.h是C语言的头文件。在C++中用math.h也是可以的,C++是兼容C的。不过推荐的是使用#include ,不过这样必须声明在std命名空间:using namespace std; 其中的函数和使用方法几乎完全相同。

取整函数 ceil、floor和round

math类中提供了三个与取整有关的方法:ceil,floor,round,这些方法的作用于它们的英文名称的含义相对应
1、ceil的英文意义是天花板,该方法表示向上取整

int a = ceil(11.3); //a = 12
int b = ceil(-11.6); //b = -11
auto c = double(11)/2; //c = 5.5
auto d = ceil(double(11)/2); // d = 6

2、floor的英文是地板,该方法就表示向下取整

int a = floor(11.6); //a = 11
int b = floor(-11.6); //b = -12
auto c = double(11)/2; //c = 5.5
auto d = floor(double(11)/2); // d = 5

3、round方法表示“四舍五入”,算法为floor(x+0.5),即将原来的数字加上0.5后再向下取整,等价于(int)(m +0.5)。

    int a = round(11.5); //a = 12
    int b = round(-11.5); //b = -12
    auto c = double(11)/2; //c = 5.5
    auto d = round(double(11)/2); // d = 6

advance(it, n) 迭代器进退n位

头文件#include
advance(it, n) it 表示某个迭代器,n 为整数。该函数的功能是将 it 迭代器前进或后退 n 个位置。
如果 it 为输入迭代器或者前向迭代器,则 n 必须为一个正数,即表示将 it 右移(前进) n 个位置;反之,如果 it 为双向迭代器或者随机访问迭代器,则 n 为正数时表示将 it 右移(前进) n 个位置,n 为负数时表示将 it 左移(后退) n 个位置。
以 forward_list 容器(仅支持使用前向迭代器)为例, it 为前向迭代器,其只能进行 ++ 操作,即只能前进(右移):

#include      // std::cout
#include      // std::advance
#include 
using namespace std;
int main() {
    //创建一个 forward_list 容器
    forward_list<int> mylist{1,2,3,4};
    //it为前向迭代器,其指向 mylist 容器中第一个元素
    forward_list<int>::iterator it = mylist.begin();
    //借助 advance() 函数将 it 迭代器前进 2 个位置
    advance(it, 2);
    cout << "*it = " << *it; //*it = 3
    return 0;
}

注意:
1)对于vector向量容器,it为随机访问迭代器,advance() 函数底层采用 it+n 操作实现的,因此n可正可负,可以前后移动迭代器。
2)当 it 为其他类型迭代器时,它们仅支持进行 ++ 或者 – 运算,这种情况下,advance() 函数底层是通过重复执行 n 个 ++ 或者 – 操作实现的。
3)advance() 函数本身不会检测 it 迭代器移动 n 个位置的可行性,如果 it 迭代器的移动位置超出了合理范围,it 迭代器的指向将无法保证,此时使用 *it 将会导致程序崩溃。

prev(it, n) 迭代器向左移动n位

pre具有前一个的意思,该函数可用来获取一个距离指定迭代器 n 个元素的迭代器。

用法:

new_iterator = prev(iterator,n)

表示迭代器左移 n 个单位,即迭代器 - n。
若移动n个单位的步长后,超出迭代器范围[begin,end),则此行为未定义。
函数的返回值为一个迭代器,也就是传入迭代器左移n个单位后,返回这个移动后的新迭代器。

当“n“为正数时,返回传入迭代器“iterator”左边,距离”iterator“ n个单位的迭代器”new_iterator“。

当“n“为负数时,返回传入迭代器“iterator”右边,距离”iterator“ n个单位的迭代器"new_iterator"。

特别地,当不写n时,表示默认向“iterator”左边移动1个单位。

 new_iterator = prev(iterator)

注:如果是随机访问迭代器,就只执行一次运算符操作 +=n( -=n ),否则,执行n次持续的递减或递增操作 ++(–)。

样例:

 vector<int> vec{ 1,2,3,4,5,6,7 };
 vector<int>::iterator end = vec.end();
 for (int i = 1; i <= vec.size(); ++i)
 {
  auto it = prev(end, i);
  cout << "end左移" << i << "个单位后的元素值为:" << *it << endl;
 } 

输出结果:

end左移1个单位后的元素值为:7
end左移2个单位后的元素值为:6
end左移3个单位后的元素值为:5
end左移4个单位后的元素值为:4
end左移5个单位后的元素值为:3
end左移6个单位后的元素值为:2
end左移7个单位后的元素值为:1

distance(first, last) 计算元素个数

distance() 函数定义在#include头文件,并位于 std 命名空间中,用于计算两个迭代器表示的范围内包含元素的个数。该函数会返回[first, last)范围内包含的元素的个数(距离)。

int num = distance (InputIterator first, InputIterator last);
//创建一个空 list 容器
list<int> mylist;
//向空 list 容器中添加元素 0~9
for (int i = 0; i < 10; i++) {
    mylist.push_back(i);}
//获取 [first,last) 范围内包含元素的个数
 cout << "distance() = " << distance(mylist.begin(), mylist.end());
//distance() = 10

INT_MAX/MIN 最大最小整型

C++中常量INT_MAXINT_MIN分别表示最大、最小整数。
头文件#include
比如想给某个变量赋一个最大的初始值,可以如下:

int indexSum = INT_MAX;

因为int占4字节32位,根据二进制编码的规则,INT_MAX =   2 31 − 1   \ 2^{31}-1\,  2311(2147483647)
,INT_MIN=   − 2 31   \ -2^{31}\,  231(-2147483648)
#define INT_MAX 2147483647
#define INT_MIN (-INT_MAX - 1)
C++整型上下限INT_MAX INT_MIN及其运算

【拓展总结】

常量 含义
CHAR_MIN char 类型最小值 -128
CHAR_MAX char类型最大值 127
UCHAR_MAX unsigned char 类型最大值 255(0xff)
SHRT_MIN short 类型最小值 -32768
SHRT_MAX short 类型最大值 32767
USHRT_MAX unsigned short 类型最大值 65535(0xffff)
INT_MIN int 类型最小值 -2147483647-1
INT_MAX int 类型最大值 2147483647
UINT_MAX unsigned int 类型最大值 4294967295(0xffffffff)
LONG_MIN long 类型最小值 -2147483647-1
LONG_MAX long 类型最大值 2147483647
ULONG_MAX unsigned long 类型最大值 4294967295(0xffffffff)
LLONG_MIN long long 类型最小值 -9223372036854775807-1
LLONG_MAX long long 类型最大值 9223372036854775807
ULLONG_MAX unsigned long long 类型最大值 18446744073709551615(0xffffffffffffffff)

next_permutation() 数组全排列

全排列除了以递归的方式实现以外,还可以利用c++标准函数库中的next_permutation()和prev_permutation()函数来实现。它们的头文件为#include
该函数有两个形参,一个为数列的首元素地址,一个为数列的尾元素地址。返回值为bool类型,当全排列进行到到最后一种情况时返回false,否则返回true。
注:使用 next_permutation(首地址,尾地址) 进行全排列的数列必须是以最小字典排列(即由小到大排列)开始的。
prev_permutation()函数则要求原数列必须由大到小进行排列。
因此这两个库函数一般与sort()函数结合使用
样例如下:

//46. 全排列
vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int> > ans;
        sort(nums.begin(),nums.end());//从小到大排列
        ans.emplace_back(nums);
        while(next_permutation(nums.begin(),nums.end()))
        {
            ans.emplace_back(nums);
        }
        return ans;
    }

如果对从大到小排列的数组 int a[] = {3,2,1}; 进行全排列,则需要使用while (prev_permutation(a, a+3))。
需要注意的是,全排列从当前数组的下一个排列开始,当前数组需要提前输出并保存。

用回溯递归方式实现全排列,输入为nums数组,输出其全排列:

//46. 全排列
void backTrace(vector<vector<int> >& ans, vector<int>& nums, int index, int n)
    {
        // 所有数都填完了
        if(index==n)
        {
            ans.emplace_back(nums);
            return ;
        }
        for(int i=index;i<n;++i)
        {
            // 动态维护数组,填入当前index位置及后面位置的任一个数,并进行交换,
            //这样可以每次只选择未使用的右侧的数字
            swap(nums[index],nums[i]);
            // 继续递归填下一个数
            backTrace(ans,nums,index+1,n);
            // 撤销操作,换回当前数字,准备换下一个数字
            swap(nums[index],nums[i]);
        }
    }
    vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int> > ans;
        int n = nums.size();
        backTrace(ans, nums, 0, n);
        return ans;
    }

shuffle() 打乱顺序

重排序给定范围 [first, last) 中的元素,打乱顺序,使得这些元素的每个排列拥有相等的出现概率。

头文件:#include
函数原型:

template< class RandomIt, class URBG >
void shuffle( RandomIt first, RandomIt last, URBG&& g );
参数:
first, last - 要随机打乱的元素范围
g - 均匀随机位生成器 (UniformRandomBitGenerator)
RandomIt 必须满足值可交换 (ValueSwappable) 和 遗留随机访问迭代器 (LegacyRandomAccessIterator) 的要求。

同样的,内置类型数组也支持这种用法,比如下面的int型数组与char型数组。

int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
char crr[] = "ABCDEFGH";

通常使用样例:
注意random_device{ }( ) 需要加头文件#include

shuffle(myvector.begin(), myvector.end(), mt19937(random_device{}()));

vector使用样例:

#include 
#include 
#include 
#include 

int main()
{
	std::vector<int> v = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	//两种写法:
	std::random_device rd;	//随机数发生器
	std::mt19937 g(rd());	// 随机数引擎:基于梅森缠绕器算法的随机数生成器
	std::shuffle(v.begin(), v.end(), g);	// 打乱顺序,重新排序(随机序列)
	//上面三句等价于下面一句
	std::shuffle(myvector.begin(), myvector.end(), std::mt19937(std::random_device{}()));
	
	for (int a : v) std::cout << a << " "; //输出:3 1 4 9 5 10 2 8 7 6
	std::cout << "\n";
}

accumulate() 累加函数

头文件#include
将一段数字从头到尾累加起来,或者使用指定的运算符进行运算。
accumulate(first, last, 初值,操作);四个参数:累加的元素起始地址;累加的元素结束地址,累加的初值(通常为0);第四个参数为进行的操作,默认为累加。
常用的求和样例:

#include
#include
#include
using namespace std;

int main() {
    vector<int> nums = {1, 2, 3, 4, 5};
    int result = accumulate(nums.begin(), nums.end(), 0);
    cout << result << endl; //result = 15    
    return 0;
}

求和时,accumulate带有三个形参:累加的元素起始地址;累加的元素结束地址,累加的初值(通常为0)。
例如:

int list[10] = { 1,2,3,4,5,6,7,8,9,10 };
sum= accumulate(list, list+10, 0) ; //得出sum=55.

求连乘积时,accumulate带有四个形参:连乘的元素起始地址;连乘的元素结束地址,连乘的初值(通常为1), multiplies() 运算

con_product= accumulate(list, list+3, 1, multiplies<int>()) ;//得出sum=6.

string合并

 vector<string>a{"1","-2345","+6"};
string a_sum=accumulate(a.begin(), a.end(),string("out: "));//得到out: 1-2345+6

iota() 区间内赋增量为1的连续值

头文件#include
iota 函数 是一个计算机语言中的 函数 ,用于产生连续的值。 该 函数 得名自 APL 语言,其中用来产生从 T 开始的连续数值,增量为1,初始值T可以为小数。 定义在 numeric 头文件中的 iota () 函数 模板会用连续的 T 类型值填充序列。
iota函数作用:
对一个区间范围内的数据进行连续累加赋值。

template <class ForwardIterator, class T>
  void iota (ForwardIterator first, ForwardIterator last, T val)
{
  while (first!=last) {
    *first = val;
    ++first;
    ++val;
  }
}

例子:

  int numbers[10];
  std::iota (numbers, numbers + 10, 100);
  //输出:100 101 …… 109

stoi() 字符串转整型

stoi()中放入(string)类型的参数,可以把string转换成int类型
stoi函数会做范围检查,所以数字的类型不能超过int范围,不然会报错,而且在转换的过程中会发生int强制类型转换,所以当有小数点或题目输入字符串长度大于等于10位时,一定要注意!
一个可行的解决方法是使用stoll函数代替stoi,将string转化为long long int。
比如下面这种情况就会发生强制类型转换

int n=stoi("1.234");
cout<<n;
//此时会输出1。

用法:
stoi(字符串名) 或 stoi(字符串名,起始位置,n进制),将 n 进制的字符串转化为十进制
n进制的字符串指的是我们把字符串里存的内容当成几进制来看
示例:

 string str = "1010";
 int a = stoi(str, 0, 2); //将字符串 str 从 0 位置开始到末尾的 2 进制转换为十进制
 int a = stoi(str); //简写

类似函数:
stol等:将string转化为其他类型
atoi等:不接受string作为输入参数,需将string转化为char*。同时,atoi不进行范围检查,超出类型上/下界时直接输出上/下界。

to_string()整型转字符串

C++中的 to_string(value)系列函数将数值value转换成字符串形式。value不能为字符类型

std::string pi = "pi is " + std::to_string(3.1415926)//输出: pi is 3.1415926

C++ int与string的相互转换
总结:

  1. const char* 字符串 以 “\0”结尾。
  2. char[] 字符串 以 “\0”结尾。
  3. string 字符串 不以 “\0”结尾。
  4. char[n] = “string”, 当string 长度+“\0”>n时,会因空间不足出错。
  5. string.c_str() 转 const char* 时, 会在字符串末尾 自动补“\0”
  6. char* 转string 时, 会自动把末尾的 “\0” 去掉。

【附】C语言的atoi()函数:
atoi()函数——将char* 转换成int类型
功 能: 把字符串char* 类型转换成整型数int类型并返回结果,注意:不适用于string类string类型需要先用c_str()函数进行转换再用atoi()函数。
用 法: int atoi(const char *nptr);
atoi()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负号才开始做转换,而再遇到非数字或字符串时(‘\0’)才结束转化,并将结果返回(返回转换后的整型数)。
举例:

#include 
char *str = "12345.67";
int n = atoi(str);
int num = atoi(1314.012);//num值为1314

str.c_str()函数
C 库函数 int atoi(const char *str) 把参数 str 所指向的字符串转换为一个整数(类型为 int 型)。但不适用于string类串,可以使用string对象中的c_str()函数进行转换。
c_str()函数返回一个指向正规c字符串的指针,内容与string串相同。将string对象转换为C中的字符串样式。

	std::string str="123";
	int a =str-'0'; //错误,不可以直接用一个字符串减去‘0’
	int n = atoi(*str);  //错误
	int n = atoi(str.c_str());   //正确,可以将string转为int

append() 字符串尾插其他字符串

类似于尾插法, 在当前字符串尾部追加其他字符串

string str ;
string str2 =123;

用法:

//在str后面追加一个str2
 str.append(str2);   //输出123
 
 //在后面追加上str2中从第二个元素开始的连续一个元素
 str.strappend(str2,1,1); //1232

//在str后面追加上abc
str.append(“abc”);  //1232abc
 
 //在str后面追加上字符串123456中的前六个元素 
 str.append(123456, 6);  

//在str后面追加5个m 
 str.append(5,‘m’);  

//使用迭代器给str追加上str2的元素
 str.append(str2.begin(),str2.end());  

replace() 替换字符串中的给定值

头文件#include

replace的执行要遍历由区间[frist,last)限定的整个队列,以把old_value替换成new_value,因此复杂度为O(n)。

下面说下replace()函数常用的五种用法,另外有4种用法编译器可能会有警告,因此不推荐使用:

1)用str替换 指定字符串从 起始位置pos开始 长度为len 的字符
声明:

string& replace (size_t pos, size_t len, const string& str); 

用例:

	string str = "he is@ a@ good boy";
    str = str.replace(str.find("a"), 2, "#");  //从第一个a位置开始的两个字符替换成#
    cout << str << endl; //he is@ # good boy

2)用str替换 迭代器起始位置 和 结束位置 的字符
声明:

string& replace (const_iterator i1, const_iterator i2, const string& str);

用例:

	string str = "he is@ a@ good boy";
    str = str.replace(str.begin(), str.begin() + 5, "#"); //用#替换从begin位置开始的5个字符
    cout << str << endl; //#@ a@ good boy

3)用substr的指定子串(给定起始位置和长度)替换从指定位置上的字符串
声明:

string& replace (size_t pos, size_t len, const string& str, size_t subpos, size_t sublen);

用例:

	string str = "he is@ a@ good boy";
    string substr = "12345";
    str = str.replace(0,5, substr, substr.find("1"), 4); //用substr的指定字符串替换str指定字符串
    cout << str << endl; //1234@ a@ good boy

4)用重复n次的c字符替换从指定位置pos长度为len的内容
声明:

 string& replace (size_t pos, size_t len, size_t n, char c); 

用例:

	char  ch = '#';
    str = str.replace(0, 6, 3, ch);   //用重复 3 次的 str1 字符替换的替换从位置 0~6 的字符串
    cout << str << endl; //### a@ good boy

5)用重复n次的c字符替换从指定迭代器位置(从i1开始到结束)的内容
声明:

 string& replace (const_iterator i1, const_iterator i2, size_t n, char c); 

用例:

	char  ch = '#';
    str = str.replace(str.begin(), str.begin() + 6, 3, ch);   //用重复3次的str1字符替换的替换从指定迭代器位置的内容
    cout << str << endl; //### a@ good boy

acos() 函数

头文件 #include
C ++中的acos()函数以弧度形式返回数字(参数)的反余弦值。

用法:
acos(data_type x)

参数:此函数接受一个强制性参数x,该参数指定应计算其反余弦值的值。它必须介于-1和+1之间,否则将抛出域错误(范围错误)。该参数可以是double,float或long double数据类型。
返回:该函数返回介于0和π之间。逆时针角度以弧度为单位,通常为double类型。

acos()函数采用[-1,1]范围内的单个强制性参数。这是因为余弦值在1到-1的范围内。
假设参数在[-1,1]范围内,则acos()函数返回[0,π]范围内的值。
如果参数大于1或小于-1,则acos()返回 NaN ,即不是数字。

参数x 返回值
x = [-1,1] [0,π] 以弧度为单位
x < -1 或 x > 1 NaN(非数字)

常用用法:

double acos(double x);
float acos(float x);
long double acos(long double x);
cout<<acos(-1.0);//3.14159
double result = acos(0.0);  //result = 90.0027

同理是asin()函数,用于查找给定数字反正弦的主值,它接受数字( x )并以弧度返回x的反正弦的主值。
C/C++常用函数_第1张图片

tolower() 大写字母转小写

头文件:#include
作用:返回转换后的小写字母,若不须转换则将参数值返回

#include 
int main()
{
    char s[] = "aBcDeFgH12345;!#$";
    printf("before tolower() : %s\n", s);
    //before tolower() : aBcDeFgH12345;!#$
    for(int i = 0; i < sizeof(s); i++)
    {
        s[i] = tolower(s[i]);
    }
    printf("after tolower() : %s\n", s);  
    //after tolower() : abcdefgh12345;!#$   
    return 0;
}

toupper() 小写转大写

把小写字母转换为大写字母。
toupper() 函数的声明:

int toupper(int c);

如果 c 有相对应的大写字母,则该函数返回 c 的大写字母,否则 c 保持不变。返回值是一个可被隐式转换为 char 类型的 int 值。

transform(first,last,result,op) 操作作用每个元素

将某操作应用于指定范围的每个元素。
比较常用的重载函数版本是:transform(first,last,result,op);
其中,first是容器的首迭代器,last为容器的末迭代器,result为存放结果的容器,op为要进行操作的一元函数对象(比如::toupper或::tolower)或sturct、class。

比如利用transform函数将一个给定的字符串中的小写字母改写成大写字母,并将结果保存在一个叫second的数组里,原字符串内容不变。

#include 
#include 
using namespace std;
char op(char ch)
{
    if(ch>='A'&&ch<='Z')
        return ch+32;
    else
        return ch;
}
int main()
{
    string first,second;
    cin>>first;
    second.resize(first.size());
    transform(first.begin(),first.end(),second.begin(),op);
    cout<<second<<endl;
    return 0;
}

当然可以用已有函数对象(比如::toupper或::tolower)进行简写,并将结果保存至str字符串自身中。

string str;  cin>>str;
transform(str.begin(), str.end(), str.begin(), ::toupper);//转为大写
transform(str.begin(), str.end(), str.begin(), ::tolower);//转为小写

isalpha() 判断是否是字母

头文件:#include
函数声明: int isalpha(int c);
返回值:如果 c 是一个字母,则该函数返回非零值,否则返回 0。
用法示例:
如果str[i] 是字母,就转为小写字母

	if (isalpha(str[i])) 
    {
        word.push_back(tolower(str[i]));//转为小写
     } 

isdigit() 判断是否十进制数

头文件:#include
声明:int isdigit(int c);
返回值:如果 c 是一个数字,则该函数返回非零值,否则返回 0。

isalnum() 判断是否字母或数字

检查所传的字符是否是字母和数字
声明:int isalnum(int c);
返回值:如果 c 是一个数字或一个字母,则该函数返回非零值,否则返回 0。

islower() 判断是否小写字母

检查所传的字符是否是小写字母。
声明:int islower(int c);
返回值:如果 c 是一个小写字母,则该函数返回非零值(true),否则返回 0(false)。

isupper() 判断是否大写字母

检查所传的字符是否是大写字母
声明:int isupper(int c);
返回值:如果 c 是一个大写字母,则该函数返回非零值(true),否则返回 0(false)

__builtin_popcount(x) 统计二进制下“1”的个数

__builtin_popcount是GCC自带的内建函数,它可以精确地计算1的个数。内部是用查表实现的。
作用:计算32 位无符号整数 x 在二进制下“1”的个数。
例子:461. 汉明距离
两个整数之间的 汉明距离 指的是这两个数字对应二进制位不同的位置的数目。
给你两个整数 x 和 y,计算并返回它们之间的汉明距离。
【分析】
计算 x 和 y 之间的汉明距离,可以先计算 x ⊕ y x \oplus y xy,然后统计结果中等于 1 的位数。
现在,原始问题转换为位计数问题。位计数有多种思路
方法一:C++内置位计数功能(其他方法见数学编程模块)

int hammingDistance(int x, int y) {
        return __builtin_popcount(x ^ y);
    }

你可能感兴趣的:(C++,数据结构与算法,c++,数据结构,算法,开发语言,leetcode)