冒泡排序及其优化

基本思想

冒泡排序是将一组数字从第一个数开始到第(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;                  //如果进行过数字交换,记录上次进行过数字交换的位置
        }
    }
}

排序过程

在这里插入图片描述
可以明显感觉得到效率提升。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值