数据结构与算法复习
同样学习过C语言版,这里用java实现冒泡排序,两种方式,也可称为一种。
冒泡排序是一种非常简单的排序算法。名称缘由就是因为每次两两相邻的进行比较,一轮比较后,递增冒泡则是大的数往上冒(上浮)。
本文介绍最常见的冒泡排序和升级版冒泡排序
算法思想
以递增排序为例:
--从左往右,依次两两相邻的数进行比较
--若左边的数比右边的数大(arr[n] > arr[n + 1]),则交换。然后继续比较
--已经排好序的序列不需要再次冒泡比较。
图示分析
一个很好的图示,很形象,在此感谢贡献者。
java实现代码
第一种
注意的是:每次都是从o位置开始两两比较,每轮的冒泡比较需要排除前几轮已经排好序的数,即 j < arr.length - i - 1
/**
* 冒泡排序
*/
public static void bubbleSort(int[] arr){
int temp;
//第一个for是有多少轮冒泡
for(int i = 0;i < arr.length - 1;i++){
/*
* 第二个for是从0位置开始与相邻位置比较(冒泡)
* arr.length - i - 1表示比较的边界,并且是有i个数已经冒泡完毕,即排序好了
*/
for(int j = 0;j < arr.length - i - 1;j++){
if(arr[j] > arr[j + 1]){
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
测试代码
public static void main(String[] args) {
/*
* 获得随机8个0到99之间数的数组
*/
int[] arr = new int[8];
for(int i = 0;i < 8;i++){
arr[i] = (int) (Math.random() * 99);
}
//排序前的输出
for(int a:arr){
System.out.print(a+" ");
}
System.out.println();
bubbleSort(arr);
//排序后的输出
for(int a:arr){
System.out.print(a+" ");
}
}
同样是随机获得的8个数,这里放上两组执行结果:
第一:
63 25 65 83 77 36 92 57
25 36 57 63 65 77 83 92
第二:
39 88 50 29 85 62 31 64
29 31 39 50 62 64 85 88
第二种:升级版冒泡排序
升级版在原有的冒泡规则上加上一个变量,这个变量用于标记本次排序过程是否有交换动作,若没有交换动作说明数据元素已经全部排好序,那么就可以提前结束排序过程。
代码:
/**
* 升级版冒泡排序
*/
public static void upGradeBubbleSort(int[] arr){
int temp;
boolean isChange = true; //是否有交换,初始值为true
//在原有冒泡基础上加上isChange变量用户标记是否有交换,若没有交换说明已经是有序的则提前结束排序
for(int i = 0;i < arr.length - 1 && isChange;i++){
isChange = false; //预计下次冒泡比较没有交换
for(int j = 0;j < arr.length - i - 1;j++){
if(arr[j] > arr[j + 1]){
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
isChange = true; //有交换
}
}
}
}
这里就通过三种情况来比较普通版和升级版的效率如何,并且拥有100000个数的两个数组来作测试样本,两个算法分别排序互不干扰。
测试代码:
public static void main(String[] args) {
int arrLength = 100000; //测试数组的长度
/*
* 获得随机arrLength个数的数组
*/
int[] arr = new int[arrLength];
int[] arr_1 = new int[arrLength]; //两个排序测试使用不同的数组
for(int i = 0;i < arrLength;i++){
//随机情况
//arr[i] = (int) (Math.random() * 99);
//arr_1[i] = arr[i];
//最坏的情况
arr[i] = arrLength - i; //创建一个递减的数组
arr_1[i] = arrLength - i; //创建一个递减的数组
//最好的情况
//arr[i] = i; //创建一个有序的数组
//arr_1[i] = i; //创建一个有序的数组
}
long start = System.currentTimeMillis(); //排序开始时间
bubbleSort(arr);
long end = System.currentTimeMillis(); //排序结束时间
System.out.println("bubbleSort()花费时间:"+(end-start));
start = System.currentTimeMillis(); //升级版排序开始时间
upGradeBubbleSort(arr_1);
end = System.currentTimeMillis(); //升级版排序结束时间
System.out.println("upGradeBubbleSort()花费时间:"+(end-start));
}
第一种情况:最好的情况,即算法去排序一个有序数组。
执行结果:(执行三次结果如下)
bubbleSort()花费时间:1815
upGradeBubbleSort()花费时间:4
bubbleSort()花费时间:1804
upGradeBubbleSort()花费时间:3
bubbleSort()花费时间:1820
upGradeBubbleSort()花费时间:4
可见,升级版效率明显提高。
第二种情况:最坏的情况,算法去排序一个倒序的数组
倒序的意思是我们是递增排序,样本数组是一个递减数组
执行结果:(执行三次结果如下)
bubbleSort()花费时间:4938
upGradeBubbleSort()花费时间:4936
bubbleSort()花费时间:4946
upGradeBubbleSort()花费时间:4945
bubbleSort()花费时间:4954
upGradeBubbleSort()花费时间:4953
此时两者效率相差不大
第三种情况:平均(随机)情况,算法去排序随机产生的100000个0-99之间的数。
执行结果:(三次结果如下)
bubbleSort()花费时间:11947
upGradeBubbleSort()花费时间:12088
bubbleSort()花费时间:11986
upGradeBubbleSort()花费时间:12017
bubbleSort()花费时间:12013
upGradeBubbleSort()花费时间:12047
此时两者效率相差也不大
综上比较:升级版冒泡排序算法时间复杂度上更高效
时间复杂度与空间复杂度
冒泡排序最好的情况:就是所有的元素都是有序的,所以不需要交换。时间复杂度就是:
稳定性
冒泡排序是把小的元素往前调或者把大的元素往后调。比较是相邻的两个元素比较,交换也发生在这两个元素之间。所以,如果两个元素相等,是不会把他们俩交换的;如果两个相等的元素没有相邻,那么即使通过前面的两两交换把两个相邻起来,这时候也不会交换,所以相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。