冒泡排序算法以及它的优化方案

一、什么是冒泡排序?

冒泡排序(Bubble Sort)是一种最为基础的交换排序,相信学过C语言的,都接触过这种排序算法。

这篇文章重点应该放在优化上面。

二、冒泡排序的实现思想:

将数组里面相邻的元素两两比较,根据大小来交换元素位置,举个栗子:

这里有一个数组array[4, 6, 5, 8, 9, 3, 2, 1, 7]

首先4和6比较,4小于6,位置不变,接下来6和5比较,6大于5,所以6和5的位置对调,数组变成[4, 5, 6, 8, 9, 3, 2,1, 7],由于6和5位置对调,接着是6和8比较,6小于8,所以位置不变,如此类推,第一轮排序后,数组变成[4,  5, 6, 8, 3, 2, 1, 7, 9],第二轮又从第一个元素4开始比较,但是最终比较的元素不是9而是7,因为第一轮比较,已经是确定将最大的元素放到了最后的位置,所以没有必要与最后的元素进行比较,这一轮最终结果为[4, 5, 6, 3, 2, 1, 7, 8, 9],

如此类推,完成全部排序总共需要array.length x( array.length-1)/2次比较(这个是等差数列计算出来的,有兴趣的可以自己算一下)。因为每一轮都要全部比较,所以最原始的冒泡排序叫做稳定排序。

根据这种原始思想,可以得到冒泡排序的原始版

public void sortArray(int[] array){
    int temp;
    for(int i=0; i<array.length; i++){
        for(int j=0; j<array.length-i-1; j++){
            if(array[j] > array[j+1]){
                temp = array[j];
                array[j] = array[j+1];
                array[j+1] = temp;
            }
        }
    }
}

我们把每一轮结果罗列出来时,

第三轮结果:[4, 5,  3,  2, 1, 6, 7, 8, 9]

第四轮结果:[4, 3,  2, 1, 5,  6, 7, 8, 9]

第五轮结果:[3, 2, 1, 4,  5,  6, 7, 8, 9]

第六轮结果:[2, 1, 3, 4,  5,  6, 7, 8, 9]

第七轮结果[1, 2, 3, 4,  5,  6, 7, 8, 9]

第八轮结果:[1, 2, 3, 4,  5,  6, 7, 8, 9]

从结果可以看出,程序做了些“无用功”,为了避免程序做这些“无用功”,要对基础版本程序作出一些修改,

优化第一版:

public void sortArray(int[] array){
    int temp;
    for(int i=0; i<array.length; i++){
        boolean isSorted = true;
        for(int j=0; j<array.length-i-1; j++){
            if(array[j] > array[j+1]){
                temp = array[j];
                array[j] = array[j+1];
                array[j+1] = temp;
                isSorted = false;
            }
        }
        if(isSorted){
            break;
        }
    }
}

程序定义了一个boolean类型的isSorted变量,用来判断往后的循环当中,数组是否已经是有序的,每一轮循环都会设置其值为true,当有元素对调位置时,就将isSorted的值设置为false,表示该数组还不是有序数组。每一轮都要判断isSorted的值,如果判断当前一轮操作没有元素有位置调换,那么可以提前结束所有的循环。当然,本次栗子中用到的数组还是需要进行8轮循环,因为,第7轮的时候isSorted的值会被设置为false,到了第八轮才是true,读者可以自行举例别的数组检验。

还是拿回每一轮运行结果出来:

第三轮结果:[4, 5,  3,  2, 1, 6, 7, 8, 9]

第四轮结果:[4, 3,  2, 1, 5,  6, 7, 8, 9]

第五轮结果:[3, 2, 1, 4,  5,  6, 7, 8, 9]

第六轮结果:[2, 1, 3, 4,  5,  6, 7, 8, 9]

第七轮结果[1, 2, 3, 4,  5,  6, 7, 8, 9]

第八轮结果:[1, 2, 3, 4,  5,  6, 7, 8, 9]

这里讲解得详细一点,以第三轮结果,在第四轮运行操作中,4和5比较,4<5,不调换位置,5和3比较,5>3,位置对调,数组变成[4, 3, 5,  2, 1, 6, 7, 8, 9],5和2比较,5<2,位置对调,变成[4, 3, 2, 5, 1, 6, 7, 8, 9],5和1比较,5>1,位置对调,变成[4, 3, 2, 1, 5, 6, 7, 8, 9]。后面就是5和6比较,6和7比较,7和8比较,8和9比较,但是这四次比较对数组排序都没有任何“贡献”,同理,在第五轮循环操作中,没有“贡献”的操作会增加一次,这是不希望出现的。

