1. 冒泡排序
1.1 冒泡排序思路
每次循环,从数组第一个元素开始,对数组内的元素两两比较,若array[i]>array[i+1] 则元素交换并向后遍历,经过一轮遍历之后最大值移动到了数组尾部。经过 n-1 轮循环即可完成排序。
public void BubbleSort(int[] array,int n){
if(n<=1) return;
//外层循环n-1次
for(int i=0;i<n-1;i++){
for(int j=0;j<n-i-1;j++){
if(array[j]>array[j+1]){
int tmp = array[j];
array[j] = array[j+1];
array[j+1] =tmp;
}
}
}
}
1.2 优化思路
在上面的分析中,在数组元素完全有序之前,每一轮都会做元素的交换。也即是说,当我们进行到某一轮循环,整个过程中没有出现元素的交换,表明数组已经完全有序了,即可以终止外层循环。
public void BubbleSort2(int[] array,int n){
if(n<=1) return;
int flag = 1;
//外层循环n-1次
for(int i=0;i<n-1;i++){
if(flag==0) break;
flag = 0;
for(int j=0;j<n-i-1;j++){
if(array[j]>array[j+1]){
int tmp = array[j];
array[j] = array[j+1];
array[j+1] =tmp;
flag = 1;
}
}
}
}
1.3 算法性能分析
- 时间复杂度分析
- 最好情况时间复杂度:对于冒泡排序的最好情况是数组元素完全有序,如 1,2,3,4,5,此时基于优化的冒泡排序只需要遍历一次,因此最好时间复杂度为O(n)。
- 最坏情况时间复杂度:最坏情况是数组元素完全逆序,如5,4,3,2,1,那么需要执行n-1次循环,每个内层循环中第一次执行n-1个操作,第二次执行n-2个操作,最后一次执行1个操作;总的操作数为 1+2+3+…+(n-1) = n(n-1)/2个操作。另外说明完全逆序情况下每个操作中均包含了比较和交换。因此最坏时间复杂度为 O ( n 2 ) O(n^2) O(n2)。
- 平均时间复杂度:在上文的分析中我们发现“交换”操作是数组元素从无序到有序的必然步骤,对于完全有序的数组交换次数为0次,完全逆序的数组交换次数为n(n-1)/2次,那么平均状态下的数组交换次数为n(n-1)/4次。此外还有比较次数,比较次数大于交换次数,同时小于完全逆序的比较次数n(n-1)/4。因此平均时间复杂度为 O ( n 2 ) O(n^2) O(n2)。
- 空间复杂度分析
- 冒泡排序属于原地排序算法。所谓原地排序算法,是指不需要申请多余的存储空间,在自身数组中通过交换和比较完成排序的算法。因此原地排序算法空间复杂度为O(1)。
- 稳定性分析
- 所谓稳定,是指在原有排序数据中存在相同数值的时候,经过排序后相同数值的元素相对次序仍然不变。对于冒泡排序,我们只要在遇到相同数值元素的时候不经过交换,即可保持算法稳定性。因此冒泡排序属于稳定性算法。
2. 插入算法
2.1 插入算法思路
插入算法是把一个数组分为两部分,前面部分是已排序的部分,后面部分是未排序的部分。每次循环是从未排序部分取出第一个元素,插入到已排序部分中。
public void insertionSort(int[] array,int n){
if(n<=1) return;
int i,j;
for(i=1;i<n;i++){
int tmp = array[i];
for(j=i-1;j>=0;j--){
if(array[j]>tmp)
array[j+1]=array[j];
else
break;
}
array[j+1] = tmp;
}
}
2.2 算法性能分析
- 时间复杂度分析
- 最好情况时间复杂度:最好情况即数组元素完全有序,每次循环仅进行了一次元素比较,不涉及到元素移动。循环执行了n-1 次,因此时间复杂度为O(n)。
- 最坏情况时间复杂度:最坏情况是数组元素完全逆序,每次循环都要进行元素的比较和移动;且第一次循环执行一个操作,第二次执行2个操作,…,第n-1次执行n-1个操作。总的操作数为(n-1) = n(n-1)/2个操作。因此时间复杂度为 O ( n 2 ) O(n^2) O(n2)。
- 平均情况时间复杂度:在冒泡排序中分析平均情况时间复杂度时,我们介绍到数组序列的有序度是和交换次数等价的,然后我们拿平均情况下的交换次数来代表平均有序度的数组序列。在插入算法中,没有直接的元素交换操作,而是元素移动操作。同样的,完全有序的数组移动次数为0,完全逆序的数组移动次数为 n(n-1)/2,那么平均状态下的数组移动次数为n(n-1)/4次。因此时间复杂度也为 O ( n 2 ) O(n^2) O(n