常用排序类型
冒泡排序、选择排序、桶排序、快速排序、归并排序
具体算法详解
1、选择排序
假设有一组数,共n个,存在数组a中,从第一个数a【0】开始,与后面的数依次比较,找到一个比它大(小)的数就交换,共进行n-1轮。
【例】
初始 【49 38 97 65】
第一趟后 38【49 97 65】
第二趟后 38 49【97 65】
第三趟后 38 49 65【97】
程序模板:
void selectsort(int r[]) /r数组中存储数据/
{
for(int i=1;i<=n-1;i++)
{
k=i;
for(int j=i+1;j<=n;j++)
{
if(r[j]<r[k]) k=j;
}
if(k!=i)
{
temp=r[i];
r[i]=r[k];
r[k]=temp;
}
}
}
2、冒泡排序
假设有一组数,共n个,从第一个开始,通过相邻两个数的比较,将大(小)数放前面,就第一次排序后,最小(大)的数最在最后面,每轮都从第n个数开始,共进行n-1轮。
由于排序的过程中总是大(小)数往前,小(大)数往前,相当于气泡的上升,所以称为冒泡排序。
【例】
初始 【4 5 7 1】
第一轮 :
1 【5 4】7 1
2 5【7 4】1
3 5 7【4 1】
第二轮:
1 【7 5】4 1
2 7 【5 4】1
第三轮 :
1 【7 5】4 1
程序模板:
void bubblesort(int r[]) /r数组中存储数据/
{
for(int i=1;i<=n-1;i++)
{
for(int j=1;j<=n-i;j++)
{
if(r[j]<r[j+1])
{
temp=r[i];
r[i]=r[k];
r[k]=temp;
}
}
}
}
由于有时发现排序等到一定时候,数据会已经排好,则之后就会进行多余的比较,从而增加不必要的排序时长,因此对程序进行如下改变:
void bubblesort(int r[]) /r数组中存储数据/
{
int i=1;
do
{
bo=true;
for(int j=1;j<=n-i;j++)
{
if(r[j]<r[j+1])
{
temp=r[i];
r[i]=r[k];
r[k]=temp;
bo=false;
}
i++;
}
}while(!bo);
}
3、桶排序
假设有一组数,共n个,将这n个在一定范围的数,依次存在下标为n的桶(数组)中,每个桶(数组)中可存若干个。
特点:待排数据有一定的范围。占用的空间相较前两种大,但时间上有减少(只进行了一轮循环)。
作用:①可将所有数据按顺序输出 ②可去重
程序模板:
void bucketsort(int a[],int n,int l,int r) /a数组中存储数据,n是数据范围,l、r是数据范围的左右界/
{
int k;
memset(b,0,sizeof(b)); /此语句在程序段中,则题头必包含#include<cstring>,作用为将数组中的各元素清零/
for(int i=1;i<=n;i++)
{
cin>>k;
a[i]++;
}
for(int i=l;i<=r;i++)
{
while(a[i]>0)
{
cout<<i<<" ";
a[i]--;
}
cout<<endl;
}
}
4、插入排序
假设有一组数,共n个,假设前面的m-1(m>=2)个数是有序的,则将第m个数插入到合适的位置,使得插入后,数据仍有序。
【例】
初始 【36】25 48 12
第一轮【25 36】48 12
第二轮【25 36 49】12
第三轮【12 25 36 49】
程序模板:
void insertsort(int a[]) /a数组中存储数据/
{
for(int i=l;i<=r;i++)
{
x=a[i];/x中存储a[i]的值并在后将其与前面的数比较/
j=i-1;
while(x<a[j])
{
a[j+1]=a[j];
j--;
}
a[j+1]=x;
}
}
5、快速排序
是对冒泡排序的改进,但若数据不好则效率可能与冒泡相同。假设有一组数,共n个,用变量将其分成两个部分,变量i、j分别指向1、n,将两个变量往中间挪,当在左侧和右侧分别找到比它小的比它大的数,则将两数交换,直到j<=i,则调用自身,在左右两侧分别施行这种排序。
特点:速度快、不稳定`
void quicksort(int a[],int l,int r) /a数组中存储数据l、r是数据范围的左右界/
{
int i,j,mid,temp;
i=l;
j=r;
mid=a[(l+r)/2];
do
{
while(a[i]<mid) i++;
while(a[j]>mid) j--;
if(i<=j)
{
temp=a[i];
a[i]=a[j];
a[j]=temp;
i++;
j--;
}
}while(i<j);//此处i、j不可相等
if(l<j) quicksort(l,j);
if(i<r) quicksort(i,r);
}
6、归并排序
将两个及以上的有序数列,合并成一个有序数列。
二路归并:假设有一组数,共n个,将i指向第一组数的第一个,j指向第二组数的第一个,k指向新数组的第一个,比较第i与第j个数,若第i个数小(大),则将第i个数赋到新数组的第k个,同时i与k同时加1,反之,一直循环此过程,直至一个组取完,则将另一组剩余的元素赋到新数组下标k及其以后的数组中。(三路、四路及以上的归并,原理相同)
(二路归并)程序模板:
void mergesort(int a[],int l,int m,int r) /a数组中存储数据,m是第一组数的结束为止,l、r是数据范围的左右界/
{
int i=l,j=m+1,k=l,b[r-l+1];/b数组中是存放排好序的数据/
while(i<=m&&j<=r)
{
if(a[i]<=a[j])
{
b[k]=a[i];
i++;
k++;
}
else
{
b[k]=a[j];
j++;
k++;
}
}
while(i<=m)
{
b[k]=a[i];
i++;
k++;
}
while(j<=r)
{
b[k]=a[j];
j++;
k++;
}
}
接下来,则以二路归并的思路,再结合递归的思想,将归并排序写出。
程序模板:
void mergesort(int a[],int l,int r) /a数组中存储数据,m是第一组数的结束为止,l、r是数据范围的左右界/
{
int i=l,k=l,b[r-l+1];
if(l==r) return;
m=(l+r)/2;
mergesort(l,m);
mergesort(m+1,r);
int j=m+1;
while(i<=m&&j<=r)
{
if(a[i]<=a[j])
{
b[k]=a[i];
i++;
k++;
}
else
{
b[k]=a[j];
j++;
k++;
}
}
while(i<=m)
{
b[k]=a[i];
i++;
k++;
}
while(j<=r)
{
b[k]=a[j];
j++;
k++;
}
for(i=l;i<=r;i++) a[i]=b[i];
}
各种排序算法的比较
1、稳定性:
稳定:插入排序、冒泡排序、二叉树排序、二路归并及其它线性排序
不稳定:选择排序、希尔排序、快速排序、堆排序
2、时间复杂性
O(n^2):插入排序、冒泡排序、选择排序
O(nlog2n):快速排序、堆排序、归并排序
O(n):桶排序
注:若从最好的情况考虑,直接插入排序、冒泡排序最快;平均情况下,快速排序最快;最坏的情况下,堆排序、归并排序最快。
3、辅助空间
O(n):桶排序、二路归并
快速排序最好O(log2n),最差 O(n)
其余均为O(1)
4、其他
插入排序、冒泡排序速度较慢,但若参与的排序的序列局部或整体有序时,则速度较快,反而此时快速排序较慢。
当n较小时,且对稳定性不作要求宜用选择排序,对稳定性有做要求时,则用插入排序或冒泡排序。
桶排序的数据有一定的范围范围,若无空间相关要求,则适合用此种排序。
当n较大时,且元素较随机,对稳定性无要求,宜用快速排序。
当n较大时,且元素可能出现本身有序,对稳定性无要求,宜用堆排序。
快速排序是目前公认的最好的排序方式,若待排数据随机分布,则其用时最短。堆排序所用辅助空间相较快速排序少,且不会出现快排可能出现的最坏情况。但两种排序均不稳定。
c++中自带的排序——sort
注意:
1、必带algorithm的头文件
2、基本形式sort(arr+m,arr+n);
若不是单纯的按从小到大对一组数进行排序则引用函数(此处的示例为comp函数)用ort(arr+m,arr+n,comp);
①若要从大到小排,则写一个类似此种的函数:
int comp(const int &a,const int &b)
{
return a>b;
}
②但若要对多个特征进行排序,则定义如下:
int comp(const stu&a,const stu&b)
{
if(a.score>b.score) return 1;
if(a.score<b.score) return 0;
if(a.name<b.name) return 1;
return 0;
}
将其引用到以下程序:
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
struct stu
{
int score;
string name;
} a[100];
int n;
int comp(const stu&a,const stu&b)
{
if(a.score>b.score) return 1;
if(a.score<b.score) return 0;
if(a.name<b.name) return 1;
return 0;
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i].name;
cin>>a[i].score;
}
sort(a,a+n,comp);
for(int i=0;i<n;i++) cout<<a[i].name<<' '<<a[i].score<<endl;
return 0;
}