1、冒泡排序算法
冒泡排序思想:
冒泡排序只会操作相邻的两个数据。每次冒泡操作都会对相邻的两个元素进行比较,看是否
满足大小关系要求。如果不满足就让它俩互换。一次冒泡会让至少一个元素移动到它应该在
的位置,重复 n 次,就完成了 n 个数据的排序工作。
public class SortTest {
private void swap(int[] data,int i,int j){
int tmp = data[i];
data[i] = data[j];
data[j] = tmp;
}
public void printArray(int[] data){
for(int d:data){
System.out.print(d+" ");
}
System.out.println();
}
/**
* 冒泡排序算法
*/
@Test
public void test1(){
int[] data = {55,76,34,66,22,31,13,25,90,87,56,65,66};
for(int i=0;i<data.length;i++){
boolean flag = true; //当已经有序时,不再交换排序
for (int j=0;j<data.length-1-i;j++){
if(data[j] > data[j+1]){
swap(data,j,j+1);
flag = false;
}
}
if(flag) break;
}
printArray(data);
}
}
结果:
13 22 25 31 34 55 56 65 66 66 76 87 90
分析:
1) 冒泡排序是原地排序算法吗?
冒泡的过程只涉及相邻数据的交换操作,只需要常量级的临时空间,所以它的空间复杂度为
O(1),是一个原地排序算法。
2)冒泡排序是稳定的排序算法吗?
在冒泡排序中,只有交换才可以改变两个元素的前后顺序。为了保证冒泡排序算法的稳定
性,当有相邻的两个元素大小相等的时候,我们不做交换,相同大小的数据在排序前后不会
改变顺序,所以冒泡排序是稳定的排序算法。
3)冒泡排序的时间复杂度是多少?
最好情况下,要排序的数据已经是有序的了,我们只需要进行一次冒泡操作,就可以结束
了,所以最好情况时间复杂度是 O(n)。而最坏的情况是,要排序的数据刚好是倒序排列
的,我们需要进行 n 次冒泡操作,所以最坏情况时间复杂度为 O(n^
2
)
2、插入排序算法
插入排序思想:
首先,我们将数组中的数据分为两个区间,
已排序区间
和
未排序区间
。初始已排序区间只有
一个元素,就是数组的第一个元素。插入算法的核心思想是取未排序区间中的元素,在已排
序区间中找到合适的插入位置将其插入,并保证已排序区间数据一直有序。重复这个过程,
直到未排序区间中元素为空,算法结束。
public class SortTest {
private void swap(int[] data,int i,int j){
int tmp = data[i];
data[i] = data[j];
data[j] = tmp;
}
public void printArray(int[] data){
for(int d:data){
System.out.print(d+" ");
}
System.out.println();
}
/**
* 插入排序
*/
@Test
public void test2(){
int[] data = {55,76,34,66,22,31,13,25,90,87,56,65,66};
for(int i=0;i<data.length-1;i++){
for(int j=i;j>=0;j--){
if(data[j]>data[j+1]){
swap(data,j,j+1);
}
}
}
printArray(data);
}
}
结果:
13 22 25 31 34 55 56 65 66 66 76 87 90
分析:
第一,插入排序是原地排序算法吗?
从实现过程可以很明显地看出,插入排序算法的运行并不需要额外的存储空间,所以空间复
杂度是 O(1),也就是说,这是一个原地排序算法。
第二,插入排序是稳定的排序算法吗?
在插入排序中,对于值相同的元素,我们可以选择将后面出现的元素,插入到前面出现元素
的后面,这样就可以保持原有的前后顺序不变,所以插入排序是稳定的排序算法。
第三,插入排序的时间复杂度是多少?
如果要排序的数据已经是有序的,我们并不需要搬移任何数据。如果我们从尾到头在有序数
据组里面查找插入位置,每次只需要比较一个数据就能确定插入的位置。所以这种情况下,
最好是时间复杂度为 O(n)。注意,这里是
从尾到头遍历已经有序的数据
。
3、选择排序算法
选择排序思想:
选择排序算法的实现思路有点类似插入排序,也分已排序区间和未排序区间。但是选择排序
每次会从未排序区间中找到最小的元素,将其放到已排序区间的末尾。
public class SortTest {
private void swap(int[] data,int i,int j){
int tmp = data[i];
data[i] = data[j];
data[j] = tmp;
}
public void printArray(int[] data){
for(int d:data){
System.out.print(d+" ");
}
System.out.println();
}
/**
* 选择排序
*/
@Test
public void test3(){
int[] data = {55,76,34,66,22,31,13,25,90,87,56,65,66};
for(int i=0;i<data.length;i++){
int min = data[i];
int minIndex = i;
for(int j=i+1;j<data.length;j++){
if(data[j]<min){
min = data[j];
minIndex = j;
}
}
swap(data,i,minIndex);
}
printArray(data);
}
}
结果:
13 22 25 31 34 55 56 65 66 66 76 87 90
分析:
第一,选择排序是原地排序算法吗?
选择排序算法的运行并不需要额外的存储空间,所以空间复
杂度是 O(1),也就是说,这是一个原地排序算法。
第二,选择排序是稳定的排序算法吗?
否定的,
比如 5,8,5,2,9 这样一组数据,使用选择排序算法来排序的话第一次找到最小的元素 2 与第一个元素交换,则打乱了两个相同值 5 的前后顺序
第三,选择排序的时间复杂度是多少?
。选择排序的最好情况时间复杂度、最坏情况和平均情况时间复杂度都为 O(n
2
)。