算法初步——排序
简单选择排序
- 令i从0到n-1枚举,进行n趟操作,每趟从A[i,n]中选择最小的元素 ,算法复杂度为O(n^2)
/* 选择排序 思路:令i从0到n-1枚举,进行n趟操作,每趟从A[i,n]中选择最小的元素 */ void selectSort(int A[], int n) { for(int i=0; i<n; ++i) { int k = i; // 记录最小元素 for(int j=i+1; j<n; ++j) { // 从A[i,n]中选择最小的元素 if(a[j] < a[k]) k = j; } int temp = a[i]; // 交换 a[i] = a[k]; a[k] = temp; } }
直接插入排序
-
假设某一趟时,序列A的前i-1个元素A[1]~A[i-1]已经有序,然后从范围[1,i-1]中寻找某个位置j ,使得插入后仍然有序,算法复杂度为O(n^2)
/* 直接插入排序 思路: 假设某一趟时,序列A的前i-1个元素A[1]~A[i-1]已经有序, 然后从范围[1,i-1]中寻找某个位置j ,使得插入后仍然有序 */ void insertSort(int A[], int n) { for(int i=1; i<n; ++i) { // 进行n-1趟排序 int temp=A[i], j=i; // 从前往后遍历 while(j>0 && temp<A[j-1]) { A[j] = A[j-1]; // 后移 j--; } A[j] = temp; } }
sort函数的应用
- 使用时必须加上头文件 #include <algorithm> 和 using namespace std;
-
函数原型
// sort(首元素的地址(必填),尾元素地址的下一个地址,比较函数(非必填)) sort(a, a+6);
- 如何实现比较函数cmp
- 若比较函数不填,则默认按照从小到大的顺序排序,如果想要从大到小来排序,则要使用比较函数cmp
bool cmp(int a, int b) { return a > b; // 可以理解为当 a > b 时把 a 放前面 }
- 结构体数组的排序
- 一级排序,按照 x 从大到小排序
struct node { // 结构体定义 int x, y; } ssd[10]; bool cmp(node a, node b) { // 一级排序 // 将ssd数组按照x从大到小排序 return a.x > b.x; }
- 二级排序,先按照 x 从大到小排序,但当 x 相等的情况下,按照 y 的大小来排序
bool cmp(node a, node b) { // 二级排序 // 将ssd数组先按照 x 从大到小排序, // 但当 x 相等的情况下,按照 y 的大小来排序 if(a.x != b.x) return a.x > b.x; else return a.y > b.y; }
- 一级排序,按照 x 从大到小排序
- 容器的排序
- 在 STL 标准容器中,只有 vector、string、deque 是可以使用 sort 的。这是因为 set、map 这种容器是用红黑树实现的,元素本身有序
- vector 的排序: sort(vi.begin(), vi.end()); // 对 vi 进行排序
-
string 的排序: sort(str, str+3); // 对 str 进行排序
- 实例:对学生进行排序
- 如果两个学生分数不相同,那么分数高的排在前面
- 否则,将姓名字典序小的排在前面
struct Student { char name[10]; // 姓名 char id[10]; // 准考证号 int score; // 分数 int rank; // 排名 } stu[10010]; bool cmp(Student a, Student b) { // 二级排序 if(a.score != b.score) return a.score > b.score; else return (strcmp(a.name, b.name) < 0); }
- 若比较函数不填,则默认按照从小到大的顺序排序,如果想要从大到小来排序,则要使用比较函数cmp
- 排名的实现
- 规则一般是:分数不相同的排名不同,分数相同的排名相同但占用一个排位
- 在数组排序完成后,先将数组的第一个个体(假设数组下标从0开始)的排名记为1
- 然后遍历剩余个体
- 如果当前个体的分数等于上一个个体的分数,那么当前个体的排名等于上一个个体的排名
- 否则,当前个体的排名等于数组下标加一
stu[0].rank = 1; for(int i=1; i<n; ++i) { if(stu[i].score == stu[i-1].score) { stu[i].rank = stu[i-1].rank; } else { stu[i].rank = i+1; } }
- 规则一般是:分数不相同的排名不同,分数相同的排名相同但占用一个排位
PAT A1025 PAT Ranking
- 题意:在 n 个考场有若干数量的考生。现在给出各个考场中考生的准考证号与分数,要求将所有考生按分数从高到低排序,并顺序输出所有考生的准考证号、排名、考场号、考场排名
- 思路:
- 按考场读入各考生的信息,并对当前读入的考生进行排序,将排名写入结构体中
- 对所有考生进行排序
- 按顺序一边计算总排名,一边输出所有考生的信息
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <cmath> 5 using namespace std; 6 7 struct Student { 8 char id[15]; // 准考证号 9 int score; // 分数 10 int location_number; // 考场号 11 int local_rank; // 考场排名 12 } stu[30010]; 13 14 // 定义排序方法 15 bool cmp(Student a, Student b) { 16 // 先按分数从大到小排序 17 if(a.score != b.score) return a.score > b.score; 18 else return (strcmp(a.id, b.id) < 0); // 后按准考证号排序 19 } 20 21 int main() { 22 int n, k, num=0; // n 考场数 k 考场人数 num 总人数 23 scanf("%d", &n); // 输入考场数 24 25 // 按考场输入并排名 26 for(int i=1; i<=n; ++i) { 27 scanf("%d", &k); // 输入考场人数 28 for(int j=1; j<=k; ++j) { // 输入考生信息 29 scanf("%s %d", stu[num].id, &stu[num].score); 30 stu[num].location_number = i; 31 num++; // 考生数量 +1 32 } 33 sort(stu+num-k, stu+num, cmp); // 考场排序 34 stu[num-k].local_rank = 1; // 考场内排名 35 for(int j=num-k+1; j<num; ++j) { 36 if(stu[j].score == stu[j-1].score) { 37 stu[j].local_rank = stu[j-1].local_rank; 38 } else { 39 stu[j].local_rank = j - (num-k) +1; 40 } 41 } 42 } 43 // 所有考生排名并输出信息 44 sort(stu, stu+num, cmp); 45 int rank = 1; // 记录排名 46 printf("%d\n", num); // 边计算总排名,边输出信息 47 printf("%s %d %d %d\n", stu[0].id, rank, stu[0].location_number, stu[0].local_rank); 48 for(int i=1; i<num; ++i) { 49 if(stu[i].score != stu[i-1].score) { 50 rank = i+1; 51 } 52 printf("%s %d %d %d\n", stu[i].id, rank, stu[i].location_number, stu[i].local_rank); 53 } 54 55 return 0; 56 }
qsort 函数的应用
c语言中没有预置的sort函数,如果在c语言中,要调用sort函数,就需要使用c语言自有的qsort函数,其头文件为stdlib.h。
函数原型:
1 void __cdecl qsort (void *base,size_t num,size_t width 2 ,int (__cdecl *comp)(const void *,const void*))
输入参数:
base:待排序数组
num:数组元素的个数
width:每一个元素所占存储空间的大小
comp:自定义,决定排序的顺序
以下是 qsort 的几种用法(升序排列)
1. 对一维数组排序:
1 #define ElemType double // 可以为 char、int、float、double 2 // 对一维数组排序 3 int cmp1(const void* a, const void* b) { 4 return *((ElemType*)a) > *((ElemType*)b) ? 1:-1; 5 }
2. 对字符串排序:
1 // 对字符串排序 2 int cmp2(const void* a, const void* b) { 3 return strcmp((char*)a, (char*)b); 4 }
3. 按结构体中多个关键字排序(多级排序):
1 // 对结构体排序 2 struct node { 3 double data; 4 int other; 5 } s[100]; 6 // 先按 data 从小到大排序 7 // 若 data 相等,按 other 从小到大排序 8 int cmp3(const void* a, const void* b) { 9 struct node* c = (node*)a; 10 struct node* d = (node*)b; 11 if(c->data != d->data) { 12 return (c->data > d->data) ? 1 : -1; 13 } else { 14 return c->other - d->other; 15 } 16 }