内容:1、简单的选择排序;
2、使用模板(泛型)使算法更加灵活;
3、使用结构体完成学生的name和score属性的排序;
4、随机生成算法测试用例。
写在前面:为什么学习O(n^2)的排序算法?
基础
- 编码简单,易于实现,是一些简单场景的首选
- 在一些特殊情况下,,简单的排序算法更有效
- 简单的排序算法思想可衍生出复杂的排序算法
- 作为子过程,改进更复杂的排序算法
1、Selection Sort 选择排序
基本思路
如:8 6 2 3 1 5 7 4
对一个序列A中的元素A[1]~A[n],令i从1到n的枚举,进行n趟操作,每趟从排序部分[i,n]中选择最小的元素,令其与待排序部分的第一个元素A[i]进行交换,直到排序完成。
示例:
[1,8]中1最小(1,8交换)——>1 6 2 3 8 5 7 4
[2,8]中2最小(2,6交换)——>1 2 6 3 8 5 7 4
[3,8]中3最小(3,6交换)——>1 2 3 6 8 5 7 4
[4,8]中4最小(4,6交换)——>1 2 3 4 8 5 7 6
[5,8]中5最小(5,8交换)——>1 2 3 4 5 8 7 6
[6,8]中6最小(6,8交换)——>1 2 3 4 5 6 7 8
[7,8]中6最小(7,8不换)——>1 2 3 4 5 6 7 8
排序完成
代码块1:
void selectionSort(int A[],int n)
{
for(int i=0;i<n;i++)
//寻找[i,n)区间里的最小值
{
int minIndex=i;
for(int j=i+1;j<n;j++)
if(A[j]<A[minIndex])
minIndex=j;
swap(A[i],A[minIndex]);//C++标准库内置函数,头文件为algorithm
}
}
2、使用模板(泛型)编写算法
添加模板template<typename T>,即可定义T类型数组。如:
void selectionSort(T A[],int n);//T代替了之前的int型
这样我们就可以使用更多类型的数组,使排序更加多样化。如:
代码块2:
int a[10]={2,3,5,7,6,1,4,9,8,10};
selectionSort(a,10);
for(int i=0;i<10;i++)
cout<<a[i]<<" ";
cout<<endl;
float b[4]={2.1,3.2,1.8,4.9};
selectionSort(b,4);
for(int i=0;i<4;i++)
cout<<b[i]<<" ";
cout<<endl;
string c[4]={"B","D","C","A"};
selectionSort(c,4);
for(int i=0;i<4;i++)
cout<<c[i]<<" ";
cout<<endl;
运行结果:
以上,我使用int、float和string三种类型完成对应类型的排序工作,但我只调用了一种函数。这就是模板(泛型)带来的好处,可以引用不同类型的数据类型,使自己的算法更加灵活多变。
3、使用头文件定义Student结构体,实现学生分数排序。
student.h
#pragma once
#ifndef SELECTIONSORT_STUDENT_H
#define SELECTIONSORT_STUDENT_H
#include<iostream>
#include<string>
using namespace std;
struct Student {//结构体的定义
string name;//定义名字
int score;//定义成绩
bool operator<(const Student &otherStudent){//方法的重载
return score < otherStudent.score;
}
friend ostream& operator<<(ostream &os, const Student &Student) {
os << "Student:"<< Student.name << " "<<Student.score<< endl;
return os;
}
};
#endif // !SELECTIONSORT_STUDENT_H
注:引用头文件——>#include"student.h" 注意,自己声明的头文件使用"",而不是<>。
代码块4:
Student d[4] = { {"D",80},{"A",70},{ "C",60 },{ "B",80 } };
selectionSort(d, 4);
for (int i = 0; i<4; i++)
cout << d[i];
cout << endl;
运行结果:
思考:学生D和学生B成绩一样,是按照什么顺序排列的呢?怎么排列使它更加合理化呢?
学生D和学生B是按照原先数组给定的顺序排列的;如果使排序更加合理化,我们可以将学生的姓名进行一次排序,类似于我们平时的 姓名首字母排序。
如何实现name属性排序呢?
我们在使用方法判断score大小时,可以利用条件运算符(三目运算符)实现name大小比较。即:
return score != otherStudent.score ? score < otherStudent.score : name < otherStudent.name;
是否相等——>不相等比较成绩
——>相等则比较姓名
代码块5:
return score != otherStudent.score ? score < otherStudent.score : name < otherStudent.name;
运行结果:
学生B的字母是排在学生D的字母前面的。
由此可见,自定义比较的威力是非常强大的,要学会自己定义,深入思考算法精髓,使自己的编程更加个性化,而不是仅仅局限于现成的代码和算法,甘心做个代码打印机。
4、随机生成算法测试用例
后面在比较不同排序算法效率的时候,可能会用到一万、十万、百万这种量级的数组,对于这种数组,不能手动生成。为此写一个新的方法生成随机数组,以及其他测试相关的辅助方法。