《算法笔记》学习笔记
第四章 入门篇(2)–算法初步
4.1排序
4.1.1 选择排序
void select_sort(int *a, int size) {
for(int i = 0; i < size - 1; i++) {
int min_index = i;
for(int j = i + 1; j < size; j++) {
if(a[j] < a[min_index])
min_index = j;
}
if(min_index != i) {
int temp = a[i];
a[i] = a[min_index];
a[min_index] = temp;
}
}
}
看完书中的选择排序代码突然想到了自己以前学完冒泡排序之后写的排序:
void my_sort(int *a, int size) {
for(int i = 0; i < size - 1; i++) {
for(int j = i + 1; j < size; j++) {
if(a[i] > a[j]) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
}
正规的冒泡排序:
void bubble_sort(int *a, int size) {
for(int i = 1; i < size; i++) {
for(int j = 0; j < size - i; j++) {
if(a[j] > a[j + 1]) {
int temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
}
以前一直以为自己写的是冒泡排序,现在看来其实是选择排序
4.1.2 插入排序
void insert_sort(int *a, int size) {
for(int i = 1; i < size; i++){
int temp = a[i];
int j = i;
while(j > 0 && a[j - 1] > temp) {
a[j] = a[j - 1];
j--;
}
a[j] = temp;
}
}
主要思想就是将整个数组分成有序序列和无序序列两部分(初始有序序列为数组第一个元素),每次遍历都将无序序列中第一个元素插入到有序序列中,插入方式是从有序序列末尾开始比较,若比它大就直接插入在其后面,否则往前找直到找到该插入的位置。
以上三种算法的时间复杂度都是 O ( n 2 ) O(n^2) O(n2).
4.1.3 排序题与sort函数的应用
- C++sort()函数用法:
int a[5]={1, 3, 4, 2, 5};
sort(a, a + 5); //默认非降序排序
//sort()函数还可以编写cmp()函数进行自定义排序规则
bool cmp(int a, int b) {
return a > b; //将大的整数排在前面,也就是非升序排列
}
sort(a, a + 5, cmp);
- 结构体联合cmp()排序:
//排序规则:分数高的排在前面,若分数相同则按姓名字典序小的排在前面
bool cmp(Student a, Student b) {
if(a.score != b.score) return a.score > b.score;
else return strcmp(a.name, b.name) < 0;
}
例题
思路:
- 建立Student结构体(char id[13], int score, int location_number, int local_rank)
- 编写cmp()函数
bool cmp(Student a, Student b) {
if(a.score != b.score) return a.score > b.score;
else return strcmp(a.id, b.id) < 0;
}
- 注意排名并列问题以及各考场排名和总排名区分
代码实现:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
struct Student {
char id[14];
int score;
int location_number;
int local_rank;
}s[30000];
bool cmp(Student a, Student b) {
if(a.score != b.score) return a.score > b.score;
else return strcmp(a.id, b.id) < 0;
}
int main() {
int n, k;
int num = 0;
cin >> n;
for(int i = 0; i < n; i++) {
cin >> k;
for(int j = 0; j < k; j++) {
cin >> s[num].id >> s[num].score;
s[num].location_number = i + 1;
num++;
}
sort(s + num - k, s + num, cmp);
for(int i = num - k; i < num; i++) {
s[i].local_rank = i - (num - k) + 1;
if(i != num - k && s[i].score == s[i - 1].score)
s[i].local_rank = s[i - 1].local_rank;
}
}
sort(s, s + num, cmp);
cout << num << endl;
int r = 1;
for(int i = 0; i < num; i++) {
cout << s[i].id << " ";
if(i != 0 && s[i].score == s[i - 1].score) {
cout << r;
} else {
cout << i + 1;
r = i + 1;
}
cout << " " << s[i].location_number;
cout << " " << s[i].local_rank << endl;
}
return 0;
}
习题练习
Codeup墓地
1.问题 A: 排序
//排序
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int n;
while(cin >> n) {
int a[n];
for(int i = 0; i < n; i++) {
cin >> a[i];
}
sort(a, a + n);
for(int i = 0; i < n; i++) {
cout << a[i];
if(i != n - 1) cout << " ";
}
cout << endl;
}
return 0;
}
坑点在于可能有多次输入,并且不要忘了结尾的回车
2.问题B:特殊排序
//特殊排序
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int n;
while(cin >> n) {
int a[n];
for(int i = 0; i < n; i++) {
cin >> a[i];
}
sort(a, a + n);
if(n == 1) {
cout << a[0] << endl;
cout << "-1" << endl;
} else {
cout << a[n - 1] << endl;
for(int i = 0; i < n - 1; i++) {
cout << a[i];
if(i != n - 1) cout << " ";
}
cout << endl;
}
}
return 0;
}
3.问题 C: EXCEL排序
//EXCEL排序
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
struct Student {
char id[7];
char name[9];
int score;
}s[100000];
bool cmp1(Student a, Student b) {
return strcmp(a.id, b.id) < 0;
}
bool cmp2(Student a, Student b) {
if(strcmp(a.name, b.name) == 0) return strcmp(a.id, b.id) < 0;
else return strcmp(a.name, b.name) < 0;
}
bool cmp3(Student a, Student b) {
if(a.score == b.score) return strcmp(a.id, b.id) < 0;
else return a.score < b.score;
}
int main() {
int n, c;
int num = 1;
while(cin >> n >> c && n != 0) {
for(int i = 0; i < n; i++) {
cin >> s[i].id >> s[i].name >> s[i].score;
}
if(c == 1) sort(s, s + n, cmp1);
else if(c == 2) sort(s, s + n, cmp2);
else sort(s, s + n, cmp3);
cout << "Case " << num << ":" << endl;
for(int i = 0; i < n; i++) {
cout << s[i].id << " " << s[i].name << " " << s[i].score << endl;
}
num++;
}
return 0;
}
坑点在于Case后面的数是测试用例数,不是C。还有超时的问题。
4.问题 D: 字符串内排序
//字符串内排序
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int main() {
char c[201];
while(cin.getline(c, 201)) {
sort(c, c + strlen(c));
cout << c << endl;
}
return 0;
}
坑点在于getline()第二个参数不能填200
5.问题 E: Problem B
//Problem B
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
bool cmp(int a, int b) {
return a > b;
}
int main() {
int n;
while(cin >> n) {
int c[n][n];
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
cin >> c[i][j];
}
}
vector<int> result;
int sum;
for(int i = 0; i < n; i++) {
sum = 0;
for(int j = 0; j < n; j++) {
sum+=c[i][j];
}
result.push_back(sum);
}
for(int j = 0; j < n; j++) {
sum = 0;
for(int i = 0; i < n; i++) {
sum+=c[i][j];
}
result.push_back(sum);
}
sum = 0;
for(int i = 0; i < n; i++) {
sum+=c[i][i];
}
result.push_back(sum);
sum = 0;
for(int i = 0; i < n; i++) {
sum+=c[i][n - i - 1];
}
result.push_back(sum);
sort(result.begin(), result.end(), cmp);
for(int i = 0; i < result.size(); i++) {
cout << result[i];
if(i != result.size() - 1) cout << " ";
else cout << endl;
}
}
return 0;
}
坑点在于题目中说共有一组数据但其实有多组输入Σ( ° △ °|||)
6.问题 F: 小白鼠排队
//小白鼠排队
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
int n;
while(cin >> n) {
map<int, string> mouse;
for(int i = 0; i < n; i++) {
int weight;
string color;
cin >> weight >> color;
mouse.insert(pair<int, string>(weight, color));
}
map<int, string>::reverse_iterator iter;
for(iter = mouse.rbegin(); iter != mouse.rend(); iter++) {
cout << iter->second << endl;
}
}
return 0;
}
7.问题 G: 中位数
//中位数
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
int n;
while(cin >> n && n != 0) {
vector<int> array;
for(int i = 0; i < n; i++) {
int a;
cin >> a;
array.push_back(a);
}
sort(array.begin(), array.end());
if(n % 2 == 0) {
cout << (array[n / 2 - 1] + array[n / 2]) / 2 << endl;
} else {
cout << array[n / 2] << endl;
}
}
return 0;
}
8.问题 H: 整数奇偶排序
//整数奇偶排序
#include <iostream>
#include <algorithm>
using namespace std;
bool cmp(int a, int b) {
return a > b;
}
int main() {
int a[10];
while(cin>>a[0]>>a[1]>>a[2]>>a[3]>>a[4]>>a[5]>>a[6]>>a[7]>>a[8]>>a[9]) {
sort(a, a + 10, cmp);
for(int i = 0; i < 10; i++) {
if(a[i] % 2 != 0) cout << a[i] << " ";
}
sort(a, a + 10);
bool flag = true;
for(int i = 0; i < 10; i++) {
if(a[i] % 2 == 0) {
if(flag) flag = false;
else cout << " ";
cout << a[i];
}
}
cout << endl;
}
return 0;
}
9.问题 I: 排名
//排名
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
struct Student {
char id[21];
int score;
};
bool cmp(Student a, Student b) {
if(a.score != b.score) return a.score > b.score;
else return strcmp(a.id, b.id) < 0;
}
int main() {
int n, m, g;
while(cin >> n && n != 0) {
cin >> m >> g;
struct Student s[n];
int questions[m];
for(int i = 0; i < m; i++) {
cin >> questions[i];
}
for(int i = 0; i < n; i++) {
cin >> s[i].id;
int num, sum = 0;
cin >> num;
for(int j = 0; j < num; j++) {
int problem;
cin >> problem;
sum += questions[problem - 1];
}
s[i].score = sum;
}
sort(s, s + n, cmp);
int num = 0;
for(int i = 0; i < n; i++) {
if(s[i].score >= g) num++;
else break;
}
cout << num << endl;
for(int i = 0; i < num; i++) {
cout << s[i].id << " " << s[i].score << endl;
}
}
return 0;
}
总结
虽然书中讲到了冒泡,选择,插入这三种排序方法,但是实际做题是一般都是用的sort()函数来进行排序。STL sort 函数实现详解
STL中的sort并非只是普通的快速排序,除了对普通的快速排序进行优化,它还结合了插入排序和堆排序。根据不同的数量级别以及不同情况,能自动选用合适的排序方法。当数据量较大时采用快速排序,分段递归。一旦分段后的数据量小于某个阀值,为避免递归调用带来过大的额外负荷,便会改用插入排序。而如果递归层次过深,有出现最坏情况的倾向,还会改用堆排序。