今天来总结一下排序算法。
1.冒泡排序:
就是从第一个开始依次与后面的值比较,重复上n-1轮就能得到排好序的数组了。
//冒泡排序.时间复杂度为O(n^2).空间复杂度为O(1).
void Bsort(int a[],int n)
{
int i,j;
if(n<=1) //若数组长度小于等于1则直接退出。
{
return;
}
for(i=0;i<n-1;i++) //需要这么多次的寻找最小值。
{
for(j=0;j<n-i-1;j++) //每次寻找需要比较的次数。
{
if(a[j]>a[j+1]) //若后者大于前者进行交换。
{
swap(&(a[j]),&(a[j+1]));
}
}
}
return;
}
2.选择排序:
先找第一个数为擂主,后面的数依次与它比较交换,重复操作即可。
//选择排序。时间复杂度为O(n^2).空间复杂度为O(1).
void Select(int a[],int n)
{
int i,j;
if(n<=1) //若数组长度小于等于1则直接退出。
{
return;
}
for(i=0;i<n-1;i++) //循环擂台主。
{
for(j=i+1;j<n;j++) //每个擂台主需要进行守擂的次数。
{
if(a[j]<a[i]) //若大于擂主,与擂主交换。
{
swap(&(a[j]),&(a[i]));
}
}
}
return;
}
3.插入排序:
//插入排序.时间复杂度为O(n^2).空间复杂度为O(1).
void Insert(int a[],int n)
{
int i,j;
int b;
if(n<=1) //若数组长度小于等于1则直接退出。
{
return;
}
for(i=1;i<n;i++) //需要插入的值的个数。
{
b=a[i];
for(j=i;j>0;j--) //每次插入寻找插入位置。
{
if(a[j-1]>b)
{
a[j]=a[j-1]; //插入数据。
}
else{
break;
}
}
a[j]=b;
}
return;
}
4.希尔排序:
它就是优化版的插入排序。
//希尔排序.时间复杂度为O(n^1.3),空间复杂度为O(1).
void Shell(int a[],int n)
{
int i,j;
int x,y;
if(n<=1) //若长度小于等于1就退出。
{
return;
}
for(i=n/2;i>=1;i/=2)
{
for(j=i;j<n;j++)
{
x=a[j];
for(y=j;y>=i;y-=i)
{
if(a[y-i]>x)
{
a[y]=a[y-i];
}
else{
break;
}
}
a[y]=x;
}
}
return;
}
5.堆排序:
//堆排序。
//(1)向下调整法
void AdjustDown(int a[],int n,int p)
{
int left=2*p+1;
int right=2*p+2;
int max;
if(left>=n)
{
return;
}
max=left;
if(right<n && a[right]>a[max])
{
max=right;
}
if(a[max]>a[p])
{
swap(a+max,a+p);
}
AdjustDown(a,n,max);
}
//(2)建大堆。
void MakeHeap(int a[],int n)
{
int i=0;
for(i=(n-2)/2;i>=0;i--)
{
AdjustDown(a,n,i);
}
return;
}
//堆排序。
void HeapSort(int a[],int n)
{
int i=0;
for(i=0;i<n-1;i++)
{
swap(a+0,a+(n-1-i)); //将堆顶与堆尾交换,在进行建堆,循环下去就可以了。
MakeHeap(a,n-i-1);
}
for(i=0;i<n;i++)
{
printf("%d ",a[i]); //打印。
}
}
6.归并排序:
采用归并的思想。将数组分为好几块,分别合并,最后在一起合并即可。
(1)递归方法:
//归并排序。
void MergeArray(int a[],int x,int y,int z,int *m)
{
int size=x; //下标。
int p1=x; //第一个值。
int p2=y; //中间的值。
while(p1<y && p2<z) //当满足条件时。
{
if(a[p1]<a[p2]) //若小于,将p1进行搬运到新的数组里。
{
m[size++]=a[p1++];
}
else{
m[size++]=a[p2++]; //否则搬运p2.
}
}
while(p1<y) //当p1小于中间值时
{
m[size++]=a[p1++]; //继续将后面所有的值放入新数组里。
}
while(p2<z)
{
m[size++]=a[p2++];
}
memcpy(a+x,m+x,sizeof(int) * (z - x)); //将整个新数组赋值给原来的数组。
}
void _MergeSort(int a[],int x,int z,int *m)
{
int mid;
if(z-x<=1)
{ //若数组元素只有一个或没有,退出。
return;
}
mid=x+(z-x)/2; //求中间值。
_MergeSort(a,x,mid,m); //递归左半边。
_MergeSort(a,mid,z,m); //递归右半边。
MergeArray(a,x,mid,z,m);
}
void MergeSort(int a[],int n)
{
int *m=(int *)malloc(sizeof(int)*n); //开辟空间。
_MergeSort(a,0,n,m); //调用归并排序。
free(m); //释放这个空间。
}
(2)非递归方法:
//非递归归并排序。
void MergeLoop(int a[],int n)
{
int *m=(int *)malloc(sizeof(int)*n); //先开辟空间。
int i,j;
int start,mid,end; //定义三个变量。
if(n<=1) //若数组个数小于等于1,则直接退出。
{
return;
}
for(j=1;j<n;j=j*2){ //每次合并数组的大小。1 2 4 8 ...
for(i=0;i<n;i+=2*j) //将原数组分成多少组小数组。
{
start=i; //将三个变量赋值。
mid=i+j;
end=mid+j;
if(mid>n) //若超过了数组大小,那就赋值1.
{
mid=n;
}
if(end>n)
{
end=n;
}
MergeArray(a,start,mid,end,m); //调用函数合并数组。
}
}
return;
}
7.快速排序。
就是确定一个中间值,将比它小的放前面,比它大的放后面,在在各个数组里继续使用这个方法即可。
//快速排序。时间复杂度:O(NlogN)空间复杂度:O(N)。
void SortArray(int a[],int left,int mid,int right) //比较函数。
{
int x=left;
if(mid==right) //若中间值与最后的值相等,则直接退出。
{
return;
}
for(x=left;x<mid;x++) //先比较左半边。
{
if(a[x]>a[mid])
{
swap(a+x,a+mid);
}
}
for(x=mid+1;x<right;x++) //在比较右半边。
{
if(a[x]<a[mid+1])
{
swap(a+x,a+(mid+1));
}
}
}
//非递归快排
void FastLoop(int a[],int n)
{
int left;
int right;
int mid;
int i,j;
if(n<=1) //若数组个数小于等于1直接退出。
{
return;
}
for(i=1;i<n;i++)
{
for(j=0;j<n;j+=2*i+1)
{
left=j; //确定三个值。
mid=j+i;
right=mid+i;
if(mid>n)
{
mid=n;
}
if(right>n) //若中间和最后的值等于数组大小,就将它赋成数组大小。
{
right=n;
}
SortArray(a,left,mid,right); //调用这个比较函数即可。
}
}
return;
}
最后给大家稍微总结一下:
这就是排序的大部分算法了,这里的算法代码不是很重要,重要的是思想和方法,希望大家能下去好好想想每个排序的具体应用思想,这样才能让大家掌握的更加牢固。