总结一下常见的排序算法,包括插入排序,冒泡排序,快速排序,
1.直接插入排序
整个序列分为有序区和无序区,取第一个元素作为初始有序区,然后第二个开始,依次插入到有序区的合适位置,直到排好序。
下面是具体代码实现:
void InsertSort2(vector<int> &num){
for(int i = 1;i < num.size();++i){
for(int j = i;j > 0;--j){
if(num[j] < num[j - 1]){
int temp = num[j];
num[j] = num[j-1];
num[j-1] = temp;
}
}
}
}
插入排序的时间复杂度最好的情况是已经是正序的序列,只需比较(n-1)次,时间复杂度为O(n),最坏的情况是倒序的序列,要比较n(n-1)/2次,时间复杂度为O(n^2 ) ,平均的话要比较时间复杂度为O(n^2 )。
插入排序是一种稳定的排序方法,排序元素比较少的时候很好,大量元素便会效率低下。
2.冒泡排序
比较相邻的元素,如果反序则交换,过程也是分为有序区和无序区,初始时有序区为空,所有元素都在无序区,经过第一趟后就能找出最大的元素,然后重复便可。
冒泡排序感觉非常好理解,第一个for循环是遍历所有元素,第二个for循环是每次遍历元素时都对无序区的相邻两个元素进行一次比较,若反序则交换。
时间复杂度最坏的情况是反序序列,要比较n(n-1)/2次,时间复杂度为O(n^2 ),最好的情况是正序,只进行(n-1)次比较,不需要移动,时间复杂度为O(n),而平均的时间复杂度为O(n^2 )。
但是还有更好的方法,如果第一次比较完没有交换即说明已经有序,不应该进行下一次遍历。
还有已经遍历出部分有序的序列后,那部分也不用进行遍历,即发生交换的地方之后的地方不用遍历。
void BubbleSort(int arr[], int len){
int i,temp;
//记录位置,当前所在位置和最后发生交换的地方
int current,last = len - 1;
while(last > 0) {
for(i = current = 0;i < last;++i){
if(arr[i] > arr[i+1]){
temp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp;
//记录当前的位置,如果没有发生交换current值即for循环初始化的0
current = i;
}
}
//若current = 0即已经没有可以交换的元素了,即已经有序了
last = current;
}
}
冒泡排序也是一种稳定的排序算法,也是元素较少时效率比较高。
3.快速排序
快速排序首先选一个轴值(pivot,也有叫基准的),将待排序记录划分成独立的两部分,左侧的元素均小于轴值,右侧的元素均大于或等于轴值,然后对这两部分再重复,直到整个序列有序。过程是和二叉搜索树相似,就是一个递归的过程。
//快速排序;
#include<iostream>
#include<algorithm>
using namespace std;
void Quick_sort(int a[],int left,int right) //快速排序;
{
if(left > right) return;
int i = left,j = right;
int base = a[left]; //记录基准数;
while(i != j)
{
while(i < j && a[j] >= base) //先从基准数的对面开始找;
j--;
while(i < j && a[i] <= base) //再从另一边找;
i++;
if(i < j) //在i和j未相遇时;
swap(a[i],a[j]); //交换两个数;
}
swap(a[left],a[i]); //将基准数归位;
Quick_sort(a,left,i-1); //处理左区间;
Quick_sort(a,i+1,right); //处理右区间;
}
这个图不是一般的棒!!来自Wikipedia。
快速排序时间复杂度的最好情况和平均情况一样为O(nlog2 n),最坏情况下为O(n^2 ),这个看起来比前面两种排序都要好,但是这是不稳定的算法,并且空间复杂度高一点( O(nlog2 n))。而且快速排序适用于元素多的情况。
未完待续...