算法竞赛常用库函数整理

ฅ(๑˙o˙๑)ฅ 大家好, 欢迎大家光临我的博客:面向阿尼亚学习
算法学习笔记系列持续更新中~

阿


文章目录

  • 前言
  • 一、#include < algorithm>头文件
    • sort排序函数
    • next_permutation()全排列函数
    • swap交换函数
    • reverse 翻转函数
    • unique 去重函数
    • max与min
    • lower_bound与upper_bound
  • 二、#include< ctype.h>头文件
    • isalnum
    • isalpha
    • isdigit
    • islower
    • isupper
    • tolower
    • toupper
  • 三、#include< iomanip>头文件
    • fixed
    • setprecision()
    • setw()
    • setfill()
  • 四、#include< cmath>头文件
  • 五、 #include< cstring>头文件
    • memset函数
  • 六、include < numeric>头文件
    • iota函数
  • 七、#include < ctime>头文件
    • random_shuffle 随机打乱
  • 最后


前言

学了半年算法以来总结的一些c/c++算法竞赛常用函数笔记
没有把每个函数讲的很详细,但是很实用

如果还有漏掉的函数,欢迎补充
其他一些属于STL的函数写在了STL专栏欢迎浏览
如果有错误,欢迎提出

另外,如果知道函数如何使用,但不知道属于哪个头文件
可以用#include 万能头文件(编译会慢一点点)


一、#include < algorithm>头文件

sort排序函数

sort函数有三个参数:

(1)第一个是要排序的数组的起始地址。

(2)第二个是结束的地址(最后一位要排序的地址)

(3)第三个参数是排序的方法,可以是从大到小也可是从小到大,还可以不写第三个参数,此时默认的排序方法是从小到大排序。

函数原型:sort(起始地址, 末尾地址, cmp),其中cmp是可以自己定义的函数名.

例如

#include
#include
using namespace std;
int main()
{
	int a[10]= {7,6,12,8,5,15,17,4,1,0};
	for(int i=0; i<10; i++)
		cout<<a[i]<<" ";
	sort(a,a+10);
	cout<<endl;
	for(int i=0; i<10; i++)
		cout<<a[i]<<" ";
	return 0;
}

输出
7 6 12 8 5 15 17 4 1 0
0 1 4 5 6 7 8 12 15 17

sort时间复杂度为n*log 2(n),执行效率较高!

实现原理:sort并不是简单的快速排序,它对普通的快速排序进行了优化,此外,它还结合了插入排序推排序。系统会根据你的数据形式和数据量自动选择合适的排序方法,这并不是说它每次排序只选择一种方法,它是在一次完整排序中不同的情况选用不同方法,比如给一个数据量较大的数组排序,开始采用快速排序,分段递归,分段之后每一段的数据量达到一个较小值后它就不继续往下递归,而是选择插入排序,如果递归的太深,他会选择推排序。

默认从小到大排序
如果需要从大到小排序,那么可以加个greater() 或者自写cmp 函数

sort(A,A+100,greater<int>());//降序排列
sort(A,A+100,less<int>());//升序排列

自定义比较函数

数组排列

int A[100];
bool cmp1(int a,int b)//int为数组数据类型
{
    return a>b;//降序排列
    //return a
}
sort(A,A+100,cmp1);

结构体排序

Student Stu[100];
bool cmp2(Student a,Student b)
{
    return a.id>b.id;//按照学号降序排列
    //return a.id
}
sort(Stu,Stu+100,cmp2);

如果想要先按x从大到小排序(即一级排序),但当x相等的情况下,按照y的大小从小到大排序(即二级排序)。
那么cmp的写法是:

bool cmp(student a,student b)
{
	if(a.x==b.x)//x值相等时按y从小到大排 
	{
		return a.y<b.y;
	} 
	return a.x>b.x;//按x值从大到小对结构体排序 
}bool cmp(student a,student b)
{
	if(a.x != b.x)//x值不相等时按x从大到小排 
    return a.x>b.x;
	else 
	return a.y<b.y;//x相等时按y值从小到大对结构体排序 
}

