经典冒泡排序及其优化

经典排序算法 – 冒泡排序Bubble sort

原理是临近的数字两两进行比较,按照从小到大或者从大到小的顺序进行交换,这样一趟过去后,最大或最小的数字被交换到了最后一位,然后再从头开始进行两两比较交换,直到倒数第二位时结束,其余类似,看例子。

例子为从小到大排序,为了便于观察,选取

原始待排序数组:| 6 | 2 | 4 | 1 | 5 | 9 |

第一趟排序(外循环)

第一次两两比较6 > 2交换(内循环)

交换前状态| 6 | 2 | 4 | 1 | 5 | 9 |

交换后状态| 2 | 6 | 4 | 1 | 5 | 9 |

 

第二次两两比较,6 > 4交换

交换前状态| 2 | 6 | 4 | 1 | 5 | 9 |

交换后状态| 2 | 4 | 6 | 1 | 5 | 9 |

 

第三次两两比较,6 > 1交换

交换前状态| 2 | 4 | 6 | 1 | 5 | 9 |

交换后状态| 2 | 4 | 1 | 6 | 5 | 9 |

 

第四次两两比较,6 > 5交换

交换前状态| 2 | 4 | 1 | 6 | 5 | 9 |

交换后状态| 2 | 4 | 1 | 5 | 6 | 9 |

 

第五次两两比较,6 < 9不交换

交换前状态| 2 | 4 | 1 | 5 | 6 | 9 |

交换后状态| 2 | 4 | 1 | 5 | 6 | 9 |

 

第二趟排序(外循环)

第一次两两比较2 < 4不交换

交换前状态| 2 | 4 | 1 | 5 | 6 | 9 |

交换后状态| 2 | 4 | 1 | 5 | 6 | 9 |

 

第二次两两比较,4 > 1交换

交换前状态| 2 | 4 | 1 | 5 | 6 | 9 | 
交换后状态| 2 | 1 | 4 | 5 | 6 | 9 |

 

第三次两两比较,4 < 5不交换

交换前状态| 2 | 1 | 4 | 5 | 6 | 9 | 
交换后状态| 2 | 1 | 4 | 5 | 6 | 9 |

 

第四次两两比较,5 < 6不交换

交换前状态| 2 | 1 | 4 | 5 | 6 | 9 |

交换后状态| 2 | 1 | 4 | 5 | 6 | 9 |

 

第三趟排序(外循环)

第一次两两比较2 > 1交换

交换后状态| 2 | 1 | 4 | 5 | 6 | 9 |

交换后状态| 1 | 2 | 4 | 5 | 6 | 9 |

 

第二次两两比较,2 < 4不交换

交换后状态| 1 | 2 | 4 | 5 | 6 | 9 | 
交换后状态| 1 | 2 | 4 | 5 | 6 | 9 |

 

第三次两两比较,4 < 5不交换

交换后状态| 1 | 2 | 4 | 5 | 6 | 9 | 
交换后状态| 1 | 2 | 4 | 5 | 6 | 9 |

 

第四趟排序(外循环)无交换

第五趟排序(外循环)无交换


排序完毕,输出最终结果1 2 4 5 6 9


下面是代码实现(仅供参考),为了更直观地表示优化结果,选取

原始待排序数组:|2|1|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|

public class BubbleSort2 {
	public int[] bubbleSort(int[] A, int n) {
		boolean flag = true;
		for (int i = 0; i < n && flag; i++) {
			flag = false;
			for (int j = i; j < n; j++) {
				if (A[i] > A[j]) {
					int temp = A[i];
					A[i] = A[j];
					A[j] = temp;
					flag = true;
				}
			}
		}
		return A;
	}

	public static void main(String args[]) {
		int A[] = { 2, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
				18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 };
		int n = A.length;
		BubbleSort bubbleSort = new BubbleSort();
		double start = System.currentTimeMillis();
		int B[] = bubbleSort.bubbleSort(A, n);
		for (int i = 0; i < n; i++)
			System.out.print(B[i] + ",");
		double end = System.currentTimeMillis();
		System.out.println("\n程序运行时间:" + (end - start) + "毫秒");
	}
}

输出:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,

程序运行时间:1.0毫秒

显然,这样的程序是有问题的。因为除了第一和第二个关键字需要交换外,别的都已经是正常顺序,,当 i=1 时,交换了2和1,此时序列已经有序,但是算法仍然不依不饶地将 i=2 到 i=29 比较一遍。尽管并没有交换数据,但是之后的大量比较还是大大多余了。


public class BubbleSort2 {
	public int[] bubbleSort(int[] A, int n) {
		boolean flag = true;// flag作为标记
		for (int i = 0; i < n && flag; i++) {// 当flag为true时退出循环
			flag = false;// 初始flag为false
			for (int j = i; j < n; j++) {
				if (A[i] > A[j]) {
					int temp = A[i];
					A[i] = A[j];
					A[j] = temp;
					flag = true;// 如果有数据交换,则flag为true
				}
			}
		}
		return A;
	}

	public static void main(String args[]) {
		int A[] = { 2, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
				18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 };
		int n = A.length;
		BubbleSort bubbleSort = new BubbleSort();
		double start = System.currentTimeMillis();
		int B[] = bubbleSort.bubbleSort(A, n);
		for (int i = 0; i < n; i++)
			System.out.print(B[i] + ",");
		double end = System.currentTimeMillis();
		System.out.println("\n程序运行时间:" + (end - start) + "毫秒");
	}
}

输出:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,
程序运行时间:0.0毫秒


由此可见,稍微加个flag,程序运行时间缩短了。

点赞