零.【摘要】在这个专刊里,我会把所有算法都讲一遍,这章讲了个种排序大全和题目。
一.【简介】排序在生活很常见,如:考试成绩排序,身高排序……排序无处不在。这章我会讲如和在C++中进行排序。
二.【排序算法大全】:
1.
冒泡排序(Bubble Sort):比较相邻的元素,如果顺序错误则交换它们,重复进行直到没有需要交换的元素。时间复杂度为O(n^2)。
- 示例:
#include <iostream> using namespace std; void bubbleSort(int arr[], int n) { for (int i = 0; i < n-1; i++) { for (int j = 0; j < n-i-1; j++) { if (arr[j] > arr[j+1]) { swap(arr[j], arr[j+1]); } } } } int main() { int arr[] = {64, 34, 25, 12, 22, 11, 90}; int n = sizeof(arr) / sizeof(arr[0]); bubbleSort(arr, n); for (int i = 0; i < n; i++) { cout << arr[i] << " "; } cout << endl; return 0; }
选择排序(Selection Sort):依次选择未排序元素中的最小值,将其放在已排序序列的末尾。时间复杂度为O(n^2)。
- 示例:
#include <iostream> using namespace std; void selectionSort(int arr[], int n) { for (int i = 0; i < n-1; i++) { int minIdx = i; for (int j = i+1; j < n; j++) { if (arr[j] < arr[minIdx]) { minIdx = j; } } swap(arr[i], arr[minIdx]); } } int main() { int arr[] = {64, 34, 25, 12, 22, 11, 90}; int n = sizeof(arr) / sizeof(arr[0]); selectionSort(arr, n); for (int i = 0; i < n; i++) { cout << arr[i] << " "; } cout << endl; return 0; } 插入排序(Insertion Sort):将未排序元素逐个插入到已排序序列的适当位置。时间复杂度为O(n^2)。 示例: #include <iostream> using namespace std; void insertionSort(int arr[], int n) { for (int i = 1; i < n; i++) { int key = arr[i]; int j = i - 1; while (j >= 0 && arr[j] > key) { arr[j+1] = arr[j]; j--; } arr[j+1] = key; } } int main() { int arr[] = {64, 34, 25, 12, 22, 11, 90}; int n = sizeof(arr) / sizeof(arr[0]); insertionSort(arr, n); for (int i = 0; i < n; i++) { cout << arr[i] << " "; } cout << endl; return 0; }
快速排序(Quick Sort):选择一个基准元素,将比基准小的元素放在其左边,将比基准大的元素放在其右边,然后分别递归对左右两个子序列进行快速排序。时间复杂度为O(nlogn)。
- 示例:
#include <iostream> using namespace std; int partition(int arr[], int low, int high) { int pivot = arr[high]; int i = low - 1; for (int j = low; j < high; j++) { if (arr[j] < pivot) { i++; swap(arr[i], arr[j]); } } swap(arr[i+1], arr[high]); return i+1; } void quickSort(int arr[], int low, int high) { if (low < high) { int pi = partition(arr, low, high); quickSort(arr, low, pi-1); quickSort(arr, pi+1, high); } } int main() { int arr[] = {64, 34, 25, 12, 22, 11, 90}; int n = sizeof(arr) / sizeof(arr[0]); quickSort(arr, 0, n-1); for (int i = 0; i < n; i++) { cout << arr[i] << " "; } cout<<endl; return 0; }
归并排序(Merge Sort):将数组拆分为两个子数组进行排序,然后将两个排序好的子数组合并成一个有序数组。时间复杂度为O(nlogn)。
- 示例:
#include <iostream> using namespace std; void merge(int arr[], int left, int mid, int right) { int n1 = mid - left + 1; int n2 = right - mid; int L[n1], R[n2]; for (int i = 0; i < n1; i++) { L[i] = arr[left + i]; } for (int j = 0; j < n2; j++) { R[j] = arr[mid + 1 + j]; } int i = 0, j = 0, k = left; while (i < n1 && j < n2) { if (L[i] <= R[j]) { arr[k] = L[i]; i++; } else { arr[k] = R[j]; j++; } k++; } while (i < n1) { arr[k] = L[i]; i++; k++; } while (j < n2) { arr[k] = R[j]; j++; k++; } } void mergeSort(int arr[], int left, int right) { if (left < right) { int mid = left + (right - left) / 2; mergeSort(arr, left, mid); mergeSort(arr, mid + 1, right); merge(arr, left, mid, right); } } int main() { int arr[] = {64, 34, 25, 12, 22, 11, 90}; int n = sizeof(arr) / sizeof(arr[0]); mergeSort(arr, 0, n-1); for (int i = 0; i < n; i++) { cout << arr[i] << " "; } cout << endl; return 0; }
堆排序(Heap Sort):将数组构建为最大堆,然后将堆顶元素与最后一个元素交换,再将剩余元素重新构建为最大堆,重复进行直到所有元素有序。时间复杂度为O(nlogn)。
- 示例:
#include <iostream> using namespace std; void heapify(int arr[], int n, int i) { int largest = i; int left = 2 * i + 1; int right = 2 * i + 2; if (left < n && arr[left] > arr[largest]) { largest = left; } if (right < n && arr[right] > arr[largest]) { largest = right; } if (largest != i) { swap(arr[i], arr[largest]); heapify(arr, n, largest); } } void heapSort(int arr[], int n) { for (int i = n / 2 - 1; i >= 0; i--) { heapify(arr, n, i); } for (int i = n - 1; i > 0; i--) { swap(arr[0], arr[i]); heapify(arr, i, 0); } } int main() { int arr[] = {64, 34, 25, 12, 22, 11, 90}; int n = sizeof(arr) / sizeof(arr[0]); heapSort(arr, n); for (int i = 0; i < n; i++) { cout << arr[i] << " "; } cout << endl; return 0; }
计数排序(Counting Sort):统计数组中每个元素的出现次数,然后根据统计结果重新排列元素。时间复杂度为O(n+k),其中k是待排序元素的取值范围。
- 示例:
#include <iostream> using namespace std; void countingSort(int arr[], int n, int k) { int output[n]; int count[k+1] = {0}; for (int i = 0; i < n; i++) { count[arr[i]]++; } for (int i = 1; i <= k; i++) { count[i] += count[i-1]; } for (int i = n-1; i >= 0; i--) { output[count[arr[i]]-1] = arr[i]; count[arr[i]]--; } for (int i = 0; i < n; i++) { arr[i] = output[i]; } } int main() { int arr[] = {4, 2, 2, 8, 3, 3, 1}; int n = sizeof(arr) / sizeof(arr[0]); int k = 8; countingSort(arr, n, k); for (int i = 0; i < n; i++) { cout << arr[i] << " "; } cout << endl; return 0; }
桶排序(Bucket Sort):将元素根据值的范围划分到不同的桶中,对每个桶中的元素进行排序,然后合并所有桶中的元素。时间复杂度为平均情况下O(n+k),其中k是桶的数量。
- 示例:
#include <iostream> #include <vector> #include <algorithm> using namespace std; void bucketSort(float arr[], int n) { vector<float> buckets[n]; for (int i = 0; i < n; i++) { int index = n * arr[i]; buckets[index].push_back(arr[i]); } for (int i = 0; i < n; i++) { sort(buckets[i].begin(), buckets[i].end()); } int index = 0; for (int i = 0; i < n; i++) { for (int j = 0; j < buckets[i].size(); j++) { arr[index++] = buckets[i][j]; } } } int main() { float arr[] = {0.8, 0.2, 0.5, 0.1, 0.9, 0.3}; int n = sizeof(arr) / sizeof(arr[0]); bucketSort(arr, n); for (int i = 0; i < n; i++) { cout << arr[i] << " "; } cout << endl; return 0; }
基数排序(Radix Sort):按照数字的每一位进行排序,将所有元素分配到不同的桶中,重复该过程直到所有位都被处理。时间复杂度为O(kn),其中k是数字的最大位数。
- 示例:
#include <iostream> using namespace std; int getMax(int arr[], int n) { int mx = arr[0]; for (int i = 1; i < n; i++) { if (arr[i] > mx) { mx = arr[i]; } } return mx; } void countingSort(int arr[], int n, int exp) { int output[n]; int count[10] = {0}; for (int i = 0; i < n; i++) { count[(arr[i] / exp) % 10]++; } for (int i = 1; i < 10; i++) { count[i] += count[i-1]; } for (int i = n-1; i >= 0; i--) { output[count[(arr[i] / exp) % 10] - 1] = arr[i]; count[(arr[i] / exp) % 10]--; } for (int i = 0; i < n; i++) { arr[i] = output[i]; } } void radixSort(int arr[], int n) { int max = getMax(arr, n); for (int exp = 1; max / exp > 0; exp *= 10) { countingSort(arr, n, exp); } } int main() { int arr[] = {170, 45, 75, 90, 802, 24, 2, 66}; int n = sizeof(arr) / sizeof(arr[0]); radixSort(arr, n); for (int i = 0; i < n; i++) { cout << arr[i] << " "; } cout << endl; return 0; }
希尔排序(Shell Sort):将数组分割为多个子序列,对每个子序列进行插入排序,逐步减小子序列的间隔直到为1。时间复杂度取决于间隔序列的选择。
- 示例:
#include <iostream> using namespace std; void shellSort(int arr[], int n) { for (int gap = n/2; gap > 0; gap /= 2) { for (int i = gap; i < n; i++) { int temp = arr[i]; int j; for (j = i; j >= gap && arr[j-gap] > temp; j -= gap) { arr[j] = arr[j-gap]; } arr[j] = temp; } } } int main() { int arr[] = {64, 34, 25, 12, 22, 11, 90}; int n = sizeof(arr) / sizeof(arr[0]); shellSort(arr, n); for (int i = 0; i < n; i++) { cout << arr[i] << " "; } cout << endl; return 0; }
以上是几种常见的排序算法,每个算法都有其自己的特点和适用场景。根据需要选择合适的排序算法以获得更高效的排序结果。
三.【题目讲解】:
1:成绩排序
时间限制: 1000 ms 内存限制: 65536 KB
提交数: 65296 通过数: 27178
【题目描述】
给出班里某门课程的成绩单,请你按成绩从高到低对成绩单排序输出,如果有相同分数则名字字典序小的在前。
【输入】
第一行为n (0 < n < 20),表示班里的学生数目;
接下来的n行,每行为每个学生的名字和他的成绩, 中间用单个空格隔开。名字只包含字母且长度不超过20,成绩为一个不大于100的非负整数。
【输出】
把成绩单按分数从高到低的顺序进行排序并输出,每行包含名字和分数两项,之间有一个空格。
【输入样例】
4
Kitty 80
Hanmeimei 90
Joey 92
Tim 28
【输出样例】
Joey 92
Hanmeimei 90
Kitty 80
Tim 28
【题目讲解】题目可以通过创建一个包含学生信息的结构体数组,可以使用冒泡排序算法进行排序。冒泡排序的基本思想是从数组的第一个元素开始,比较相邻的两个元素,如果前面的元素大于后面的元素,则交换它们的位置。重复这个过程,直到整个数组按照指定的顺序排序。
首先,在 struct Student
中定义了一个结构体,用来存储学生的姓名和成绩。
struct Student {
string name;
int grade;
};
然后,使用冒泡排序算法对学生成绩进行排序的 bubbleSort
函数。
void bubbleSort(vector<Student>& students) {
int n = students.size();
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (students[j].grade < students[j + 1].grade ||
(students[j].grade == students[j + 1].grade && students[j].name > students[j + 1].name)) {
// 交换位置
swap(students[j], students[j + 1]);
}
}
}
}
在 main
函数中,首先读取学生的数目 n
,然后创建一个存储学生信息的向量 students
。接下来,使用循环逐个读取每个学生的姓名和成绩,并将其存储在 students
向量中。
int main() {
int n;
cin >> n; // 输入学生数目
vector<Student> students(n);
for (int i = 0; i < n; i++) {
cin >> students[i].name >> students[i].grade; // 输入学生姓名和成绩
}
最后,调用 bubbleSort
函数对学生成绩进行排序,并依次输出排序后的成绩单。
bubbleSort(students); // 使用冒泡排序对成绩单进行排序
for (int i = 0; i < n; i++) {
cout << students[i].name << " " << students[i].grade << endl; // 输出排序后的成绩单
}
return 0;
}
【完整代码】:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
// 定义学生结构体
struct Student {
string name;
int grade;
};
// 冒泡排序函数
void bubbleSort(vector<Student>& students) {
int n = students.size();
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (students[j].grade < students[j + 1].grade ||
(students[j].grade == students[j + 1].grade && students[j].name > students[j + 1].name)) {
// 交换位置
swap(students[j], students[j + 1]);
}
}
}
}
int main() {
int n;
cin >> n; // 输入学生数目
vector<Student> students(n);
for (int i = 0; i < n; i++) {
cin >> students[i].name >> students[i].grade; // 输入学生姓名和成绩
}
bubbleSort(students); // 使用冒泡排序对成绩单进行排序
for (int i = 0; i < n; i++) {
cout << students[i].name << " " << students[i].grade << endl; // 输出排序后的成绩单
}
return 0;
}
整个程序的主要思路是通过冒泡排序算法对学生成绩进行排序,当成绩相同时,按照姓名的字典序进行排序。最后输出排序后的成绩单。
【优化代码】:我们可以优化代码,这就要用到sort函数。
【格式】:sort(开始位置,结束位置,排序方式);默认排序方式是从小到大排;
以下是使用 sort
函数对 N 个数进行从大到小排序的示例代码:
#include<iostream>
#include<algorithm>
using namespace std;
int a[10010],n;
bool cmp(int a,int b){
return a>b;
}//排序方式:从大到小
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+1+n,cmp);//直接调用sort函数
for(int i=1;i<=n;i++) cout<<a[i]<<" ";
return 0;
}
【优化答案】:
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
using namespace std;
struct Student {
string name;
int score;
};
bool compare(Student a, Student b) {
if (a.score != b.score) {
return a.score > b.score;
} else {
return a.name < b.name;
}
}
int main() {
int n;
cin >> n;
vector<Student> students(n);
for (int i = 0; i < n; i++) {
cin >> students[i].name >> students[i].score;
}
sort(students.begin(), students.end(), compare);
for (int i = 0; i < n; i++) {
cout << students[i].name << " " << students[i].score << endl;
}
return 0;
}
2:合影效果
时间限制: 1000 ms 内存限制: 65536 KB
提交数: 29292 通过数: 16873
【题目描述】
小云和朋友们去爬香山,为美丽的景色所陶醉,想合影留念。如果他们站成一排,男生全部在左(从拍照者的角度),并按照从矮到高的顺序从左到右排,女生全部在右,并按照从高到矮的顺序从左到右排,请问他们合影的效果是什么样的(所有人的身高都不同)?
【输入】
第一行是人数n�(2≤n≤402≤�≤40,且至少有11个男生和11个女生)。
后面紧跟n�行,每行输入一个人的性别(男male
或女female
)和身高(浮点数,单位米),两个数据之间以空格分隔。
【输出】
n�个浮点数,模拟站好队后,拍照者眼中从左到右每个人的身高。每个浮点数需保留到小数点后22位,相邻两个数之间用单个空格隔开。
【输入样例】
6
male 1.72
male 1.78
female 1.61
male 1.65
female 1.70
female 1.56
【输出样例】
1.65 1.72 1.78 1.70 1.61 1.56
题目讲解:题目要求将男生按照矮到高的顺序从左到右排列,女生按照高到矮的顺序从左到右排列,然后输出站好队后每个人的身高。我们使用结构体 Person
存储每个人的性别和身高。然后定义了自定义的比较函数 compare
,按照题目要求对人员排序。在排序后,我们使用 cout
输出每个人的身高,并使用 fixed
和 setprecision
设定输出格式以保留两位小数。最后输出换行符 endl
。注意,题目要求禁止使用动态数组,因此我们使用了静态数组 people
。
#include <iostream>
#include <algorithm>
#include <iomanip>
using namespace std;
struct Person {
string gender;
double height;
};
// 自定义比较函数,按照题目要求排序
bool compare(Person a, Person b) {
if (a.gender == "male" && b.gender == "female") {
return true; // 男生在女生前面
} else if (a.gender == "female" && b.gender == "male") {
return false; // 女生在男生后面
} else {
if (a.gender == "male") {
return a.height < b.height; // 男生按照矮到高排序
} else {
return a.height > b.height; // 女生按照高到矮排序
}
}
}
int main() {
int n;
cin >> n;
Person people[n];
for (int i = 0; i < n; i++) {
cin >> people[i].gender >> people[i].height;
}
// 使用自定义的比较函数进行排序
sort(people, people + n, compare);
// 输出排序后的结果
for (int i = 0; i < n; i++) {
// 保留两位小数
cout << fixed << setprecision(2) << people[i].height << " ";
}
cout << endl;
return 0;
}
3:分数线划定
时间限制: 1000 ms 内存限制: 65536 KB
提交数: 35162 通过数: 16713
【题目描述】
世博会志愿者的选拔工作正在 A 市如火如荼的进行。为了选拔最合适的人才,A市对所有报名的选手进行了笔试,笔试分数达到面试分数线的选手方可进入面试。面试分数线根据计划录取人数的150%150%划定,即如果计划录取m�名志愿者,则面试分数线为排名第m×150%�×150%(向下取整)名的选手的分数,而最终进入面试的选手为笔试成绩不低于面试分数线的所有选手。
现在就请你编写程序划定面试分数线,并输出所有进入面试的选手的报名号和笔试成绩。
【输入】
第一行,两个整数n,m(5≤n≤5000,3≤m≤n)�,�(5≤�≤5000,3≤�≤�),中间用一个空格隔开,其中n� 表示报名参加笔试的选手总数,m� 表示计划录取的志愿者人数。输入数据保证m×150%�×150%向下取整后小于等于n�。
第二行到第 n+1�+1 行,每行包括两个整数,中间用一个空格隔开,分别是选手的报名号k(1000≤k≤9999)�(1000≤�≤9999)和该选手的笔试成绩s(1≤s≤100)�(1≤�≤100)。数据保证选手的报名号各不相同。
【输出】
第一行,有两个整数,用一个空格隔开,第一个整数表示面试分数线;第二个整数为进入面试的选手的实际人数。
从第二行开始,每行包含两个整数,中间用一个空格隔开,分别表示进入面试的选手的报名号和笔试成绩,按照笔试成绩从高到低输出,如果成绩相同,则按报名号由小到大的顺序输出。
【输入样例】
6 3
1000 90
3239 88
2390 95
7231 84
1005 95
1001 88
【输出样例】
88 5
1005 95
2390 95
1000 90
1001 88
3239 88
【提示】
样例说明:m×150%=3×150%=4.5�×150%=3×150%=4.5,向下取整后为44。保证44个人进入面试的分数线为8888,但因为8888有重分,所以所有成绩大于等于8888的选手都可以进入面试,故最终有55个人进入面试。
【题目讲解】这道题要求根据计划录取的志愿者人数,计算出面试分数线,并输出所有进入面试的选手的报名号和笔试成绩。我们定义了一个结构体 Candidate
存储每个选手的报名号和笔试成绩。然后定义了自定义的比较函数 compare
,按照题目要求对选手排序。在排序后,我们可以根据计划录取的志愿者人数,计算出面试分数线,并遍历所有选手,统计实际进入面试的人数。最后,输出面试分数线和实际进入面试的人数,并分别输出进入面试的选手的报名号和成绩。注意,题目要求面试分数线向下取整,因此计算时需要使用 m * 150 / 100 - 1
。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
struct Candidate {
int id;
int score;
};
bool compare(Candidate a, Candidate b) {
if (a.score != b.score) {
return a.score > b.score; // 按照成绩从高到低排序
} else {
return a.id < b.id; // 成绩相同则按照报名号从小到大排序
}
}
int main() {
int n, m;
cin >> n >> m;
vector<Candidate> candidates(n);
for (int i = 0; i < n; i++) {
cin >> candidates[i].id >> candidates[i].score;
}
// 对选手按照成绩从高到低排序
sort(candidates.begin(), candidates.end(), compare);
// 计算面试分数线
int interviewScore = candidates[m * 150 / 100 - 1].score;
// 计算实际进入面试的人数
int interviewCount = 0;
for (int i = 0; i < n; i++) {
if (candidates[i].score >= interviewScore) {
interviewCount++;
}
}
// 输出面试分数线和实际进入面试的人数
cout << interviewScore << " " << interviewCount << endl;
// 分别输出进入面试的选手的报名号和成绩
for (int i = 0; i < n; i++) {
if (candidates[i].score >= interviewScore) {
cout << candidates[i].id << " " << candidates[i].score << endl;
}
}
return 0;
}
创作不易,点个👍,观个注吧。