想要按照score的大小从大到小排序,如果score相同按照名字的字典序从小到大排序:

bool cmp(node x1,node x2)
{
    if(x1.score==x2.score)
        return x1.name<x2.name;
       return x1.score>x2.score; 
}

将string的长度从大到小输出

bool cmp(string a,string b)
{
return a.length()>b.length();
}

在STL标准容器中,只有vector、string、deque是可以使用sort的。
这是因为像set、map这种容器是用红黑树实现的(了解即可),元素本身有序,故不允许使用sort排序。

#include 
#include 
#include 
using namespace std;
int main()
{
    vector<int>a({1,3,2,5,2});
    sort(a.begin(),a.end(),greater<int>());
    for(auto x:a) cout << x <<' ';
    return 0;
}

next_permutation()全排列函数

介绍:next_permutation函数将按字母表顺序生成给定序列的下一个较大的排列,直到整个序列为降序为止。

使用方法:next_permutation(数组头地址,数组尾地址);
若下一个排列存在,则返回真,如果不存在则返回假
若求上一个排列,则用prev _permutation

#include
#include//注意添加头文件
using namespace std;

int q[10];//1 ~ 9最多9个数字 
int n;
int main()
{
    cin>>n;
    //输入数字 1 ~ n
    for(int i = 0 ; i<n ; i++)
        q[i] = i+1;
    //输出字典序最小的排列
    for(int i = 0 ; i<n ; i++)
        cout<<q[i]<<" ";
    cout<<endl;

    //当存在比当前字典序更大的排列时,next_permutation()返回真,直到没有更大的排列的时候才退出循环
    while(next_permutation(q,q+n))//利用next_permutation()自动找到下一个更大的字典序
    {
        //输出更大的排列
        for(int i = 0 ; i<n ; i++)
            cout<<q[i]<<" ";
        cout<<endl;
    }
    return 0;
}

输出
3
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1

next_permutation 自定义比较函数

//题目中要求的字典序是
#include //poj 1256 Anagram
#include
#include
using namespace std;
int cmp(char a,char b) 
{
   if(tolower(a)!=tolower(b))//tolower 是将大写字母转化为小写字母.
       return tolower(a)<tolower(b);
   else
       return a<b;
}
int main()
{
    char ch[20];
    int n;
    cin>>n;
    while(n--)
{
    scanf("%s",ch);
    sort(ch,ch+strlen(ch),cmp);
 do
{
    printf("%s\n",ch);
}while(next_permutation(ch,ch+strlen(ch),cmp));
}
 return 0;
}

输入
1
adv
输出
adv
avd
dav
dva
vad
vda

char 类型的next_permutation

#include 
#include 
#include 
using namespace std;
int main()
{
   char ch[205];
   cin >> ch;
   sort(ch, ch + strlen(ch) );
//该语句对输入的数组进行字典升序排序。如输入9874563102 cout<
   char *first = ch;
   char *last = ch + strlen(ch);
   do {
     cout<< ch << endl;
}while(next_permutation(first, last));
   return 0;
}
//这样就不必事先知道ch的大小了,是把整个ch字符串全都进行排序
//若采用 while(next_permutation(ch,ch+5)); 如果只输入1562,就会产生错误,因为ch中第五个元素指向未知
//若要整个字符串进行排序,参数5指的是数组的长度,不含结束符

string 类型的next_permutation

