【学习笔记】八大排序(待更新)
一、 冒泡排序
1.什么是冒泡排序?
冒泡排序的英文是Bubble Sort ,是一种最基础的交换排序,之所以叫冒泡排序,是因为每个元素都可以像小气泡一样,根据自身大小一点一点地向数组一侧移动。
每一趟只能确定将一个数归位,即第一趟只能确定将末尾上的数归位,第二趟只能将倒数第二位上的数归位,以此类推下去。如果有 n 个数进行排序,只需将 n-1 个数归位,也就是要进行n-1 趟操作。
而每一趟都需要从第一位开始进行相邻的两个数的比较,将较大的数放后面,比较完毕之后向后挪一位继续比较下面两个相邻的数大小关系,重复此步骤,直到最后一个还没归位的数。
2.动图展示
3.时间复杂度
比较4个数排完序需要3趟,第一趟需要比较三次,第二趟需要比较两次,第三趟需要比较一次,总共需要比较3+2+1 = 6次
如果有n个数,则需要比较 (n-1)+(n-2)+......2+1次,显然这是一个等差数列
根据复杂度的规则,去掉最低价项(n/2),且去掉常数系数,可以得到复杂度为O(n^2)
4.冒泡排序初始版
package com.wzt.array;
import java.util.Arrays;
public class ArrayDemo04 {
public static void main(String[] args) {
int[] a = {23,14,6,89,77,3};
int[] result = bubbleSort(a);
System.out.println(Arrays.toString(result));
}
public static int[] bubbleSort(int[] array){
int temp = 0;
for (int i = 0; i < array.length-1; i++) { //外层循环控制的是趟数
for (int j = 0; j < array.length-(i+1); j++) { //里层循环控制的是每趟比较的次数 其中i+1是第几趟
if (array[j] > array[j+1]){
temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
}
}
}
return array;
}
}
存在的问题
如果在第二趟结束后数组已经有序,如下
[23,14,6,89,77] 第一趟-------> [14,6,23,77,89] 第二趟-------> [6,14,23,77,99]
那么按照以上代码,算法依旧会兢兢业业地执行第三趟、第四趟,造成了时间上的浪费
我们可以利用布尔量作为标记,如果在本轮排序中,元素有交换,则说明数列无序,如果没有元素交换,说明元素已经有序,直接跳出大循环
package com.wzt.array;
import java.util.Arrays;
public class ArrayDemo04 {
public static void main(String[] args) {
int[] a = {23,14,6,89,77,3};
int[] result = bubbleSort(a);
System.out.println(Arrays.toString(result));
}
public static int[] bubbleSort(int[] array){
int temp = 0;
for (int i = 0; i < array.length-1; i++) { //外层循环控制的是趟数
boolean flag = false;
for (int j = 0; j < array.length-(i+1); j++) { //里层循环控制的是每趟比较的次数 其中i+1是第几趟
if (array[j] > array[j+1]){
flag = true; //如果发生了元素交换,则令flag为true
temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
}
}
//执行完一趟之后,判断是否有元素交换,有则说明数组无序,没有说明有序,直接跳出大循环
if(!flag){
break;
}
}
return array;
}
}
新问题
如果数组中前半部分是无序的,而后半部分是有序的,比如(3,4,2,1,5,6,7,8),这个数组后半部分许多元素已经有序,但每一趟依然往后比较了许多次
第一趟:
3和4比较,3小于4,不用交换
然后4与2 比较 ,4大于2,交换位置
然后4与1比较,交换位置
然后,后面是有序数组,但依旧需要两两比较
4与5比较,5与6比较,6与7比较,7与8比较
然后进入第二趟
第二趟:
3与2比较,交换位置
3与1比较,交换位置
然后发现,后面又是有序数组了
3与4比较,4与5比较,....... 白白比较了很多次
如何优化?
对于这个问题,关键在于数列有序区的界定,如果按照冒泡排序代码原始版分析的话,有序区的长度和排序的轮数是相等的,比如第一轮排序后,有序区长度是1,第二轮排序后有序区长度是2......
但是,实际数列有序区会大于这个数,也就是上面的例子,第二轮中,后面5个数都在有序区内,因此后面的比较就没有意义了。
我们可以这样做来避免这种情况,在每一轮排序的最后,记录一下最后一次元素交换的位置,那个位置是无序区数列的边界,在往后就是有序区了。
package com.wzt.array;
import java.util.Arrays;
public class ArrayDemo04 {
public static void main(String[] args) {
int[] a = {23,14,6,89,77,3};
int[] result = bubbleSort(a);
System.out.println(Arrays.toString(result));
}
public static int[] bubbleSort(int[] array){
int temp = 0;
//无序数列的边界,再往后就是有序区了
int indexBorder = array.length-1;
//记录每一次元素交换的位置
int location = 0;
for (int i = 0; i < array.length-1; i++) { //外层循环控制的是趟数
boolean flag = false;
for (int j = 0; j < indexBorder; j++) { //比较到哪个地方的位置
if (array[j] > array[j+1]){
flag = true; //如果发生了元素交换,则令flag为true
temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
location = j; //记录最后一次元素交换的位置
}
}
indexBorder = location; //把元素交换的位置给无序数列的边界
//执行完一趟之后,判断是否有元素交换,有则说明数组无序,没有说明有序,直接跳出大循环
if(!flag){
break;
}
}
return array;
}
}