(一)选择排序
选择排序:在每次循环中找出最小的元素,将其移至开头,第二次找出次小元素,将其移至第二位,以此类推
算法复杂度:O(n*n)
//泛型函数模板
template<typename T>
void selectionSort(T arr[],int n){//分别存放待排序的数组、数组元素个数
for(int i=0;i<n;i++){
int minIndex=i; //用来存放最小元素下标
for(int j=i+1;j<n;j++){
if(arr[j]<arr[minIndex]){
minIndex=j;
}
swap(arr[i],arr[minIndex]);
}
}
}
选择排序易于理解,但是缺点也十分明显,每次必须完整遍历整个数组,才能找出最小元素,因此,这种排序方法是低效的,与之算法复杂度相同的,还有另一种排序方式:插入排序。
(二)插入排序
插入排序:将每个元素依次插入到数组中正确的位置(类似整理扑克牌)
算法复杂度:O(n*n)
template<typename T>
void insertionSort(T arr[],int n){
//默认第一个元素已经有序
for(int i=1;i<n;i++){
//从第i个元素的前一位开始比较
for(int j=i-1;j>0;j--){
if(arr[j]<arr[j-1])
swap(arr[j],arr[j-1]);
else
break;
}
}
}
也可以将代码结构简化,把if判断语句移动到第二个循环判断内部:
void insertionSort(T arr[],int n){
//默认第一个元素已经有序
for(int i=1;i<n;i++){
//从第i个元素的前一位开始比较
for(int j=i-1;j>0&&arr[j]<arr[j-1];j--){
swap(arr[j],arr[j-1]);
}
}
}
插入排序的优点在于:如果找到了合适的插入位置,可以提前终止循环,因此,在数据量近乎有序的情况下,反而比一些算法复杂度为O(nlogN)的算法更为高效。
但这里调用的是系统中提供的swap()函数,本质上是三次赋值的交换,还可以做进一步修改,使得算法更为高效:
其核心思想是:将要寻找合适插入位置的第i个元素临时保存,再判断其放在当前位置是否合适,跟前一个位置的元素进行比较,如果前一个位置的元素大于该位置的元素,直接让前一个位置的元素值覆盖当前位置的元素,以此类推,直到该元素找到了合适的位置并将该位置原有的元素覆盖
void insertionSort(T arr[].int n){
//用变量e保存数组第i个元素
for(int i=1;i<n;i++){
T e=arr[i];
int j;
for(j=i;j>0&&arr[j-1]>e;j--){
arr[j]=arr[j-1];
}
//找到合适的位置,满足:
//该位置的元素不再大于e的值
//此时的j即为合适的位置
arr[j]=e;
}
}
注:本文的内容来自慕课网的课程《c++,java算法与数据结构》,主讲人为刘宇波老师~极力推荐!
这里附上课程链接:http://coding.imooc.com/class/71.html