#include 
#include 
#include 
using namespace std;
/*
int main()
{
 string line;
 while(cin>>line&&line!="#")
{
 if(next_permutation(line.begin(),line.end())) //从当前输入位置开始
cout<
int main()
{
   string line;
   while(cin>>line&&line!="#")
  {
   sort(line.begin(),line.end());//全排列
   cout<<line<<endl;
   while(next_permutation(line.begin(),line.end()))
   cout<<line<<endl;
  }
}

swap交换函数

swap(a,b);
交换a,b的值

#include 
#include 
using namespace std;
int main( )
{
    int a = 10;
    int b = 5;
  swap(a,b);
    cout << "a = " << a << ", b = " << b << endl;
}

输出
a = 5, b = 10

reverse 翻转函数

reverse函数用于反转在[first,last)范围内的顺序(包括first指向的元素,不包括last指向的元素),reverse函数没有返回值

函数原型,该函数等价于通过调用iter_swap来交换元素位置

template <class BidirectionalIterator>
void reverse (BidirectionalIterator first, BidirectionalIterator last)
{
    while ((first!=last)&&(first!=--last))
    {
        std::iter_swap (first,last);
        ++first;
    }

例如:

#include 
#include 
#include 
using namespace std;
int main()
{
    vector<int>a({1,2,3,4,5});
    reverse(a.begin(),a.end());
    for(auto x:a) cout << x <<' ';
    return 0;
}

输出
5 4 3 2 1

unique 去重函数

需要保证相同元素在一起才行,个人建议先sort
m=unique(begin,end)-begin //m为不重复的个数
或者a. erase(unique(begin,end),end)

例如:

#include 
#include 
#include 
using namespace std;
int main()
{
    vector<int>a({1,2,2,3,3,4,4,4});//vector赋初值时不要等号
    int m=unique(a.begin(),a.end())-a.begin();
    cout << m <<endl;
    for(int i=0;i<m;i++) cout << a[i]<<' ';
    return 0;
}

输出
4
1 2 3 4

#include 
#include 
#include 
using namespace std;
int main()
{
    vector<int>a({1,2,2,3,3,4,4,4});//vector赋初值时不要等号
    a.erase(unique(a.begin(),a.end()),a.end());
    for(auto x:a) cout << x <<' ';
    return 0;
}

输出
1 2 3 4

max与min

max(x,y)
返回两个中较小的一个
min(x,y)
返回两个中较大的一个

#include 
#include 
using namespace std;
int main()
{
	int a=max(2,5);
	int b=min(4,3);
	cout<<a<<" "<<b<<endl;
}

lower_bound与upper_bound

头文件: #include< algorithm >
集成了二分的函数

函数lower_bound()
//lower_bound(起始地址,结束地址,要查找的数值) 返回的是数值 第一个 出现的位置。
功能:函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置.
注意:如果所有元素都小于val,则返回last的位置,且last的位置是越界的!!

函数upper_bound()
//upper_bound(起始地址,结束地址,要查找的数值) 返回的是数值 最后一个 出现的位置。
功能:函数upper_bound()返回的在前闭后开区间查找的关键字的上界,返回大于val的第一个元素位置
注意:返回查找元素的最后一个可安插位置,也就是“元素值>查找值”的第一个元素的位置。同样,如果val大于数组中全部元素,返回的是last。(注意:数组下标越界)

lower_bound(val):返回容器中第一个值【大于或等于】val的元素的iterator位置。
upper_bound(val): 返回容器中第一个值【大于】

//当然这个区间内的数应当是有序的。这两个函数返回值都是地址,所以说使用方法如下:

int pos=lower_bound(a+1,a+1+n,5)-a; 
cout<<a[pos];
有时候需要寻找第一个小于等于的数,那么加一个greater即可:
int pos=lower_bound(a+1,a+1+n,5,greater<int>())-a; 
cout<<a[pos];
upper_bound同理
    
    void main()
{
    vector<int> t;
    t.push_back(1);
    t.push_back(2);
    t.push_back(3);
    t.push_back(4);
    t.push_back(6);
    t.push_back(7);
    t.push_back(8);


    int low=lower_bound(t.begin(),t.end(),5)-t.begin();//end()返回的却是末尾元素再下一个元素的迭代器
    int upp=upper_bound(t.begin(),t.end(),5)-t.begin();
    cout<<low<<endl;
    cout<<upp<<endl;


    system("pause");
}
//4
//4
#include

using namespace std;

int main(){
    vector<int> vec = {1,1,2,3,3,4,4,5};
    auto pos1 = lower_bound(vec.begin(), vec.end(), 2) - vec.begin();
    auto pos2 = upper_bound(vec.begin(), vec.end(), 2) - vec.begin();
    auto flag = binary_search(vec.begin(), vec.end(), 2);
    cout << "第一个大于等于2的位置是" << pos1 << endl;
    cout << "第一个大于2的位置是" << pos2 << endl;
    cout << "查找2返回的结果:" << flag << endl;
    return 0;
}

输出
第一个大于等于2的位置是2
第一个大于2的位置是3
查找2返回的结果:1

二、#include< ctype.h>头文件

包含的常用函数如下:

isalnum

函数原型: int isalnum(int ch);

函数功能: 检查ch是否是字母或数字

函数返回: 是字母或数字返回非0,否则返回0//字母返回4,数字返回2

isalpha

函数原型: int isalpha(char ch);

函数功能: 检查ch是否是字母.

函数返回: 是字母返回非0(在vs2015中为2,否则返回 0.//字母返回2

isdigit

函数原型: int isdigit(char ch);

函数功能: 检查ch是否是数字(0-9)//返回1

函数返回: 是返回非0,否则返回0

islower

函数原型: int islower(int ch);

函数功能: 检查ch是否小写字母(a-z)

函数返回: 是返回非0,否则返回0//返回2

isupper

函数原型: int isupper(int ch);

函数功能: 检查ch是否是大写字母(A-Z)

函数返回: 是返回非0,否则返回0//返回1

tolower

函数原型: int tolower(int ch);

函数功能: 将ch字符转换为小写字母

函数返回: 返回ch所代表的字符的小写字母

toupper

函数原型: int toupper(int ch);

函数功能: 将ch字符转换成大写字母

函数返回: 与ch相应的大写字母    

三、#include< iomanip>头文件

iomanip在c++程序里面经常见到的头文件#include < iomanip>,io代表输入输出,manip是manipulator(操纵器)的缩写(在c++上只能通过输入缩写才有效)

包含的主要函数如下:
dec设置整数为十进制
hex设置整数为十六进制
oct设置整数为八进制

int n;
cout<<___<<n<<endl;
//可直接将n转换成相应进制数

fixed

那么如何消除浮点数的科学计数法呢?
答案是用fixed。

//类型一:整数位很多
double x=12345678;
//类型二:小数位很多,有效小数位少
double y=0.00001234;

cout<<fixed<<x<<endl;
cout<<fixed<<y<<endl;

输出结果是:

12345678.000000
0.000012

其实只要出现了fixed,则后面都是以fixed输出。
那么只需要写

cout<<fixed<<x<<endl;
cout<<y<<endl;//之后不用再打一遍fixed了

setprecision()

setprecision( n ) 设显示有效数字为n位

fixed与setprecision(n)连用可以控制小数点后的位数,现在就可以理解因为那是定点数记数法。

如果没有fixed的话,就是浮点数记数法了,那么它控制的应该就是有效数字的位数(包括小数点前的)!!!!!

大家应该很清楚了,但还是举个例子吧。

double x = 0.123456;
double y = 1.123456;

cout<<x<<endl;
cout<<y<<endl;

//0.123456
//1.12346

cout<<fixed<<setprecision(1)<<x<<endl;
cout<<fixed<<setprecision(4)<<y<<endl;

//0.1
//0.1234

setw()

setw( n ) 设域宽为n个字符

//若想用setw(int n)呢,要加头文件 < iomanip > [io+manipulator的意思]
//其控制后面输出的长度,默认右对齐,输出内容长度不够用空格补齐,输出内容长度超过则正常输出。
//注:1. setw()只对后面紧跟的输出有限制。
//    2. 标点符号占一位!
	double x = 0.1;
	double y = 0.123456;

	cout  <<setw(7)<< x << endl;
	cout << x << endl;
	cout << setw(3)<<y << endl;
	
//    0.1
//0.1
//0.123456

setfill()

setfill(char c) 用法 : 就是在预设宽度中如果已存在没用完的宽度大小,则用设置的字符c填充

cout<<setfill('@')<<setw(5)<<255<<endl;
//输出@@255

setw只作用于紧随其后的部分,例如

cout<')<123456
这里setfill('
')<**123,456作为另一部分随后输出。

四、#include< cmath>头文件

头文件cmath或math.h中包含的常用数学函数

1.开平方

double sqrt(double x);

2.求常数e的x次方

double exp(double x);

3.求x的y次方

double pow(double x, double y);

4.求对数ln(x)

double log(double x);

求对数lg(x)

double log10(double x);

其他用换底公式

5.求x绝对值

int abs(x);

long int abs(long int x);

double fabs(double x);

6.三角函数

   求正弦 

double sin(double x);

   求余弦

double cos(double x);

   求正切

double tan(double x);

   反正切

double atan(double x);

7.取整函数

   向上取整

double ceil(double x);

   向下取整

double floor(double x);

8.产生随机数 0~32767

函数原型:int rand(void);

功能和返回值:返回一个 0 ~ RAND_MAX 的随机数 

五、 #include< cstring>头文件

其他相关函数点这里

memset函数

// 头文件
#include//C语言
#include//c++
当初始化一个字节单位的数组时,可以用memset把每个数组单元初始化成任何你想要的值,比如,
int a[MAXN];
memset(a, 0, sizeof(a));//数组中的所有元素全为0
memset(a, -1, sizeof(a));//数组中的所有元素全为-1
memset(a, 127, sizeof(a));//数组中的所有元素全为2139062143(可以将其视为INF)
memset(a,0x3f,sizeof(a));//数组中的所有元素全为0x3f3f(可以将其视为INF)

六、include < numeric>头文件

iota函数

iota函数对一个范围数据进行赋值:

//用法
// iota example
#include      // std::cout
#include       // std::iota    头文件
using namespace std;
int main () {
  int numbers[10];

  iota (numbers,numbers+10,100);

  cout << "numbers:";
  for (int& i:numbers) cout << ' ' << i;
 cout<<endl;

  return 0;
}
//输出
numbers: 100 101 102 103 104 105 106 107 108 109

相当于

//iota(p,p+10010,0);
	for(int i=1;i<=10000;i++)
    {
        p[i]=i;
    }

七、#include < ctime>头文件

random_shuffle 随机打乱

注:可通过更改随机种子,让随机数变得不同

include <ctime>
srand(time(0));//随机种子

输出10000个随机数

#include 
#include 
using namespace std;
int main()
{
	srand(time(0));//time函数返回的是自UTC时间1970年1月1日0点以来经过的秒数。
	for(int i=0;i<10000;i++)
	{
		cout<<rand()%10<<endl;//通过取样控制数的范围
	}
	return 0;
}
#include 
#include 
#include 
using namespace std;
int main()
{
	multiset<int>s;
	srand(time(0));
	for(int i=0;i<10000;i++)
	{
	//	cout<
		s.insert(rand()%10);
	}
	cout<<s.count(0)<<endl;
	cout<<s.count(1)<<endl;
	cout<<s.count(2)<<endl;
	cout<<s.count(3)<<endl;
	cout<<s.count(4)<<endl;
	cout<<s.count(5)<<endl;
	cout<<s.count(6)<<endl;
	cout<<s.count(7)<<endl;
	cout<<s.count(8)<<endl;
	cout<<s.count(9)<<endl;
	return 0;
}

在我这个时间戳输出:
994
973
1005
986
979
1041
1023
940
1054
1005


最后

莫言真理无穷尽,寸进自有寸进欢
算法竞赛常用库函数整理_第1张图片

你可能感兴趣的:(算法,算法,c++,排序算法)