冒泡排序的实现及优化和变形

1.概述

冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。在一般面试中也是最容易碰到的排序算法。

算法描述

  • 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
  • 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
  • 针对所有的元素重复以上的步骤,除了最后一个;
  • 重复步骤1~3,直到排序完成。

2.基本实现

参考代码如下

pojo类

 1 public class pojo {
 2     public int[] s;
 3     public pojo(){}
 4     //产生n个随机整数
 5     public pojo(int n){
 6         s=new int[n];
 7         for(int i=0;i<n;i++)
 8             s[i]=new Random().nextInt(n);
 9     }
10     //产生n个有序整数,falg为true为顺序,false为逆序
11     public pojo(int n,boolean falg){
12         s=new int[n];
13         if(falg){
14             for(int i=0;i<n;i++)
15                 s[i]=i;
16         }else{
17             for(int i=0;i<n;i++)
18                 s[i]=n-i;
19         }
20     }
21     //返回前n个数总和
22     public long average(int n){
23         long sum=0;
24         for(int i=0;i<n;i++)
25             sum+=s[i];
26         return sum;
27     }
28 }

maopao类

 1 public class maopao {
 2     public static void sort(int[] s){
 3         for(int i=0;i<s.length;i++){
 4             for(int j=0;j<s.length-1-i;j++){
 5                 if(s[j]>s[j+1]){
 6                     s[j]=s[j]+s[j+1];
 7                     s[j+1]=s[j]-s[j+1];
 8                     s[j]=s[j]-s[j+1];
 9                 }
10             }
11         }
12     }
13     public static void main(String[] args) {
14         pojo a=new pojo(10000);
15         int []s=a.s;
16         System.out.println(Arrays.toString(s));
17         long startTime=System.nanoTime();   //获取开始时间
18         sort(s);
19         long endTime=System.nanoTime(); //获取结束时间
20         System.out.println(Arrays.toString(s));
21         System.out.println("冒泡排序程序运行时间:"+(endTime-startTime)+"ns"+"\t"+"数组长度为:"+s.length);
22     }
23 }

运行结果


注意代码中"s[j]=s[j]+s[j+1];s[j+1]=s[j]-s[j+1];s[j]=s[j]-s[j+1];",这段代码意思为s[j]与s[j+1]的值交换

3.优化

思考一下,当需要排序的数据是排好的或者接近排好的,这样的话在循环结束前就已经排好了,但是排序还是会循环判断下去,这样会多做不少无用功,那有什么办法让循环停止呢?

我们发现在一次冒泡循环中,如果当前元素与下一个元素不用交换、下一个元素与下下个元素不用交换、下下个元素...那么当前元素一直到最后一个元素一定是排好的,而循环遍历到当前元素时,第一个元素到当前元素已经是排好的了,所有整体就第一个元素到最后一个元素都排好了,可以直接结束了。

参考代码如下

 1 public class maopao1 {
 2     public static void sort(int[] s){
 3         for(int i=0;i<s.length;i++){
 4             boolean flag=false;
 5             for(int j=0;j<s.length-1-i;j++){
 6                 if(s[j]>s[j+1]){
 7                     s[j]=s[j]+s[j+1];
 8                     s[j+1]=s[j]-s[j+1];
 9                     s[j]=s[j]-s[j+1];
10                     flag=true;
11                 }
12             }
13             if(!flag)
14                 break;
15         }
16     }
17     public static void main(String[] args) {
18         pojo a=new pojo(10000);
19         int []s=a.s;
20         System.out.println(Arrays.toString(s));
21         long startTime=System.nanoTime();   //获取开始时间
22         sort(s);
23         long endTime=System.nanoTime(); //获取结束时间
24         System.out.println(Arrays.toString(s));
25         System.out.println("优化冒泡排序程序运行时间:"+(endTime-startTime)+"ns"+"\t"+"数组长度为:"+s.length);
26     }
27 }

运行结果

我在这里增加了一个flag变量来做标记,当满足条件后直接跳出循环。

发现没有,运行时间上基本没什么变化,但是注意我上面说了,当需要排序的数据是排好的或者接近排好的,优化效果就非常明显了。

改变上面maopao1类的代码

这个表示获取从小到大的1-10000排列的数组,我们的目标也是从小打大排序。

结果如下

3.变形

我在这里讲一种新的排序,它叫鸡尾酒排序,或者叫快乐小时排序,当然它不止这两种叫法。他是冒泡排序的一种变形,是基于冒泡排序的。

他的原理是:先找到最小的数字,把他放到第一位,然后找到最大的数字放到最后一位。然后再找到第二小的数字放到第二位,再找到第二大的数字放到倒数第二位。以此类推,直到完成排序。也就是双向的冒泡。

参考代码如下

 1 public class maopao2 {
 2     public static void sort(int[] s){
 3         int left=0,right=s.length-1;
 4         while(left<right){
 5             //同优化冒泡排序
 6             boolean flag=false;
 7             //从右向左冒泡,找最小的
 8             for(int i=right;i>left;i--)
 9                 if(s[i]<s[i-1]){
10                     s[i]=s[i]+s[i-1];
11                     s[i-1]=s[i]-s[i-1];
12                     s[i]=s[i]-s[i-1];
13                     flag=true;
14                 }
15             left++;
16             //从左向右冒泡,找最大的
17             for(int i=left;i<right;i++)
18                 if(s[i]>s[i+1]){
19                     s[i]=s[i]+s[i+1];
20                     s[i+1]=s[i]-s[i+1];
21                     s[i]=s[i]-s[i+1];
22                     flag=true;
23                 }
24             right--;
25             if(!flag)
26                 break;
27         }
28     }
29     public static void main(String[] args) {
30         pojo a=new pojo(10000);
31         int []s=a.s;
32         System.out.println(Arrays.toString(s));
33         long startTime=System.nanoTime();   //获取开始时间
34         sort(s);
35         long endTime=System.nanoTime(); //获取结束时间
36         System.out.println(Arrays.toString(s));
37         System.out.println("鸡尾酒排序程序运行时间:"+(endTime-startTime)+"ns"+"\t"+"数组长度为:"+s.length);
38     }
39 }

