美文网首页
排序算法(九)鸡尾酒排序

排序算法(九)鸡尾酒排序

作者: ChooAcc | 来源:发表于2019-06-10 16:59 被阅读0次

    排序算法(九)鸡尾酒排序

      鸡尾酒排序(Cock-Tail-Sort)是基于冒泡排序做一点点优化而来的。冒泡排序的原理:从第一个数开始,依次往后比较,相邻的元素两两比较,根据大小来交换元素的位置,如果前面的数比后面的数大就交换,否则不作处理。这就类似烧开水时,壶底的水泡往上冒的过程。这个过程中,元素是单向交换的,也就是说只有从左往右交换,而鸡尾酒排序的元素比较和交换过程是双向的。

    图解过程

    以数组:3, 4, 5, 6, 1为例,按从小到大的方式排序,冒泡排序的过程如下:
    冒泡第一次循环

    冒泡第一此循环
    我们可以发现,在未开始排序的时候,前4个数已经是有序序列了,然而进行冒泡排序至少还需要循环四次、交换四次,这也太浪费时间了吧!
    因此就有了鸡尾酒排序,先看看用鸡尾酒排序是怎么操作的,
    鸡尾酒第一次循环*
    鸡尾酒第一次循环
    从上图可看出,本来需要四次循环,选择仅需一次即可,效率大大提高。
    代码实现
    public int[] sort() {
        int[] numbers = {3, 4, 5, 6, 1};
        for (int i = 0; i < numbers.length/2 - 1; i++) {
    
            // 从左往右遍历时,是否有交换操作的标志
            boolean isRightExchange = false;
            for (int j = 0; j < numbers.length - 1 - i; j++) {
                if (numbers[j] > numbers[j + 1]) {
                    int temp = numbers[j];
                    numbers[j] = numbers[j + 1];
                    numbers[j + 1] = temp;
                    isRightExchange = true;
                }
            }
            // 若没有交换操作,则说明序列已经成为有序序列,直接跳出循环
            if (!isRightExchange) {
                break;
            }
    
            // 从右到左遍历时,是否有交换操作额标志
            boolean isLeftExchange = false;
            for (int k = numbers.length - i - 2; k > i ;k--) {
                if (numbers[k] < numbers[k - 1]) {
                    int temp = numbers[k];
                    numbers[k] = numbers[k - 1];
                    numbers[k -1] = temp;
                    isLeftExchange = true;
                }
            }
            // 若没有交换操作,则说明序列已经成为有序序列,直接跳出循环
            if (!isLeftExchange) {
                break;
            }
        }
        return numbers;
    }
    

    我们知道,在冒泡排序中,可以针对有序区进行优化,鸡尾酒排序一样也是可以的。
    要想优化,我们可以在每一轮排序的最后,记录下最后一次元素交换的位置,那个位置也就是无序数列的边界,再往后就是有序区了。
    对于单向的冒泡排序,我们需要设置一个边界值,对于双向的鸡尾酒排序,我们需要设置两个边界值。请看代码:

     public int[] sort() {
        int[] numbers = {3, 4, 5, 6, 1};
    
        // 左侧最后一次交换元素的位置
        int lastLeftExchangeIndex = 0;
        // 左侧边界值
        int sortLeftBorder = 0;
    
        // 右侧最后一次交换元素的位置
        int lastRightExchangeIndex = 0;
        // 右侧的边界值
        int sortRightBorder = numbers.length - 1;
    
        for (int i = 0; i < numbers.length/2 - 1; i++) {
            // 从左往右遍历时,是否有交换操作的标志
            boolean isRightExchange = false;
            for (int j = sortLeftBorder; j < sortRightBorder; j++) {
                if (numbers[j] > numbers[j + 1]) {
                    int temp = numbers[j];
                    numbers[j] = numbers[j + 1];
                    numbers[j + 1] = temp;
                    // 说明有交换操作
                    isRightExchange = true;
                    // 记录左侧最后一次元素交换的位置
                    lastRightExchangeIndex = j;
                }
            }
            // 设置最后一次交换元素的位置
            sortRightBorder = lastRightExchangeIndex;
            // 若没有交换操作,则说明序列已经成为有序序列,直接跳出循环
            if (!isRightExchange) {
                break;
            }
    
            // 从右到左遍历时,是否有交换操作额标志
            boolean isLeftExchange = false;
            for (int k = sortRightBorder; k > sortLeftBorder ;k--) {
                if (numbers[k] < numbers[k - 1]) {
                    int temp = numbers[k];
                    numbers[k] = numbers[k - 1];
                    numbers[k -1] = temp;
                    // 说明有交换操作
                     isLeftExchange = true;
                    // 记录右侧最后一次元素交换的位置
                    lastLeftExchangeIndex= k;
                }
            }
            // 设置最后一次交换元素的位置
            ortLeftBorder = lastLeftExchangeIndex;
            // 若没有交换操作,则说明序列已经成为有序序列,直接跳出循环
             if (!isLeftExchange) {
                break;
            }
        }
        return numbers;
    }
    

    最后说明

    鸡尾酒排序适用于在大部分元素已经有序的情况下,其优点是能够在该情况下大大减少循环次数,而缺点则是代码有点多。。。

    相关文章

      网友评论

          本文标题:排序算法(九)鸡尾酒排序

          本文链接:https://www.haomeiwen.com/subject/yyozxctx.html