做这个系列一是记录自己的学习过程,二是整合目前我所接触的比较好的资料,给出最直观,最通俗的算法解释
总体概况
十大排序算法:(比较排序):冒泡、选择、插入、归并、快速、希尔、堆排序
基数排序、桶排序、计数排序
冒泡排序(Bubble Sort)
流程
从头开始比较相邻的一对元素,如果前者大于后者,则交换。如果前者小于后者,则不变
经过第一轮循环,最末尾的元素就是最大的元素
经过第二轮循环,倒数第二个元素为第二大的元素
……
经过N轮循环,则数组已从小到大排序
第一轮循环用代码表示
int[] array = {23, 53, 1, 32, 5, 77, 64};for (int begin = 1; begin < array.length; begin++) {
if (array[begin] < array[begin-1]){
int tmp = array[begin]; array[begin] = array[begin-1]; array[begin-1] = tmp;//交换 }}for (int i = 0; i < array.length; i++) {
System.out.print(array[i]+" ");}
首先自己定义一个数组,并用for循环进行从头到尾的遍历,这边从1开始是因为我们需要拿到begin-1的值,begin-1是非负数,所以begin从1开始
array[begin-1]为前者 array[begin] 即为后者
按我们逻辑:前者大于后者时交换,所以接下来是一个典型的交换方法
原数组:[23 , 53 , 1 , 32 , 5 , 77 , 64]
在一轮循环结束看一下数组的变化:
此时最后一位已经固定了(最大值),下一次循环循环到倒数第二位,这么依次下来需要用到外层循环(直到固定到第一位):
for (int end = array.length - 1; end > 0; end--) {
for (int begin = 1; begin <= end; begin++) {
if (array[begin] < array[begin - 1]) {
int tmp = array[begin]; array[begin] = array[begin - 1]; array[begin - 1] = tmp;//交换 } }}
这就是著名的冒泡排序!
完全有序情况优化
如果拿到的数组就是有序的,那我们还需要经历这两重for循环吗?
目前的代码不管数组是有序还是无序,都要经历整个过程
所以我们对此进行优化
在第一次扫描元素后,我们就知道数组是否有序
在开始时定义一个元素sorted = true,如果进入了循环中的if语句,则把sorted置为false
定义sorted的值我们放在外层循环中。原因是可能整个数组在开始时候有序,这是最理想的情况,还有的情况就是在循环了几次之后发现变成有序的了,这时候后面的循环就没有必要进行下去了。所以需要在每一次扫描前把sorted置为true。
for (int end = array.length - 1; end > 0; end--) {
boolean sorted = true; for (int begin = 1; begin <= end; begin++) {
if (array[begin] < array[begin - 1]) {
int tmp = array[begin]; array[begin] = array[begin - 1]; array[begin - 1] = tmp;//交换 sorted = false; } } if (sorted) break;}
显而易见,通过这种方式我们处理了在进行几次循环后完全有序的情况,确实比之前的快了不少,但是还不够优化。原因是很少能出现这种完全有序的情况。
所以遇到中间局部有序的情况,需要进一步优化
局部有序情况优化
每次扫描数据的时候,记录最后一次交换的位置
定义一个索引指向最后一次交换的位置
for (int end = array.length - 1; end > 0; end--) {
int sortedIndex = 1; for (int begin = 1; begin <= end; begin++) {