排序算法(C语言)
(一)冒泡排序
原理
总体来说就八个字吧,双重循环,两两比较。
- 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
- 针对所有的元素重复以上的步骤,除了最后一个;
- 重复步骤1~3,直到排序完成。
相关代码
/*冒泡排序*/
void mp(int *a,int length){//a为数组的首地址,length为数组元素的个数。
int i,j,t;
for(i=1;i<length;i++)
for(j=0;j<length-i;j++){
if(a[j]<a[j+1]){//若前者小于后者,则交换这两个元素的位置。
t=a[j];
a[j]=a[j+1];
a[j+1]=t;
}
}
}
复杂度分析
冒泡排序需要比较的次数为n(n-1)/2,最差需要交换的次数为n(n-1)/2,其时间复杂度为O(n^2)。**
优点
- 编程复杂度低,很容易实现;
- 具有稳定性,这里的稳定性是指源序列中相同元素的相对顺序仍然保持到排序后的顺序;
(二)选择排序
原理
选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
相关代码
/*选择排序*/
void xz(int *a,int length){//a为数组的首地址,length为数组元素的个数。
int i,j,t,min;
for(i=0;i<length-1;i++){
min=i; //将当前下标定义为最小值下标;
for(j=i+1;j<length;j++){
if(a[j]<a[min]){//寻找下标为nin以及min之后数组元素的最小值;
min=j;
}
}
if(min!=i){
t=a[i];a[i]=a[min];a[min]=t;//将找到的最小值与a[i]交换;
}
}
}
复杂度分析
选择排序需要比较的次数为n*(n-1)/2,但最差需要交换的次数为n-1次,其时间复杂度为O(n^2),比较次数和冒泡排序一致,交换次数少于冒泡排序,总体优于冒泡排序。但其稳定性较差。
(三)直接插入排序
原理
插入排序(Insertion-Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
- 从第一个元素开始,该元素可以认为已经被排序;
- 取出下一个元素,在已经排序的元素序列中从后向前扫描;
- 如果该元素(已排序)大于新元素,将该元素移到下一位置;
- 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
- 将新元素插入到该位置后;
- 重复步骤2~5。
相关代码
/*直接插入排序*/
void cr(int *a,int length){
int i=0,t=0,j=0;
for(i=1;i<length;i++){//将第一个元素a[0]看作是有序序列;
if(a[i]<a[i-1]){
t=a[i];
for(j=i-1;j>=0&&a[j]>t;j--)//向前扫描,找到正确位置;
a[j+1]=a[j];
a[j+1]=t;
}
}
}
复杂度分析
当排序序列为逆序即最坏情况下,总比较次数为(n+2)(n-1)/2,移动次数为(n+4)(n-1)/2;
当排序序列已排好序,即最好情况下,总比较次数为n-1,移动次数为0;
如果排序记录是随机的话,那么根据概率相同的情况原则,平均比较和移动的次数约为(n^ 2)/4 次,因此我们可以得出直接插入排序法的书剑复杂度为O(n^2) 从这里也可以看出直接插入排序比冒泡排序和简单选择排序性能要好一点,是一个稳定的排序算法。
(四)希尔排序
原理
1959年Shell发明,第一个突破O(n2)的排序算法,是简单插入排序的改进版。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序。
核心思想: 先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。
- 选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
- 按增量序列个数k,对序列进行k 趟排序;
- 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1时,整个序列作为一个表来处理,表长度即为整个序列的长度。
相关代码
#include <stdio.h>
int shsort(int s[], int n) /* 自定义函数 shsort()*/
{
int i,j,d;
d=n/2; /*确定固定增虽值*/
while(d>=1)
{
for(i=d+1;i<=n;i++) /*数组下标从d+1开始进行直接插入排序*/
{
s[0]=s[i]; /*设置监视哨*/
j=i-d; /*确定要进行比较的元素的最右边位置*/
while((j>0)&&(s[0]<s[j]))
{
s[j+d]=s[j]; /*数据右移*/
j=j-d; /*向左移d个位置V*/
}
s[j + d]=s[0]; /*在确定的位罝插入s[i]*/
}
d = d/2; /*增里变为原来的一半*/
}
return 0;
}
int main()
{
int a[11],i; /*定义数组及变量为基本整型*/
printf("请输入 10 个数据:\n");
for(i=1;i<=10;i++)
scanf("%d",&a[i]); /*从键盘中输入10个数据*/
shsort(a, 10); /* 调用 shsort()函数*/
printf("排序后的顺序是:\n");
for(i=1;i<=10;i++)
printf("%5d",a[i]); /*输出排序后的数组*/
printf("\n");
return 0;
}
复杂度分析
希尔排序的时间复杂度与选中的增量d 有关。
在最优的情况下,时间复杂度为:O(n ^ 1.3) (元素已经排序好顺序)
在最差的情况下,时间复杂度为:O(n ^ 2);
参考出处:
https://blog.youkuaiyun.com/Gunanhuai/article/details/102407016
https://www.cnblogs.com/onepixel/p/7674659.html