排序算法:一种能将一串数据依照特定的排序方式进行排列的一种算法。 排序算法性能:取决于时间和空间复杂度,其次还得考虑稳定性,及其适应的场景。 稳定性:让原本有相等键值的记录维持相对次序。也就是若一个排序算法是稳定的,当有俩个相等键值的记录R和S,且原本的序列中R在S前,那么排序后的列表中R应该也在S之前。
# 1-冒泡排序
原理 俩俩比较相邻记录的排序码,若发生逆序,则交换;有俩种方式进行冒泡,一种是先把小的冒泡到前边去,另一种是把大的元素冒泡到后边。冒泡法大家都较熟悉。其原理为从a[0]开始,依次将其和后面的元素比较,若a[0]>a[i],则交换它们,一直比较到a[n]。同理对a1,a2,…a[n-1]处理,即完成排序
冒泡排序的基本概念:
依次比较相邻的两个数,将小数放在前面,大数放在后面。即在第一趟:首先比较第1个和第2个数,将小数放前,大数放后。然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后。至此第一趟结束,将最大的数放到了最后。在第二趟:仍从第一对数开始比较(因为可能由于第2个数和第3个数的交换,使得第1个数不再小于第2个数),将小数放前,大数放后,一直比较到倒数第二个数(倒数第一的位置上已经是最大的),第二趟结束,在倒数第二的位置上得到一个新的最大数(其实在整个数列中是第二大的数)。如此下去,重复以上过程,直至最终完成排序。由于在排序过程中总是小数往前放,大数往后放,相当于气泡往上升,所以称作冒泡排序。
实现:
外循环变量设为i,内循环变量设为j。假如有10个数需要进行排序,则外循环重复9次,内循环依次重复9,8,…,1次。每次进行比较的两个元素都是与内循环j有关的,它们可以分别用a[j]和a[j+1]标识,i的值依次为1,2,…,9,对于每一个i,j的值依次为1,2,…10-i。
图示:

性能 时间复杂度为O(N^2),空间复杂度为O(1)。排序是稳定的,排序比较次数与初始序列无关,但交换次数与初始序列有关。
优化 若初始序列就是排序好的,对于冒泡排序仍然还要比较O(N^2)次,但无交换次数。可根据这个进行优化,设置一个flag,当在一趟序列中没有发生交换,则该序列已排序好,但优化后排序的时间复杂度没有发生量级的改变
代码
#include<stdio.h>
void sort(int *a,int len)
{
int i,j,t;
for( i = 0;i<len-1;++i)
{
for(j = 0;j<len-1-i;++j) 或者 j=i+1;j<len;++j
{
if(a[j] >a[j+1])
{
t = a[j];
a[j] = a[j+1];
a[j+1] = t;
}
}
}
}
void main()
{
int a[6] = {10,2,8,-8,11,0};
int i = 0;
sort(a,6);
for(i = 0; i<6;++i)
{
printf("%d ",a[i]);
}
printf("\n");
}
冒泡法原理简单,但其缺点是交换次数多,效率低。下面介绍一种源自冒泡法但更有效率的方法“选择法”。
# 2-选择排序
原理 每次从未排序的序列中找到最小值,记录并最后存放到已排序序列的末尾.选择法循环过程与冒泡法一致,它还定义了记号k=i,然后依次把a[k]同后面元素比较,若a[k]>a[j],则使k=j.最后看看k=i是否还成立,不成立则交换a[k],a[i],这样就比冒泡法省下许多无用的交换,提高了效率。
性能 时间复杂度为O(N^2),空间复杂度为O(1),排序是不稳定的(把最小值交换到已排序的末尾导致的),每次都能确定一个元素所在的最终位置,比较次数与初始序列无关。
代码
//直接选择排序
#include<stdio.h>
void sort(int *a,int len)
{
int i,j,min,t;
for(i = 0;i<len-1;++i)
{
for(min=i,j=i+1;j<len;++j)
{
if(a[min]>a[j])
min = j;
}
if(min!=i)
{
t = a[i];
a[i] = a[min];
a[min] = t;
}
}
}
void main()
{
int a[6] = {4,0,3,2,5,1};
sort(a,6);//a代表数组的首地址
for(int i=0;i<6;++i)
printf("%d\n",a[i]);
}