这里要介绍一个概念——有序区,有序区指数组有序的区域,这里只数组末尾的有序元素组成的区域,在极端的情况,如[9, 8, 7, 6, 5, 4, 3, 2, 1],按照从小到大顺序排序,每一轮排序,有序区只增加一位元素,但更多的情况有序区元素是大于循环轮次,当有序区元素等于数组长度时,可以认为这个数组已经排序完成,所以下面给出第二次优化,

优化第二版:

public void sortArray(int[] array){
    int border = array.length-1;
    int lastIndex = 0;
    int temp;
    for(int i=0; i<array.length; i++){
        boolean isSorted = true;
        for(int j=0; j<border; j++){
            if(array[j] > array[j+1]){
                temp = array[j];
                array[j] = array[j+1];
                array[j+1] = temp;

                lastIndex = j;
                isSorted = false;
            }
        }
        border = lastIndex;
        if(isSorted){
            break;
        }
    }
}

这一版新增了两个int类型变量,一个是border,表示无序项的边界,同时也是每一轮循环的次数设定值,另一个是lastIndex,用来记录最后元素需要交换的下标值,进行一轮循环后,将这个值赋值给border,作为下一轮循环的次数。每一轮循环,当有元素需要调换位置时,记录j的位置,当前轮次循环结束,就将lastIndex赋值给border,最为新一轮循环操作的边界。

以第五轮结果为栗子,[3, 2, 1, 4,  5,  6, 7, 8, 9]

在进行第六轮循环操作时,3和2比较,3>2,位置对调,变成[2, 3, 1, 4,  5,  6, 7, 8, 9],此时lastIndex = j = 0,3和1比较,3>1,位置对调,变成[2, 1, 3, 4,  5,  6, 7, 8, 9],此时lastIndex = j = 1,3和4比较,3<4,位置不变,如此类推,本轮循环结束时,lastIndex = 1,那么此时border = 1,在第七轮循环里面,只需要进行1次比较就可以结束第七轮循环。

但是,优化第二版仍不是最优方案,上面的两种优化方案只是减少每轮的操作次数,还有一种可以直接减少循环的轮数,那就是鸡尾酒算法排序,这个留到下一篇更新。

原文地址:https://www.cnblogs.com/SysoCjs/p/9398491.html

时间: 2024-10-14 02:28:40

冒泡排序算法以及它的优化方案的相关文章

冒泡排序算法及其两种优化

