摘要:时间复杂度为,和分别是和的长度示例如下输出输出把从号位开始长度为的子串替换为上把的迭代器范围的子串替换为示例如下
欢迎回到:遇见蓝桥遇见你,不负代码不负卿!
目录
【前言】
这篇是上次文章的后续哦,铁汁们可以先回顾一下上篇的内容。
蓝桥杯算法竞赛系列第0章——蓝桥必考点及标准模板库STL(上)(万字博文,建议抱走)_安然无虞的博客-CSDN博客
上次有好几位铁汁建议我多换点图片,表示看腻了,也有不少热心小友私发给了我一些,但是由于格式大小的问题,能用的不多,不过在这里还是要特别感谢一下哈,抱拳啦。
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- scanf()
- printf()
- getchar()
- putchar()
- gets()
- puts()
- sscanf()
- sprintf()
标准输入输出头文件,当然除了scanf() 和 printf() 很重要外,sscanf() 和 sprintf()也是非常重要的,对于这两个库函数,老师从未讲过,但是看题解时经常出现,它们是用来处理字符串的利器。待会再谈它们,先讲一下scanf() 的弊端,对于scanf() 函数,不能读入空格,遇到空格就结束了,所以处理起字符串就很不方便。所以这里还有两个库函数用来处理字符串:gets() 和 puts() , gets() 用来输入一行字符串,识别"/n" 结束,遇到空格不会结束哦,puts() 用来输出一行字符串,并且紧跟一个换行,对于putchar()和getchar() 用得不多,有兴趣可自行了解哦。
sscanf() 与 sprintf() 是处理字符串问题的利器,我们很有必要学会它们(sscanf() 从单词上可理解为 string + scanf , sprintf 则可理解为 string + printf, 均在stdio.h 头文件下) 。先来回顾一下scanf() 和 printf(), 如果想要从屏幕上输入int 型变量n 并将int 型变量 n 输出到屏幕上,则可以写成下面这样:
scanf("%d", &n);printf("%d", n);
事实上,上面的写法其实可以表示成下面的样子,其中screen 表示屏幕:
scanf(screen, "%d", &n);printf(screen, "%d", n);
可以发现,scanf() 的输入其实是把screen 的内容以"%d" 的格式传输到n 中(即从左至右),而printf() 的输出则是把n 以“%d” 的格式传输到screen 上(即从右至左)
sscanf() 和 sprintf() 与上面的格式是相同的,只不过把screen 换成了字符数组(假设定义了一个char 数组 str[100]),如下所示:
sscanf(str, "%d", &n);sprintf(str, "%d", n);
上面的sscanf() 写法的作用是把字符数组str 中的内容以"%d" 的格式写到n 中(还是从左至右)
示例如下:
#includeint main(){ int n = 0; char str[100] = "123"; sscanf(str, "%d", &n); printf("%d/n", n);//输出123 return 0;}
而sprintf() 写法的作用是把n 以"%d" 的格式写到str 字符数组中(还是从右至左)
示例如下:
#includeint main(){ int n = 233; char str[100]; sprintf(str, "%d", n); printf("%s/n", str);//输出233 return 0;}
上面只是一些简单的应用,事实上,可以像使用scanf() 和 printf() 那样进行复杂的格式的输入和输出。例如下面的代码使用sscanf() 将字符数组str 中的内容按"%d:%lf,%s"的格式写到int 型变量n、double 型变量db、char型数组str2中
#includeint main(){ int n; double db; char str[100] = "2048:3.14,hello", str2[100]; sscanf(str, "%d:%lf,%s", &n, &db, str2); printf("n = %d, db = %lf, str2 = %s/n", n, db, str2); return 0;}
类似的,下面的代码使用sprintf() 将int 型变量n 、double 型变量db、char 型数组str2 按"%d:%lf,%s" 的格式写到字符数组str 中
#includeint main(){ int n = 12; double db = 3.1415; char str[100], str2[100] = "good"; sprintf(str, "%d:%.2lf,%s", n, db, str2); printf("str = %s/n", str); return 0;}
主要用于生成随机数以及动态内存开辟,常用的库函数有srand((unsigned int) time(NULL)),rand() 和动态内存开辟用的malloc(),用new会更简单一些
上面生成随机数的时候,常用time()函数用于生成时间戳,作为随机数种子
- fabs()
- sqrt()
- pow()
- floor()
- ceil()
- round()
用数学函数可以节省大量的时间,所以一定要记住,对于很常用的其实也就是fabs()、sqrt()和pow()
该函数用于对double 型变量取绝对值。
该函数用于返回 r ^ p ,要求r 和 p 都是double类型的
该函数用于返回double型变量的算数平方根
在这里就只简单介绍这三个最常用的。
- strlen()
- strcmp()
- strcpy()
- strcat()
strlen()函数可以得到字符数组中第一个/0之前的字符的个数
strcmp()函数返回两个字符串大小的比较结果,比较原则是按字典序,所谓字典序就是字符串在字典中的顺序,因此如果有两个字符数组str 1 和 str 2, 且满足str 1[0...k - 1] == str 2[0...k - 1]、str1[k] < str2[k], 那么就说str 1的字典序小于str2。例如"a" 的字典序小于"b"、"aaaa" 的字典序小于"aab"
strcmp()函数的返回值:
- 如果字符数组1 < 字符数组2,则返回一个负整数(不一定是-1,由编译器决定)
- 如果字符数组1 == 字符数组2,则返回0
- 如果字符数组1 > 字符数组2,则返回一个正整数(不一定是1,由编译器决定)
strcpy()函数可以把一个字符串复制给另一个字符串,格式如下:
strcpy(字符数组1,字符数组2);
注意哦,是把字符数组2复制给字符数组1,这里的“复制” 包括了结束标志/0
示例如下:
#include#includeint main(){ char str1[50] = "Thank"; char str2[50] = "you for your smile."; strcpy(str1, str2); puts(str1);//输出you for your smile. //printf("%s/n", str1); return 0;}
strcat()可以把一个字符串拼接到另一个字符串的后面
strcat(字符数组1, 字符数组2);
注意哦,是把字符数组2拼接到字符数组1的后面
示例如下:
#include#includeint main(){ char str1[50] = "Thank"; char str2[50] = "you for your smile."; strcat(str1, str2); puts(str1);//输出 Thankyou for your smile. //printf("%s/n", str1); return 0; return 0;}
常用函数:
- push_back()
- pop_back()
- size()
- clear()
常用函数
- push()
- pop()
- front()
- back()
- empty()
- size()
常用函数:
- push()
- pop()
- top()
- empty()
- size()
常用函数:
- max()
- min()
- swap()
- fill()
- sort()
下面在介绍一些常见的容器:
在C语言中,一般使用字符数组char str[ ] 来存放字符串,但是使用字符数组有时会显得操作麻烦,而且容易因经验不足产生错误,得不偿失。为了使编程者可以更方便的对字符串进行操作,C++在STL中加入了string类型,对字符串常用的需求功能进行了封装,使得操作起来更方便,且不易出错。
如果要使用string,需要添加string头文件,即#include
(注意string.h 和 string 是不一样的头文件)。除此之外,还需要在头文件下面加上一句:"using namespace std;", 这样就可以在代码中使用string了。下面来看string的一些常见用法。
定义string的方式跟基本数据类型相同,只需要在string后面跟上变量名即可:
string str;
如果要初始化,可以直接给string类型的变量进行赋值:
string str = "abcd"
一般来说,可以直接像字符数组那样去访问string:
#include#includeusing namespace std;int main(){ string str = "abcd"; for (int i = 0; i < str.length(); i++) { printf("%c ", str[i]);//输出a b c d } return 0;}
注意哦,如果要读入和输出整个字符串,则只能用cin 和 cout:
#include//cin和cout在iostream头文件中,而不是stdio.h#includeusing namespace std;int main(){ string str; cin >> str; cout << str; return 0;}
上面的代码对任意的字符串输入,都会输出同样的字符串。
那么,真的没有办法用printf来输出string吗?其实是有的,即用c_str()将string类型转换为字符数组进行输出,示例如下:
#include#includeusing namespace std;int main(){ string str = "abcd"; printf("%s/n", str.c_str());//将string型str使用c_str()变成字符数组 return 0;}
一般仅通过(1)即可满足访问的要求,但是有些函数比如insert()与erase()则要求以迭代器为参数,因此还是需要学习一下string迭代器的用法。
由于string不像其他STL容器那样需要参数,因此可以直接入下定义:
string::iterator it;
这样就得到了迭代器it, 并且可以通过*it 来访问string里的每一位:
#include#includeusing namespace std;int main(){ string str = "abcd"; for (string::iterator it = str.begin(); it != str.end(); it++) { printf("%c ", *it);//输出a b c d } return 0;}
最后指出,string和vector一样,支持直接对迭代器进行加减某个数字,如str.begin() + 3的写法是可行的
- operator+=
- compare operator
- length() / size()
- insert()
- erase()
- clear()
- substr()
- string::nops
- find()
- replace()
这是string的加法,可以将两个string直接拼接起来
示例如下:
#include#includeusing namespace std;int main(){ string str1 = "abc", str2 = "xyz", str3; str3 = str1 + str2;//将str1和str2拼接,赋值给str3 str1 = str1 + str2;//将str2直接拼接到str1上 cout << str1 << endl;//输出abcxyz cout << str3 << endl;//输出abcxyz return 0;}
两个string类型可以直接使用==、!=、<、<=、>、>=比较大小,比较规则是字典序。
示例如下:
#include#includeusing namespace std;int main(){ string str1 = "aa", str2 = "aaa", str3 = "abc", str4 = "xyz"; if (str1 < str2)//如果str1字典序小于str2,输出ok1 { printf("ok1/n");//输出ok1 } if (str1 != str3)//如果str1和str3字典序不等,输出ok2 { printf("ok2/n");//输出ok2 } if (str4 >= str3)//如果str4字典序大于等于str3,输出ok3 { printf("ok3/n");//输出ok3 } return 0;}
length()返回string的长度,即存放的字符数。时间复杂度为O(1)。size()与length()基本相同
示例如下:
string str = "abcdef";printf("%d %d/n", str.length(), str.size());//输出6 6
string的insert()函数有很多种写法,这里给出几种常用的写法。时间复杂度为O(N)
1.insert(pos, string), 在pos号位置插入一个字符串string
示例如下:
string str = "abcxyz", str2 = "opq";str.insert(3, str2);//往str[3]处插入opq,将括号里的str2直接写成"opq"也是可以的cout<
2.insert(it, it2, it3), it 为原字符串的欲插入位置,it2 和 it3 为待插字符串的首尾迭代器,用来表示串[it2, it3)将被插在it 的位置上
示例如下:
#include#includeusing namespace std;int main(){ string str = "abcxyz", str2 = "opq";//str为原字符串,str2为待插字符串 //在str的3号位(即c和x之间)插入str2 str.insert(str.begin() + 3, str2.begin(), str2.end()); cout << str << endl;//输出abcopqxyz return 0;}
erase()有两种用法:删除单个元素、删除一个区间内的所有元素。时间复杂度均为O(N)
1.删除单个元素:str.erase(it) 用于删除单个元素,it为需要删除的元素的迭代器
示例如下:
#include#includeusing namespace std;int main(){ string str = "abcdefg"; str.erase(str.begin() + 4);//删除4号位(即e) cout << str << endl;//输出abcdfg return 0;}
2.删除一个区间内的所有元素:有两种方法:
示例如下:
#include#includeusing namespace std;int main(){ string str = "abcdefg"; //删除在[str.begin() + 2, str.end() - 1)内的元素,即cdef str.erase(str.begin() + 2, str.end() - 1); cout << str << endl;//输出abg return 0;}
示例如下:
#include#includeusing namespace std;int main(){ string str = "abcdefg"; str.erase(3, 2);//删除de cout << str << endl;//输出abcfg return 0;}
clear()可以清空string中的数据,时间复杂度一般为O(1)
示例如下:
#include#includeusing namespace std;int main(){ string str = "abcd"; str.clear();//清空字符串 cout << str.length() << endl;//输出0 return 0;}
substr(pos, len) 返回从pos号位开始、长度为len的子串,时间复杂度为O(len)
示例如下:
#include#includeusing namespace std;int main(){ string str = "Thank you for your smile."; cout << str.substr(0, 5) << endl;//输出Thank cout << str.substr(14, 4) << endl;//输出your cout << str.substr(19, 5) << endl;//输出smile return 0;}
string::npos是一个常数,其本身的值为-1 ,但由于是unsigned int 类型,因此实际上也可以认为是unsigned int 类型的最大值,可认为是4,294,967,295。string::npos 用以作为 find 函数失配时的返回值。
str.find(str) 当str2 是str 的子串时,返回其在str 中第一次出现的位置,如果str2 不是str 的子串,那么返回string::npos
str.find(str2, pos), 从str 的pos 号位开始匹配str2,返回值与上相同。时间复杂度为O(M*N),M和N 分别是str2 和str的长度
示例如下:
#include#includeusing namespace std;int main(){ string str = "Thank you for your smile"; string str2 = "you"; string str3 = "me"; if (str.find(str2) != string::npos) { cout << str.find(str2) << endl;//输出6 } if (str.find(str2, 7) != string::npos) { cout << str.find(str2, 7) << endl;//输出14 } if (str.find(str3) != string::npos) { cout << str.find(str3) << endl; } else { cout << "I know there is no position for me." << endl; } return 0;}
str.replace(pos,len,str2) 把str 从pos 号位开始、长度为len 的子串替换为上str2
str.replace(it1,it2,str2) 把str 的迭代器[it1, it2)范围的子串替换为str2
示例如下:
#include#includeusing namespace std;int main(){ string str = "Maybe you will turn around."; string str2 = "will not"; string str3 = "surely"; cout << str.replace(10, 4, str2) << endl; cout << str.replace(str.begin(), str.begin() + 5, str3) << endl; return 0;}
queue翻译为队列,在STL中主要则是实现一个先进先出的容器,当需要实现广度优先搜索时,可以不用自己手动实现一个队列,而是用queue代替,以提高程序的准确性。
要使用queue, 需要先添加头文件#include
其定义的写法和其他STL容器相同,typename 可以是任意基本数据类型和容器:
queue name;
由于队列(queue)本身就是一种先进先出的限制性数据结构,因此在STL中只能通过front() 来访问队首元素,或是通过back() 来访问队尾元素。
示例如下:
#include#includeusing namespace std;int main(){ queue q; for (int i = 1; i <= 5; i++) { q.push(i);//push(i)用以将i压入队列,因此依次入队1 2 3 4 5 } printf("%d %d/n", q.front(), q.back());//输出结果为1 5 return 0;}
- push()
- front()
- back()
- pop()
- empty()
- size()
push(x) 将x 进行入队,时间复杂度为O(1)
front(), back()可以分别获得队首元素和队尾元素,时间复杂度为O(1)
注意哦,使用front() 和 pop() 函数之前,必须用empty() 判断队列是否为空,否则可能会因为队列空导致错误
pop()令队首元素出队,时间复杂度为O(1)
示例如下:
#include#includeusing namespace std;int main(){ queue q; for (int i = 1; i <= 5; i++) { q.push(i); } for (int i = 0; i < 3; i++) { q.pop();//出队列元素3次,依次出队1 2 3 } printf("%d/n", q.front());//输出4 return 0;}
empty()检测queue是否为空,返回true则为空,返回false则非空,时间复杂度为O(1)
示例如下:
#include#includeusing namespace std;int main(){ queue q; if (q.empty() == true)//一开始队列里没有元素,所以是空 { printf("Empty/n"); } else { printf("Not Empty/n"); } q.push(1); if (q.empty() == true) { printf("Empty/n"); } else { printf("Not Empty/n"); } return 0;}
size()返回queue内元素的个数,时间复杂度为O(1)
示例如下:
#include#includeusing namespace std;int main(){ queue q; for (int i = 1; i <= 5; i++) { q.push(i); } printf("%d/n", q.size());//输出5 return 0;}
【延伸】:STL容器中还有两种容器跟队列有关,分别是双端队列(deque) 和优先队列(priority_queue) ,前者是首尾皆可插入和删除的队列,后者是使用堆实现的默许将当前队列最大元素置于队首的容器,这里暂时先不介绍,后期如果需要再进行补充。
stack 翻译为栈,是STL中实现的一个先进后出的容器,stack 用来模拟实现一些递归,防止程序对栈内存的限制而导致程序运行出错。
要使用stack,应先添加头文件#include
其定义的写法和其他STL容器相同,typename可以是任意基本数据类型或容器:
stack name;
由于栈(stack) 本身就是一种先进后出的数据结构,在STL的stack 中只能通过top() 来访问栈顶元素
示例如下:
#include#includeusing namespace std;int main(){ stack st; for (int i = 1; i <= 5; i++) { st.push(i);//依次入栈1 2 3 4 5 } printf("%d/n", st.top());//输出5 return 0;}
- push()
- top()
- pop()
- empty()
- size()
push(x) 将x 入栈,时间复杂度为O(1),
top()获得栈顶元素,时间复杂度为O(1)
pop()用以弹出栈顶元素,时间复杂度为O(1)
示例如下:
#include#includeusing namespace std;int main(){ stack st; for (int i = 1; i <= 5; i++) { st.push(i); } for (int i = 0; i < 3; i++) { st.pop(); } printf("%d/n", st.top());//输出2 return 0;}
empty()可以检测stack 内是否为空,返回true 为空,返回false 为非空,时间复杂度为O(1)
size()返回stack 内元素的个数,时间复杂度为O(1)
使用algorithm 头文件,需要在头文件下面加上一行"using namespace std;",才能正常使用
- max()、min()、abs()
- swap()
- reverse()
- next_permutation()
- fill()
- sort()
- lower_bound() 和 upper_bound()
max(x,y)和min(x,y) 分别返回x, y中的最大值和最小值,且参数必须是两个,可以是浮点数,如果想返回三个数x,y,z的最大值,可以使用max(x, max(y, z)) 的写法;abs(x) 返回x的绝对值。注意:此时的x 必须是整数,浮点数的绝对值请用math 头文件下的fabs
示例如下:
#include#includeusing namespace std;int main(){ int x = -1; int y = -2; printf("%d %d/n", max(x, y), min(x, y));//输出-1 -2 printf("%d %d/n", abs(x), abs(y));//输出1 2 return 0;}
swap(x, y) 用来交换x 和 y 的值
示例如下:
#include#includeusing namespace std;int main(){ int x = 10; int y = 20; swap(x, y); printf("%d %d/n", x, y);//输出20 10 return 0;}
reverse(it, it2) 可以将数组指针在[it, it2) 之间的元素或容器的迭代器在[it, it2) 范围内的元素进行反转
示例如下:
#include#includeusing namespace std;int main(){ int arr[10] = { 10,11,12,13,14,15 }; reverse(arr, arr + 4);//将arr[0]~arr[3]反转 for (int i = 0; i < 6; i++) { printf("%d ", arr[i]);//输出13,12,11,10,14,15 } return 0;}
如果要是对容器中的元素(例如string 字符串)进行反转,结果也是一样
示例如下:
#include#include#includeusing namespace std;int main(){ string str = "abcdefghi"; reverse(str.begin() + 2, str.begin() + 6);//对str[0]~str[5]反转 for (int i = 0; i < str.length(); i++) { printf("%c", str[i]);//输出abfedcghi } return 0;}
next_permutation() 给出一个序列在全排列中得下一个序列
例如,当n == 3 时的全排列为:
123
132
213
231
312
321
这样231的下一个序列就是312
示例如下:
#include#includeusing namespace std;int main(){ int a[10] = { 1,2,3 }; //a[0]~a[2]之间的序列需要求解next_permutation do { printf("%d%d%d/n", a[0], a[1], a[2]); } while (next_permutation(a, a + 3)); return 0;}
在上述的代码中,使用循环是因为next_permutation在已经到达全排列的最后一个时会返回false, 这样会方便退出循环。而使用do...while语句而不使用while语句是因为序列1 2 3本身也需要输出,如果使用while会直接跳到下一个序列再输出,这样的话结果会少一个123
fill()可以把数组或容器中的某一段区间赋为某个相同的值。和memset 不同,这里的赋值可以是数组类型对应范围中的任意值
示例如下:
#include#includeusing namespace std;int main(){ int a[5] = { 1,2,3,4,5 }; fill(a, a + 5, 133);//将a[0]~a[4]均赋值为133 for (int i = 0; i < 5; i++) { printf("%d ", a[i]);//输出133 133 133 133 133 } return 0;}
顾名思义,sort()就是用来排序的函数,它根据具体情形使用不同的排序方法,效率较高。一般来说,不推荐使用C语言中的qsort函数,原因是qsort 用起来比较繁琐,涉及很多指针的操作。
sort函数的使用必须加上头文件"#include
sort(首元素地址(必填),尾元素地址的下一个地址(必填),比较函数(非必填));
可以看到,sort的参数有三个,其中前两个是必填的,而比较函数则可以根据需要填写,如果不写比较函数,则默认对前面给出的区间进行递增排序。
示例如下:
#include#includeusing namespace std;int main(){ int a[6] = { 9,4,2,5,6,-1 }; //将a[0]~a[3]进行从小到大排序 sort(a, a + 4); for (int i = 0; i < 6; i++) { printf("%d ", a[i]);//输出2 4 5 9 6 -1 } putchar("/n"); //将a[0]~a[5]进行从小到大排序 sort(a, a + 6); for (int i = 0; i < 6; i++) { printf("%d ", a[i]);//输出-1 2 4 5 6 9 } return 0;}
【敲黑板】:特别需要注意理解的是尾元素地址的下一个地址!
对double数组进行排序:
#include#includeusing namespace std;int main(){ double a[] = { 1.4,-2.1,9 }; sort(a, a + 3); for (int i = 0; i < 3; i++) { printf("%.1lf ", a[i]); } return 0;}
对char型数组进行排序(默认是字典序)
示例如下:
#include#includeusing namespace std;int main(){ char c[] = { "T", "W","A", "K" }; sort(c, c + 4); for (int i = 0; i < 4; i++) { printf("%c", c[i]);//输出AKTW } return 0;}
我们需要知道的是,如果对序列进行排序,那么序列中的元素一定要有可比性,因此需要制定排序规则来建立这种可比性。特别是像结构体,本身并没有大小关系,需要认为制定比较的规则。sort 的第三个可选参数就是cmp函数,用来实现这个规则。
下面介绍对基本数据类型、结构体类型、STL容器进行自定义规则排序时cmp的写法。
若比较函数不填,则默认按照从小到大的顺序排序。
示例如下:
#include#includeusing namespace std;int main(){ int a[] = { 3,1,4,2 }; sort(a, a + 4); for (int i = 0; i < 4; i++) { printf("%d ", a[i]);//输出1 2 3 4 } return 0;}
如果想要从大到小来排序,则要使用比较函数cmp 来“告诉”sort 何时要交换元素(让元素的大小比较关系反过来)
示例如下:
#include#includeusing namespace std;bool cmp(int a, int b){ return a > b;//可以理解为当a>b时把a放在b前面}int main(){ int a[] = { 3,1,4,2 }; sort(a, a + 4, cmp); for (int i = 0; i < 4; i++) { printf("%d ", a[i]);//输出4 3 2 1 } return 0;}
这样就可以让数值较大的元素放在前面,也就达到了从大到小排序的要求。
同样的,对double型数组从大到小排序的代码如下:
#include#includeusing namespace std;bool cmp(double a, double b){ return a > b;//同样是a>b}int main(){ double a[] = { 1.4,-2.1,9 }; sort(a, a + 3, cmp); for (int i = 0; i < 3; i++) { printf("%.1lf ", a[i]);//输出9.0 1.4 -2.1 } return 0;}
对char型数组从大到小排序如下:
#include#includeusing namespace std;bool cmp(char a, char b){ return a > b;//可以理解为当a>b时把a放在b之前}int main(){ char c[] = { "T","W","A","K" }; sort(c, c + 4, cmp); for (int i = 0; i < 4; i++) { printf("%c", c[i]);//输出WTKA } return 0;}
【记忆方法】:
如果要把数据从小到大排列,那么就用"<", 因为"a", 因为"a>b" 就是左大右小。而当不确定或者忘记的时候,不妨两种都试一下,就会知道该用哪种了。
现在定义了如下结构体:
struct node{ int x, y;}ssd[10];
如果想将ssd数组按照 x 从大到小排序(即进行一级排序),那么可以这样写cmp函数:
bool cmp(node a, node b){ return a.x > b.x;}
示例如下:
#include#includeusing namespace std;struct node{ int x; int y;}ssd[10];bool cmp(node a, node b){ return a.x > b.x;//按x值从大到小对结构体数组进行排序}int main(){ ssd[0].x = 2; ssd[0].y = 2; ssd[1].x = 1; ssd[1].y = 3; ssd[2].x = 3; ssd[2].y = 1; sort(ssd, ssd + 3, cmp); for (int i = 0; i < 3; i++) { printf("%d %d/n", ssd[i].x, ssd[i].y); } return 0;}
而如果想先按x 从大到小排序,但当x相等的情况下,按照y的大小从小到大来排序(即进行二级排序),那么cmp的写法是:
bool cmp(node a, node b){ if(a.x != b.x) { return a.x > b.x; } else { return a.y < b.y; }}
这里的cmp函数首先判断结构体内的x 元素是否相等,如果不相等则直接按照x 的大小来排序,否则,按照y 的大小来排序。
示例如下:
#include#includeusing namespace std;struct node{ int x; int y;}ssd[10];bool cmp(node a, node b){ if (a.x != b.x) { return a.x > b.x;//x 不等时按x 从大到小排序 } else { return a.y < b.y;//x 相等时按y 从小到大排序 }}int main(){ ssd[0].x = 2; ssd[0].y = 2; ssd[1].x = 1; ssd[1].y = 3; ssd[2].x = 3; ssd[2].y = 1; sort(ssd, ssd + 3, cmp);//排序 for (int i = 0; i < 3; i++) { printf("%d %d/n", ssd[i].x, ssd[i].y); } return 0;}
在STL标准容器中,只有vector、string、deque是可以使用sort的。这是因为像set、map这种容器是用红黑树实现的(了解即可),元素本身有序,故不允许使用sort排序
vector示例如下:
#include#include#includeusing namespace std;bool cmp(int a, int b)//因为vector中的元素为int型,因此仍然是int的比较{ return a > b;}int main(){ vector vi; vi.push_back(3); vi.push_back(1); vi.push_back(2); sort(vi.begin(), vi.end(), cmp); for (vector::iterator it = vi.begin(); it != vi.end(); it++) { printf("%d ", *it);//输出3 2 1 } return 0;}
再来看string 的排序,示例如下:
#include#include#includeusing namespace std;int main(){ string str[3] = { "bbbb", "cc", "aaa" }; sort(str, str + 3);//将string数组按字典树从小到大输出 for (int i = 0; i < 3; i++) { cout << str[i] << endl; } return 0;}
如果上面这个例子中,需要按照字符串长度从小到大排序,那么可以这样写:
#include#include#includeusing namespace std;bool cmp(string str1, string str2){ return str1.length() < str2.length();//按照string 的长度从小到大排序}int main(){ string str[3] = { "bbbb", "cc", "aaa" }; sort(str, str + 3, cmp); for (int i = 0; i < 3; i++) { cout << str[i] << endl; } return 0;}
lower_bound() 和 upper_bound() 需要用在一个有序数组或容器中
lower_bound(first, last, val) 用来寻找在数组或容器的[first, last) 范围内第一个值大于等于val元素的位置,如果是数组,则返回该位置的指针;如果是容器,则返回该位置的迭代器。
upper_bound(first, last, val) 用来寻找在数组或容器的[first, last) 范围内第一个值大于val 的元素的位置,如果是数组,则返回该位置的指针;如果是容器,则返回该位置的迭代器。
显然,如果数组或容器中没有需要寻找的元素,则lower_bound() 和 upper_bound() 均返回可以插入该元素的位置的指针或迭代器(即假设存在该元素时,该元素应当在的位置)。
示例如下:
#include#includeusing namespace std;int main(){ int a[10] = { 1,2,2,3,3,3,5,5,5,5 }; //寻找-1 int* lowerPos = lower_bound(a, a + 10, -1); int* upperPos = upper_bound(a, a + 10, -1); printf("%d %d/n", lowerPos - a, upperPos - a);//输出0 0 //寻找1 lowerPos = lower_bound(a, a + 10, 1); upperPos = upper_bound(a, a + 10, 1); printf("%d %d/n", lowerPos - a, upperPos - a);//输出0 1 //寻找3 lowerPos = lower_bound(a, a + 10, 3); upperPos = upper_bound(a, a + 10, 3); printf("%d %d/n", lowerPos - a, upperPos - a);//输出3 6 //寻找4 lowerPos = lower_bound(a, a + 10, 4); upperPos = upper_bound(a, a + 10, 4); printf("%d %d/n", lowerPos - a, upperPos - a);//输出6 6 //寻找6 lowerPos = lower_bound(a, a + 10, 6); upperPos = upper_bound(a, a + 10, 6); printf("%d %d/n", lowerPos - a, upperPos - a);//输出10 10 return 0;}
显然,如果只想获得欲查元素的下标,就可以不使用临时指针,而直接令返回值减去数组首地址即可。
【敲黑板】:这里补充一条知识点,指针 - 指针 = 两指针之间的元素个数
示例如下:
#include#includeusing namespace std;int main(){ int a[10] = { 1,2,2,3,3,3,5,5,5,5 }; //寻找3 printf("%d %d/n", lower_bound(a, a + 10, 3) - a, upper_bound(a, a + 10, 3) - a);//输出3 6 return 0;}
希望能给大家带来帮助,码字不易,如果可以动动小手来个三连那就更好啦,hh,咱们下次再见。
·
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/124089.html
摘要:针对计算机类的同学,数学建模,电子科技大赛,大创,,蓝桥杯这些都是值得参加的高含金量的比赛,无论是学校加分还是应届招聘,都被广泛认可。但近几届的蓝桥杯题目难度已经明显增大,准备参加的同学也决不可掉以轻心。 ...
摘要:文章目录一你应该知道的蓝桥杯含金量获奖率高不高支持哪些编程语言二川川带你体验蓝桥杯省赛蓝桥杯蓝桥杯三个人感受一你应该知道的蓝桥杯如果你是计算机相关专业,你不知蓝桥杯就过不去了,我们来看看蓝桥杯如何,不知道更应该来了解下了。 ...
摘要:问题描述审美的历程课上有位学生,帅老师展示了幅画,其中有些是梵高的作品,另外的都出自五岁小朋友之手。输入格式第一行两个数和,表示学生数和图画数接下来是一个的矩阵如果,表示学生觉得第幅画是小朋友画的如果,表示学生觉得第幅画是梵高画的。 问题描述 《审美的历程》课上有n位学生,帅老师展示了m幅画,其中有些是梵高的作品,另外的都出自五岁小朋友之手。老师请同学们分辨哪些画的作者是梵高,但是老...
摘要:而众所周知,马是要走日子格的。输出格式输出有一行,一个数表示走法数。那为了防止爆掉,我们每加完一条路的总步数之后就取一遍余。题目解法思路如上述,但是这里有一个我之前从来没有注意过的问题,导致我一直只有分。三题解四题目链接过河马 ...
摘要:现在小明想统计有哪些帖子曾经是热帖。如果一个帖子曾在任意一个长度为的时间段内收到不少于个赞,小明就认为这个帖子曾是热帖。以下行列代表一张海域照片。照片保证第行第列第行第列的像素都是海洋。 2018年4月1日愚人节,我第一次参加了有关计算机算法类比赛蓝桥杯,这篇算是经验总结和题目回顾,水平有限,有不妥之处欢迎留言批评指正,也可以加QQ891465170交流~下面进入正题: 第一题:第几...
阅读 2620·2021-11-23 09:51
阅读 3188·2021-11-22 14:44
阅读 4547·2021-11-22 09:34
阅读 5004·2021-10-08 10:14
阅读 2295·2021-09-22 15:47
阅读 3421·2021-09-22 15:40
阅读 1465·2019-08-30 15:44
阅读 1590·2019-08-28 18:23