基本思想
冒泡排序是将一组数字从第一个数开始到第(m(数组长度)-k(循环次数)-1)数,一直与后一位数进行比较(从小到大排序),大的数放后一位,小的数放前一位,总共循环m(数组长度)-1次。
排序过程
C语言实例
//data是排序的数组,length是数组长度
int BubbleSort(int data[], int length) {
int i, j;
for(i = 0;i < length - 1;i ++) { //循环(length - 1)次
for(j = 0;j < length - 1 - i;j ++) { //循环(length - 1 - 循环次数)次
if(data[j] > data[j+1]) { //与后一位进行比较,把小的放前面,大的放后面
int tmp = data[j];
data[j] = data[j+1];
data[j+1] = tmp;
}
}
}
return 0;
}
总结
冒泡排序其实就是每一次遍历数组找到最大(或最小)的数放到m(数组长度)-k(循环次数)-1位(即数组从尾到头是从大到小排序),是比较次数和排序时间比较稳定是一种排序。
算法优化
1.设置标记
如果遍历数组的过程中没有进行过数字交换,设置一个标记,表示数组已经排序好了,就不需要继续进行遍历。
C语言实例
int BubbleSort(int *data, int length) {
int i, j;
int flag; //是否排序完成标记
for(i = 0;i < length - 1;i ++) { //循环(length - 1)次
flag = 0; //每一次遍历开始标记是0
for(j = 0;j < length - 1 - i;j ++) { //循环(length - 1 - 循环次数)次
if(data[j] > data[j+1]) { //与后一位进行比较,把小的放前面,大的放后面
int tmp = data[j];
data[j] = data[j+1];
data[j+1] = tmp;
flag = 1; //如果遍历过程有进行数字交换,标记为1
}
}
if(flag == 0) { //如果没有进行过数字交换,排序完成
return 0;
}
}
return 0;
}
排序过程
2.记录最后进行数字交换的位置
记录上次遍历最后进行数字交换的位置,因为该位置后面的数字都是排序好的,就不需要继续排序了。
C语言实例
int BubbleSort(int *data, int length) {
int i, j;
int flag; //是否排序完成标记
int pos = length; //记录上次遍历数字的位置
int num = length; //临时记录
for(i = 0;i < length - 1;i ++) { //循环(length - 1)次
flag = 0; //每一次遍历开始标记是0
//循环(length - 1 - 循环次数)次,如果遍历到上一次最后排序的位置,结束本次遍历
for(j = 0;j < length - 1 - i && j < pos;j ++) {
if(data[j] > data[j+1]) { //与后一位进行比较,把小的放前面,大的放后面
int tmp = data[j];
data[j] = data[j+1];
data[j+1] = tmp;
flag = 1; //如果遍历过程有进行数字交换,标记为1
num = j; //一直记录遍历的位置,直到本次遍历完毕
}
}
if(flag == 1) { //如果进行过数字交换,记录上次进行过数字交换的位置
pos = num;
}else { //如果没有进行过数字交换,排序完成
return 0;
}
}
return 0;
}
排序过程
3.鸡尾酒排序
鸡尾酒排序又叫双向冒泡排序,来回排序,比原来快一点,原理就是数组的"正序"和"逆序"程度不同,有时候正向冒泡比较快,有时候反向冒泡比较快,两种方向结合起来,吸收各自的优点和缺点,但是优点比较大。
例如:
1.数组2,3,4,5,1的情况下正向冒泡需要4次遍历,反向冒泡1次遍历
2.数组5,1,2,3,4的情况下正向冒泡需要1次遍历,反向冒泡4次遍历
3.而以上两种情况鸡尾酒排序都只需要2次遍历
不过如果数组特别"逆序"的情况下,冒泡排序和鸡尾酒排序效率都很差。
C语言实例
int CocktailSort(int *data, int length) {
int left = 0; //记录反向冒泡终点
int right = length-1; //记录正向冒泡终点
int i,j;
int temp;
while(left < right) { //左右终点相交排序完毕
for(i = left;i < right;i ++) { //正向冒泡,找到当前排序元素里最大的那个,放在右侧
if(data[i] > data[i+1]) {
temp = data[i];
data[i] = data[i+1];
data[i+1] = temp;
}
}
right--; //反向冒泡终点左进
for(j = right;j > left;j --) { //反向冒泡,找到当前排序元素里最小的那个,放在左侧
if(data[j-1] > data[j]) {
temp = data[j-1];
data[j-1] = data[j];
data[j] = temp;
}
}
left++; //正向冒泡终点右进
}
}
排序过程
最终优化
将1,2,3点优化结合起来
C语言实例
int CocktailSort(int *data, int length) {
int left = 0; //记录反向冒泡终点
int right = length-1; //记录正向冒泡终点
int i,j;
int temp;
int flag; //是否排序完成标记
int num; //临时记录
while(left < right) { //左右终点相交排序完毕
flag = 0; //每一次遍历开始标记是0
for(i = left;i < right;i ++) { //正向冒泡,找到当前排序元素里最大的那个,放在右侧
if(data[i] > data[i+1]) {
temp = data[i];
data[i] = data[i+1];
data[i+1] = temp;
flag = 1; //如果遍历过程有进行数字交换,标记为1
num = i; //一直记录遍历的位置,直到本次遍历完毕
}
}
//right--; //反向冒泡终点左进
if(flag == 0) {
return 0;
}else {
right = num; //如果进行过数字交换,记录上次进行过数字交换的位置
}
flag = 0; //每一次遍历开始标记是0
for(j = right;j > left;j --) { //反向冒泡,找到当前排序元素里最小的那个,放在左侧
if(data[j-1] > data[j]) {
temp = data[j-1];
data[j-1] = data[j];
data[j] = temp;
flag = 1; //如果遍历过程有进行数字交换,标记为1
num = j; //一直记录遍历的位置,直到本次遍历完毕
}
}
//left++; //正向冒泡终点右进
if(flag == 0) {
return 0;
}else {
left = num; //如果进行过数字交换,记录上次进行过数字交换的位置
}
}
}
排序过程
可以明显感觉得到效率提升。