冒泡排序算法及其两种优化 1.排序方法 将被排序的记录数组R[1..n]垂直排列,每个记录R[i]看作是重量为R[i].key的气泡.根据轻气泡不能在重气泡之下的原则,从下往上扫描数组R:凡扫描到违反本原则的轻气泡,就使其向上"飘浮".如此反复进行,直到最后任何两个气泡都是轻者在上,重者在下为止. (1)初始    R[1..n]为无序区. (2)第一趟扫描    从无序区底部向上依次比较相邻的两个气泡的重量,若发现轻者在下.重者在上,则交换二者的位置.即依次比较(R[n],R[n-1

百度没出新算法之前这种最好的的优化方案

百度没出新算法之前这种最好的的优化方案:看到这个标题我相信大家很多人都会呲之以鼻的因为都自己心里感觉这人太装B了吧,谁敢说他的优化方案是最厉害的,首先这只是我感觉的. 自从绿萝算法更新以后咱们这个时候再去更新一篇文章,百度就不会去再从他原先有的数据库里面寻找了,因为这样的话太麻烦太坑爹了,就像一个我们的汶川大地震后的拯救工作太浩大了,就和研究中心里面说的一样,对一篇文章中,抓住10个中心重点就可以判断文章的原创性,伪原创需要的就是知道文章中心重点词,打个比方就像真猴子和假猴子一样万变不离其宗,伪

百度没出新算法之前这样的最好的的优化方案

百度没出新算法之前这样的最好的的优化方案:看到这个标题我相信大家非常多人都会呲之以鼻的由于都自己心里感觉这人太装B了吧,谁敢说他的优化方案是最厉害的,首先这仅仅是我感觉的. 自从绿萝算法更新以后咱们这个时候再去更新一篇文章.百度就不会去再从他原先有的数据库里面寻找了,由于这种话太麻烦太坑爹了,就像一个我们的汶川大地震后的解救工作太浩大了,就和研究中心里面说的一样,对一篇文章中,抓住10个中心重点就能够推断文章的原创性.伪原创须要的就是知道文章中心重点词.打个例如就像真猴子和假猴子一样万变不离其宗

C言语冒泡排序算法及代码

根本思惟及举例阐明 冒泡排序的根本思惟就是不时比拟相邻的两个数,让较大的元素不时地往后移.经由一轮比拟,就选出最大的数:经由第2轮比拟,就选出次大的数,以此类推.下面以对 3  2  4  1 停止冒泡排序阐明.第一轮 排序进程3  2  4  1    (最后)2  3  4  2    (比拟3和2,交流)2  3  4  1    (比拟3和4,不交流)2  3  1  4    (比拟4和1,交流)第一轮完毕,最大的数4曾经在最初面,因而第二轮排序只需求对后面三个数停止再比拟.第二轮 排

【C语言】两种方式实现冒泡排序算法

题目要求 编写一个C语言程序,实现基本的冒泡排序算法. 算法 冒泡排序,用一句话来总结: 一组数中,相邻的两个数进行比较.交换,将最大(小)数交换至尾(首)部,即完成了一次冒泡排序 要想对N个数字进行排序,循环N次即可. 如果真的不理解冒泡排序算法,请点击:冒泡排序_360百科 核心代码 //方式一:从头向尾遍历,将最大数(相对)沉入尾部(相对) void BubbleSort1(int *arr,int sz){ int i = 0; int j = 0; assert(arr); for(i

【排序】冒泡排序算法

特别说明: 对于算法,重在理解其思想.解决问题的方法,思路.因此,以下内容全都假定待排序序列的存储结构为:顺序存储结构. 冒泡排序思想 冒泡排序与插入排序.简单选择排序一样,都是比较简单的一类排序算法.假设待排序序列为 ,则冒泡排序算法思想如下: 01.设置  =  - 1 (注:0     - 1, 用于标记外层循环迭代): 02.如果  = 0,则排序结束,退出: 03.设置  = 0 (注:0    , 用于标记内层循环迭代): 04.如果  = ,跳转并执行 09 步骤 (即:该趟冒泡排

web前端优化方案(Yahoo)

目录(分7类,共35条): [内容]尽量减少HTTP请求数    [服务器]使用CDN(Content Delivery Network)    [服务器]添上Expires或者Cache-Control HTTP头    [服务器]Gzip组件    [css]把样式表放在顶部    [js]把脚本放在底部    [css]避免使用CSS表达式    [js, css]把JavaScript和CSS放到外面    [内容]减少DNS查找    [js, css]压缩JavaScript和CSS

地图点聚合优化方案

一.为什么需要点聚合 在地图上查询结果通常以标记点的形式展现,但是如果标记点较多,不仅会大大增加客户端的渲染时间,让客户端变得很卡,而且会让人产生密集恐惧症(图1).为了解决这一问题,我们需要一种手段能在用户有限的可视区域范围内,利用最小的区域展示出最全面的信息,而又不产生重叠覆盖. 图1 二.已尝试的方案---kmeans 直觉上用聚类算法能较好达成我们目标,因此采用简单的kmeans聚类.根据客户端的请求,我们知道了客户端显示的范围,并到索引引擎里取出在此范围内的数据,并对这些数据进行kme

SPFA算法及其应用和优化

by mps [问题引入] 又是一年春运时,因为睡懒觉而导致抢不到票的你,只能打车回家了,而无疑会消耗许多钱财(黑车...),为了尽可能的节省钱,你希望走的是最短路,路途中会经过n个城市,而你每次经过两个城市之间的高速公路时,都会损耗Ci元,假设其中包含了所有的价钱(邮费,过桥费之类的),你现在在1号城市,希望到达n号城市去,请问最少花费是多少? [输入描述] 第一行,n,m,表示有n个城市,m条高速公路 第二行至第m+1行,每行三个数u,v,w,表示u城市到达v城市的耗费为w元(均为有向边)