#排序算法总结
- 插入排序
特点:效率低,容易实现
原理:将数组分为两部分,将后部分元素逐一插入前部分有序元素的适当位置
void insert(int *a,int length);
int main() {
int a[]={3,2,1,6,5,4,9,8,7,10};
insert(a,10);
for(int i=0;i<10;i++)
cout<<a[i];
return 0;
}
void insert(int *a,int length){
int temp;
for(int i=0;i<length;i++)
{
int j=i;
temp=a[i];
while(j>0&&temp<a[j-1])
{
a[j]=a[j-1];
j--;
}
a[j]=temp;
}
}
- 选择排序
特点:效率低,容易实现
原理:每一趟都将一个数排在序列左边的合适位置上,剩下的未排序序列,重复上述过程。
优化方法:不用一遇到比已选择的元素大的元素就进行交换;而是记录该元素下标,最终只需要将该下标元素和需交换的元素交换即可。
void XuanZe(int *a,int length);
int main() {
int a[]={3,2,1,6,5,4,9,8,7,10};
XuanZe(a,10);
for(int i=0;i<10;i++)
cout<<a[i];
return 0;
}
void XuanZe(int *a,int length){
int index;
for(int i=0;i<length-1;i++)
{
index=i;
for(int j=i+1;j<length;j++)
if(a[index]>a[j])
{
swap(index,j);
}
if(index!=i)
{
swap(a[index],a[i]);
}
}
}
- 冒泡排序
特点:效率低,容易实现
原理:将待排序列中最大的数往后冒泡,成为新的序列
for(i=0;i<n;i++)
for(j=0;j<n-i-1;j++)
- 快速排序
特点:高效,时间复杂度为nlogn;
原理:采用分治法的思想:首先设置一个中间值,然后以这个中间值为划分基准将待排序序列分成比该值小的两部分,将这两部分再分别进行快速排序,直到序列只剩下一个元素。
void quicksort(int a[],int low,int high);
//快速排序
int main() {
int a[]={4,3,2,1,5,8,7,6,10,9};
quicksort(a,0,9);
for(int i : a)
cout<<i<<endl;
return 0;
}
void quicksort(int *a,int low,int high){
if(low<high)
{
int x=a[low],i=low,j=high;
while(i<j)
{
while(i<j&&a[j]>=x)
j--;
if(i<j)
a[i++]=a[j];
while(i<j&&a[i]<=x)
i++;
if(i<j)
a[j--]=a[i];
}
a[i]=x;
quicksort(a,low,i-1);
quicksort(a,i+1,high);
}
}
- 归并排序
核心思想:分治。
下面我们来看归并排序的思路(先讲思路再来具体讲归并的细节):
归并排序(Merge Sort)
当我们要排序这样一个数组的时候,归并排序法首先将这个数组分成一半。如图:
然后想办法把左边的数组给排序,右边的数组给排序,之后呢再将它们归并起来。当然了当我们对左边的数组和右边的素组进行排序的时候,再分别将左边的数组和右边的数组分成一半,然后对每一个部分先排序,再归并。如图:
对于上面的每一个部分呢,我们依然是先将他们分半,再归并,如图:
分到一定细度的时候,每一个部分就只有一个元素了,那么我们此时不用排序,对他们进行一次简单的归并就好了。如图:
归并到上一个层级之后继续归并,归并到更高的层级,如图:
直至最后归并完成。
void Merge(int r[],int r1[],int s,int m,int t) //r[]是一个输入的数组,r1[]是中间数组,s=0,t=数组长度减一
{
int i=s;
int j=m+1;
int k=s;
while(i<=m&&j<=t)
{
if(r[i]<=r[j])
r1[k++]=r[i++];
else
r1[k++]=r[j++];
}
while(i<=m)
r1[k++]=r[i++];
while(j<=t)
r1[k++]=r[j++];
for(int l=0; l<8; l++)
r[l]=r1[l];
}
void MergeSort(int r[],int r1[],int s,int t)
{
if(s==t)
return;
else
{
int m=(s+t)/2;
MergeSort(r,r1,s,m);
MergeSort(r,r1,m+1,t);
Merge(r,r1,s,m,t);
}
}
6.计数排序
优点:计数排序(Count Sort)是一个非基于比较的排序算法,该算法于1954年由 Harold H. Seward 提出。它的优势在于在对一定范围内的整数排序时,它的复杂度为Ο(n+k)(其中k是整数的范围),快于任何比较排序算法。
算法分析:计数排序是一种以空间换时间的排序算法,并且只适用于带排序中所有的数较集中是,比如一组序列中的数据为0 1 2 3 4 9999;就得开辟10000个辅助空间。
时间复杂度:
计数排序的时间复杂度理论为O(n+k),其中k为序列中数的范围。
不过当O(k)>O(n*log(n))的时候其效率反而不如基于比较的排序(比如归并排序)
原理:计数排序的思想类似于哈希表中的直接定址法,在给定的一组序列中,先找出该序列中的最大值和最小值,从而确定需要开辟多大的辅助空间,每一个数在对应的辅助空间中都有唯一的下标。
找出序列中最大值和最小值,开辟Max-Min+1的辅助空间
最小的数对应下标为0的位置,遇到一个数就给对应下标处的值+1,。
遍历一遍辅助空间,就可以得到有序的一组序列
void CountSort(int* array,int size)
{
assert(array);
int max = array[0];//序列中的最大值
int min = array[0];//序列中的最小值
for(int i = 0;i < size;++i)
{
if(array[i] >= max)
{
max = array[i];
}
else
{
min = array[i];
}
}
int range = max - min + 1;//需要开辟的空间大小
int* count = new int[range];
memset(count,0,sizeof(int)*range);//辅助空间初始化为0,0代表没有那个数
for(int i = 0;i < size;++i)
{
count[array[i] - min]++;//array[i]-min是将该数对应到辅助空间的下标
}
int index = 0;
for(int i = 0;i < range;++i)//遍历辅助空间
{
while(count[i]--)//下标处的数值是几,说明该数出现了几次
{
array[index++] = i + min;//将下标处的数对应回原数组
}
}
delete[] count;
}
7.桶排序
原理:桶排序的原理和技术排序的原理一样
8.基数排序