八大排序算法(5) 冒泡排序

基本思想

遍历一个序列,对相邻的两个数比较排序,使小的上浮、大的下沉。
因为是自上而下遍历,因此最终得到的是最大的先沉到底部,较小的元素则一点一点的上浮。
这就是冒泡。

示例:

// 升序,左起
/*初始值*/    12, 7, 1, 8, 5, 10, 6, 3, 9

/*第一趟*/    7, 1, 8, 5, 10, 6,  3, 9, 12
/*第二趟*/    1, 7, 5, 8, 6,  3,  9, 10,12
/*第三趟*/    1, 5, 7, 6, 3,  8,  9, 10,12
/*第四趟*/    1, 5, 6, 3, 7,  8,  9, 10,12
/*第五趟*/    1, 5, 3, 6, 7,  8,  9, 10,12
/*第六趟*/    1, 3, 5, 6, 7,  8,  9, 10,12
/*第七趟*/    1, 3, 5, 6, 7,  8,  9, 10,12
/*第八趟*/    1, 3, 5, 6, 7,  8,  9, 10,12

改进一:

如果一次遍历没有发生交换,说明已经排好了,可以提前结束

改进二:

最后一次交换位置的后面,都是排好了的,那么可以记录下最后一次排序位置,下次循环的哨兵可直接设置在此处。

改进三:

同时对最大、最小进行冒泡。即、一次冒泡中,先进行一轮正向冒泡,再进行一轮反向冒泡,同时设置首尾哨兵。
任意一轮没有交换,可提前结束。
每一轮都记录最后交换位置,下一回相反的冒泡直接从最后交换位置开始。
注意:这种排序是先将两端排好、再排中间,此时的循环不能以链表长度为准,而应该以 未排序的左、右索引值为准。

代码:

void printList(int *l, int n) {
    for (int i = 0; i < n; i++) {
        printf("%d ", l[i]);
    }
    printf("\n");
}


int main() {
    int list[50] = { 12, 7, 1 , 8, 5, 10, 6, 3, 9 };
    int n = 9;
    printList(list, n);

    // 升序,大的先排,小的向上冒泡
    for ( int i = n - 1; i >= 0; ){
        // 以 i 为哨兵,从 顶部 开始。
        int lastIndex = 0;
        bool hasSwap = false;
        for (int j = 0; j < i; j++){
            // 如果 j 比它后面的数大,那么就交换
            if ( list[j] > list[j+1] ){
                int k = list[j];
                list[j] = list[j + 1];
                list[j + 1] = k;
                hasSwap = true;
                lastIndex = j;
            }
        }
        // 如果一次遍历没有发生交换,说明已经排好了,可以提前结束
        if ( !hasSwap ){
            break;
        }
        // 记录最后一次交换的 index,用来当做下一次循环的哨兵
        i = lastIndex;
        printList(list, n);
    }
    printList(list, n);

    printf("==================\n");
    // 升序,小的先排,大的向下沉
    for (int i = 0; i < n;) {
        // 以 i 为哨兵,从 底部 开始。
        int lastIndex = i;
        bool hasswap = false;
        for (int j = n - 1; j > i; j--) {
            // 如果 j 比它前面的数小,那么就交换
            if (list[j] < list[j - 1]) {
                int k = list[j];
                list[j] = list[j - 1];
                list[j - 1] = k;
                hasswap = true;
                lastIndex = j;
            }
        }
        // 如果一次遍历没有发生交换,说明已经排好了,可以提前结束
        if ( !hasswap ){
            break;
        }
        i = lastIndex;
        printList(list, n);
    }
    printList(list, n);


    //printf("==================\n");
    // 升序,双向冒泡,先从底部开始向上冒泡
    int leftIndex = 0;
    int rightIndex = n - 1;
    while (leftIndex < rightIndex) {
        int lastIndex = leftIndex;
        bool hasSwap = false;

        // 先向上冒泡一轮
        for (int j = leftIndex; j < rightIndex; j++) {
            if ( list[j] > list[j + 1] ){
                int k = list[j];
                list[j] = list[j + 1];
                list[j + 1] = k;
                hasSwap = true;
                lastIndex = j;
            }
        }
        // 提前结束
        if ( !hasSwap ) {
            break;
        }
        // 向上冒泡,更新的是下限
        rightIndex = lastIndex;
        printList(list, n);
        printf("leftIndex:%d, rightIndex:%d\n", leftIndex, rightIndex);

        // 再向下冒泡一轮
        for (int j = rightIndex; j > leftIndex; j--) {
            if (list[j] < list[j - 1] ) {
                int k = list[j];
                list[j] = list[j - 1];
                list[j - 1] = k;
                hasSwap = true;
                lastIndex = j;
            }
        }
        // 提前结束
        if (!hasSwap) {
            break;
        }
        // 向下冒泡,更新的是上限
        leftIndex = lastIndex;
        printList(list, n);
        printf("leftIndex:%d, rightIndex:%d\n", leftIndex, rightIndex);
    }
    printList(list, n);


    system("pause");
    return 0;
}

以上

原文链接 http://blog.csdn.net/u011546766/article/details/74053481

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值