基本思想:
两两比较相邻记录的关键字,若顺序反了就进行交换,直到所有元素排序正确
将要排序的一组数字进行遍历。
第一次遍历,将相邻的两个数字进行比较,直到这组数字全部比较完成,如果前面比后面的数字大,则进行交换位置,此时可以将最大的数字筛选出来,放到最后的位置上。
第二次遍历,将相邻的两个数字进行比较,直到这组数字全部比较完成,如果前面比后面的数字大,则进行交换位置,将这组数字里面第二大的数字筛选出来,放到倒数第二的位置上。
依次进行遍历,交换位置,直到排序完成。
由于每次遍历都放置好了一个当前最大数,故每次执行遍历的时候的循环次数减一
排序所用的结构和函数:
#define MAX 10
//排序所用的顺序表结构
typedef struct
{
int a[MAX+1]; //存储排序数组,a[0]用作临时变量,不存入数值
int length; //记录顺序表的长度
}Sqlist;
//交换
void swap(Sqlist *L,int i,int j)
{
int t=L->a[i];
L->a[i]=L->a[j];
L->a[j]=t;
}
最简冒泡排序:
//初级版冒泡排序
//该算法效率低下,比较当前的关键字时对其余的关键字的排序没有帮助
void BubbleSort(Sqlist *L)
{
int i,j;
for(i=1;i<L->length;i++)
{
for(j=i+1;j<=L->length;j++) //j=i+1
{
if(L->a[i]>L->a[j])
swap(L,i,j);
}
}
}
改进的正版冒泡排序:
//交换当前关键字的过程中,其余的关键字也有一定程度的排序
//较小的数字如同气泡一般上浮,故得名冒泡排序
void BubbleSort(Sqlist *L)
{
int i,j;
for(i=1;i<L->length;i++)
{
for(j=L->length-1;j>=i;j++) //逆序循环,注意要有j=i
{
if(L->a[j]>L->a[j+1]) //将前者与后者比较 (注意比较的条件j,j+1)
swap(L,j,j+1);
}
}
}
在待排序的序列大部分都是有序的情况下,传统冒泡排序效率不高,所以我们进行再改进:
//定义一个标志变量
void BubbleSort2(Sqlist *L)
{
int i,j;
int flag=TRUE;
for(i=1;i<L->length&&flag;i++) //意为当flag为FALSE时循环退出,此时说明没有发生交换,即有序
{
flag=FALSE;
for(j=L->length-1;j>=i;j++)
{
if(L->a[j]>L->a[j+1])
{
swap(L,j,j+1);
flag=TRUE;
}
}
}
}
有了标志变量之后,有序的部分就不需要一步步去排序了,节省了时间。
时间复杂度
最好的情况下,表本身就有序,依据最后改进的代码,进行n-1次比较,无数据交换,时间复杂度O(n)
最坏情况,表为逆序,此时比较:1+2+3+4+...+(n-1)=n*(n-1)/2次,移动次数相同,故O(n^2)