一. 冒泡排序(Bubble Sort)
1. 优点:
简单.
2. 缺点
运行十分缓慢,效率低.
3. 思路:
点击此处,演示执行流程
比较相邻两个队员. 如果左边高于右边, 交换位置, 否则不变. 一圈比较下来最高的跑到了最后面; 第二圈忽略最后面的那个数(因为它已经是最大的了), 再从左边开始比较相邻两个数…如此循环
4. 核心代码:
public void testBubbleSort(){
int[] arr = {33,44,22,11,55};
// 外圈循环一次, 最大的"冒泡"到最后边
for(int i=0; i<arr.length-1; i++){
// 内圈循环是为了比较相邻两个数
for(int j=0; j<arr.length-i-1; j++){
if(arr[j]>arr[j+1]){
// 交换位置
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
for(int a : arr){
System.out.print(a+" ");
}
}
5. 时间复杂度
假设有10个数, 第一圈比较9次, 第二圈比较8次…总共下来是:9+8+7+6+5+4+3+2+1=45次.
一般来说, 数组中有N个数据项, 第一趟排序中有N-1次比较, 第二趟中有N-2次比较, 以此类推. 这种求和公式如下:
这样, 算法作了N^2次比较.(忽略减1,当N很大时,不会有很大差别)
平均下来, 大约有一般的数据要进行交换, 则交换次数为N^2/4.(就算在最坏的逆序情况下,比较数等于交换数)
无论何时,只要看到一个循环嵌套在另一个循环里, 例如在冒泡排序和其他排序中, 就可以怀疑这个算法的运行时间为O(N^2)级.这就意味着大约需要执行N*N或者N^2次某个基本操作.
二. 选择排序(Select Sort)
1. 优点
改进冒泡排序, 将必要交换次数从O(N^2)减少到O(N).
2. 缺点
比较次数仍然为O(N^2).
3. 思路
点击此处,演示执行流程
把所有队员都扫描一遍, 从中挑出来最矮的一个队员. 让最矮的队员和最左边的队员交换位置.所以最左边的队员就是有序的了.注意:这个算法中有序的队员都排在队列的左边(较小的下标值), 而在冒泡排序中有序的是队列右边的数据.
再次扫描队员时,就从1号位置开始(0号已是最矮), 还是寻找最矮的, 然后和1号位置队员交换. 这个过程一只持续到所有队员都排定.
注意:
挑出来最小的, 并不是记录它的值, 而是记录下来他的索引位置, 然后和最左边的索引进行交换.
4. 核心代码
public void testSelectSort(){
int[] arr = {33,44,22,11,55};
// 外圈, 为了让左边和最小值进行交换(而寻找最小值是内圈的任务)
for(int i=0; i<arr.length-1; i++){
// 将最左边的索引记录给min
int min = i;
for(int j=i+1; j<arr.length; j++){
// 找出最小
if(arr[j]<arr[min]){
min = j;
}
// 交换位置
int temp = arr[min];
arr[min] = arr[i];
arr[i] = temp;
}
}
for(int each : arr){
System.out.print(each+" ");
}
}
5. 时间复杂度
选择排序和冒泡排序进行了相同次数的比较N*(N-1)/2. 对于10个数据项, 需要比较45次.然而, 10个数据项只需要少于10次的交换.
当N值很大时, 比较次数是主要的, 所以结论是选择排序和冒泡排序一样运行了O(N^2)时间. 但是, 无疑是选择排序效率更高, 因为它的实际交换次数少.
三. 插入排序(Insert Sort)
1. 优点
平均情况下,速度快于冒泡和选择(完全逆序除外).
2. 缺点
较于冒泡和选择稍微复杂.
3. 思路
点击此处,演示执行流程
取出一个(等待被插入)值赋值给一个临时变量, 然后将这个临时变量和它左边的值作比较, 如果左边的值大于这个临时值, 则将左边的值向右移动.否则就将临时值插入到这个位置. 一轮循环到此结束, 接下来再将上一个(等待被插入)的值的下一个值取出来作为新的(等待被插入的值),再次执行上边的步骤.如此循环, 直至全部有序.
举个例子: 就像整理书架上的书籍一样, 以几本有序的为基准, 将它右边的书本一本一本拿出来, 然后将有序的向右推, 将取出的书本插入到有序的合适的位置.(又有点像整理扑克牌一样)
4. 核心代码
public void testInsertSort(){
int i,j;
for(i=1;i<arr.length;i++){
// 记录下来被取出(等待被插入)的值
int temp = arr[i];
j=i;
// 拿这个被取出的值和它左边的值比较, 如果左边的值大于它,将左边的值向右移动一位
while(j>0&&arr[j-1]>=temp){
arr[j] = arr[j-1];
--j;
}
// 最后将等待被插入的值插入到合适的索引位
arr[j] = temp;
}
for(int each: arr){
System.out.print(each + " ");
}
}