【算法】一般冒泡排序 O(n^2) 稳定的 C语言
冒泡排序
一、算法描述
假设序列中有N个元素:
第一趟选取第一个元素作为关键字,从左至右比较,若遇到比它小的则放到它左边(也即两数进行交换),若遇到比它大的,则改为选取该元素作为关键字完成后续的比较,第一趟则将最大的数调整至序列的最末位置
第二趟选取第一个元素作为关键字,从左至右比较,若遇到比它小的则放到它左边(也即两数进行交换),若遇到比它大的,则改为选取该元素作为关键字完成后续的比较,第二趟则将倒数第二大的数调整至序列的倒数第二位置
第三趟选取第一个元素作为关键字,从左至右比较,若遇到比它小的则放到它左边(也即两数进行交换),若遇到比它大的,则改为选取该元素作为关键字完成后续的比较,第三趟则将倒数第三大的数调整至序列的倒数第三位置
。
。
。
第m趟选取第一个元素作为关键字,从左至右比较,若遇到比它小的则放到它左边(也即两数进行交换),若遇到比它大的,则改为选取该元素作为关键字完成后续的比较,第m趟则将倒数第m大的数调整至序列的倒数第m位置
。
。
。
第N趟选取第一个元素作为关键字,从左至右比较,若遇到比它小的则放到它左边(也即两数进行交换),若遇到比它大的,则改为选取该元素作为关键字完成后续的比较,第N趟(即最后一次)则将倒数第N大(即最小的)的数调整至序列的倒数第N位置(即首位)
注:当没有发生过记录交换,则算法终止
即每次选取第一个元素作为主元往后进行比较,若遇到比它小的则放到它左边(即进行交换),若遇到比它大的则选取大的作为主元进行后续比较,每趟选取了无序队列中最大元素放置无序列最后位,当一趟比较没有发生交换则为有序序列,即像吐泡泡一样第一次把最大的数吐到最末位,第二趟把倒数第二大的数吐到倒数第二位。。。。。
二、算法分析
当原始数据正向有序时为最好情况,此时只需进行一趟排序,作n-1次比较,因此最好情况下的时间复杂度是O(n)
当原始数据反向有序时为最坏情况,此时需进行n-1趟排序,这样需n(n-1)/2次比较,移动元素3n(n-1)/2次,因此最坏情况下时间复杂度为O(n^2)
综上,因此冒泡排序总的平均时间复杂度为 O(n^2) ,且只需定义一个临时变量用于交换,因此空间复杂度为O(1)
冒泡排序就是把小的元素往前调或者把大的元素往后调。比较是相邻的两个元素比较,交换也发生在这两个元素之间。所以,如果两个元素相等,我想你是不会再无聊地把他们俩交换一下的;如果两个相等的元素没有相邻,那么即使通过前面的两两交换把两个相邻起来,这时候也不会交换,所以相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法
三、算法实现代码
定义顺序表代码:
typedef struct list { int Size;//大小 int Elements[MaxSize];//用数组存放 }List;//定义顺序表
定义冒泡排序代码:
void Maopaopaixu(List*lst) { int i, j; int temp;//用于交换 bool sorted;//用于判别是否发生过交换 sorted = false; i = lst->Size - 1;//用于记录趟数 while (i > 0 && !sorted) //当i<=0时(已经完成了N趟排序)或sorted为ture时(某趟没有发生交换)退出 { sorted = true; for (j = 0; j < i; j++)//完成0到i期间的比较,i逐渐变小 { if (lst->Elements[j + 1] < lst->Elements[j])//若主元大于需比较的也即其后面的元素,进行交换,也即 { //放到他左边若小于或等于,不做任何处理,也即换取了后一个数作为主元 temp = lst->Elements[j + 1]; lst->Elements[j + 1] = lst->Elements[j]; lst->Elements[j] = temp; sorted = false;//若发生交换则为false,若该趟不发生一次交换,则sorted一直为true } } i--;//完成一次趟数减一 } }
四、实例测试代码
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <stdbool.h>//布尔类型头文件,需支持C99 #define MaxSize 99 typedef struct list { int Size;//大小 int Elements[MaxSize];//用数组存放 }List;//定义顺序表 void Maopaopaixu(List*lst);//冒泡排序函数声明 int main(void) { List a;//定义一个顺序表对象a int i; srand((unsigned)time(NULL)); //随机数种子 a.Size = 10;//定义大小为10 for (i = 0; i<10; i++) { a.Elements[i] = rand() % 10;//初始化顺序表 } printf("初始原表为:"); for (i = 0; i < 10; i++) { printf("%d ", a.Elements[i]); } printf("\n"); Maopaopaixu(&a);//调用冒泡排序函数,修改值需传入地址 printf("经冒泡排序:"); for (i = 0; i < 10; i++) { printf("%d ", a.Elements[i]); } getchar(); return 0; } void Maopaopaixu(List*lst) { int i, j; int temp;//用于交换 bool sorted;//用于判别是否发生过交换 sorted = false; i = lst->Size - 1;//用于记录趟数 while (i > 0 && !sorted) //当i<=0时(已经完成了N趟排序)或sorted为ture时(某趟没有发生交换)退出 { sorted = true; for (j = 0; j < i; j++)//完成0到i期间的比较,i逐渐变小 { if (lst->Elements[j + 1] < lst->Elements[j])//若主元大于需比较的也即其后面的元素,进行交换,也即 { //放到他左边若小于或等于,不做任何处理,也即换取了后一个数作为主元 temp = lst->Elements[j + 1]; lst->Elements[j + 1] = lst->Elements[j]; lst->Elements[j] = temp; sorted = false;//若发生交换则为false,若该趟不发生一次交换,则sorted一直为true } } i--;//完成一次趟数减一 } }