运行结果

虽然运行时间没有多大改变,但是在某些特定的环境下是要优于冒泡排序的。

改变maopao2类代码:

运行结果:

改变maopao2类代码:

运行结果:

原文地址:https://www.cnblogs.com/chengpu/p/algorithm3.html

时间: 2024-10-11 19:23:30

冒泡排序的实现及优化和变形的相关文章

【总结】冒泡排序及冒泡排序的两种优化

------------------------------------------------------------------------------------------------------ 冒泡排序(bubble sort)算法的运作如下:从前往后一次比较相邻的两个元素,如果第二个比第一个元素小,则交换这两个元素,一直到与最后一个元素比较完成,这样最大的元素就放到了最后:这样重复比较(n-1)次即可完成排序. -----------------------------------

冒泡排序及两种优化方式

冒泡排序是最常用的小型数据排序方式,下面是用C语言实现的,及其两种优化方式. 第一种优化方式是设置一个标记位来标记是否发生了交换,如果没有发生交换就提前结束: 第二种优化方式是记录最后放生交换的位置,作为下一趟比较结束的位置. #include <stdio.h> /* * 打印数组 * */ void printArray(int arr[], int n) { int i = 0; for (i = 0; i < n; ++i) { printf("%d ", a

冒泡排序的三种优化

传统的冒泡排序完全可以满足我们最基本的需求,但是也仅仅是最简单的需求,这种简单的两个for循环不加任何的判断语句的形式注定它只能是一种效率最低的算法. 我们先贴一个传统的实现方式,之后的三个优化全部建立在函数排序所使用的消耗上,这也是我们优化一切算法的根本路径. void BubbleSort(int* arr,int size) { assert(arr&&size); if(size==1) return; for(int i=0;i<size-1;i++) { for(int

Java_冒泡排序_原理及优化

冒泡排序及其优化 一.原理及优化原理 1.原理讲解 冒泡排序即:第一个数与第二个数进行比较,如果满足条件位置不变,再把第二个数与第三个数进行比较.不满足条件则替换位置,再把第二个数与第三个数进行比较,以此类推,执行完为一个趟,趟数等于比较的个数减一. 2.冒泡排序原理图示:(以98765序列为例,排序结果从小到大) 3.冒泡排序优化 优化版:每一次减少一次循环(即红色部分不需要在进行比较) 4.冒泡排序最终版 最终版:每一趟减少一次循环(删除线不需要再执行) 二.实现代码 1.冒泡排序实现主要代

冒泡排序以及冒牌排序优化算法

冒泡排序是最常用的排序算法,在笔试中也非常常见,能手写出冒泡排序算法可以说是基本的素养. 算法重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来,这样越大的元素会经由交换慢慢“浮”到数列的顶端. 时间复杂度 算法稳定性 冒泡排序就是把小的元素往前调或者把大的元素往后调.比较是相邻的两个元素比较,交换也发生在这两个元素之间.所以,如果两个元素相等,是不会再交换的:如果两个相等的元素没有相邻,那么即使通过前面的两两交换把两个相邻起来,这时候也不会交换,所以相同元素的前后顺

冒泡排序的终极改进优化

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

冒泡排序优化JAVA

本文对传统的冒泡排序进行了一些优化,减少了循环次数. 时间复杂度 若文件的初始状态是正序的,一趟扫描即可完成排序.所需的关键字比较次数 C 和记录移动次数 M 均达到最小值: C(min)=n-1 , M(min)=0 .所以,冒泡排序最好的时间复杂度为 O(n); 若初始文件是反序的,需要进行  趟排序.每趟排序要进行  次关键字的比较(1≤i≤n-1),且每次比较都必须移动记录三次来达到交换记录位置.在这种情况下,比较和移动次数均达到最大值: 冒泡排序的最坏时间复杂度为O(n^2) . 综上

求单独出现的数,冒泡排序优化,strncpy的优化

求未配对的数(1): 在一组数据中有 只有一个数出现了一次,其余的数都是成对的出现,请找出这个数:这个题很容易解决,只要把这组数据全部异或(相同为零,不同为1),所以出现两次的数异或后就为零,最后剩下的就是出现一次的数. #include<stdio.h> #include<stdlib.h> int find_once_num(int arr[], int len ) {                  int num = 0;                  for (in

【数据结构】常用排序算法(包括:选择排序,堆排序,冒泡排序,选择排序,快速排序,归并排序)

直接插入排序: 在序列中,假设升序排序 1)从0处开始. 1)若走到begin =3处,将begin处元素保存给tmp,比较tmp处的元素与begin--处元素大小关系,若begin处<begin-1处,将begin-1处元素移动到begin:若大于,则不变化.再用tmp去和begin--处的元素用同样的方法去作比较,直至begin此时减少到数组起始坐标0之前结束. 3)以此类推,依次走完序列. 时间复杂度:O() 代码如下: //Sequence in ascending order  voi