您的位置:首页 > 其它

蛮力算法: 选择排序 冒泡排序(详解)

2015-10-26 20:39 169 查看

蛮力法:

蛮力法(brute force)是一种简单直接地解决问题的方法,常常直接基于问题的描述和所涉及的概念定义。

虽然巧妙而高效的算法很少来自于蛮力法,但它还是具有重要地位。因为它能解决几乎任何问题,如果要解决的问题的规模不大,或者对性能没有很高的要求,那么花大工夫涉及复杂的算法显然是不值得的。

下面就来介绍一下2大蛮力排序算法,然后是它们的分析。

框架介绍:

在介绍算法之前,有必要介绍一些以后会用到的方法。

使用前2个方法,我们就可以生成随机数组,然后方便地判断数列是否被正确排序了,以此验证排序算法的正确性

第3个方法从标准输入中读取数据(通过重定向),进行大规模排序,以此比较不同算法的性能

/**
* 生成一个长度为0~600的数组,每个元素的值为0~99999的整数。
*
* @return
*/
public static Integer[] randomArray() {
Integer[] r = new Integer[(int) (600 * Math.random())];
for (int i = 0; i < r.length; i++)
r[i] = (int) (99999 * Math.random());
return r;
}

/**
* 返回一个数组是否是有序的。
* @param r
* @return
*/
public static boolean isSorted(Integer[] r) {
for (int i = 1; i < r.length; i++)
if (r[i].compareTo(r[i - 1]) < 0)
return false;
return true;
}

/**
* 从标准输入中读取1000000个整数的数组。
* @return
*/
public static Integer[] arrayIn(){
Scanner in = new Scanner(System.in);
Integer[] r = new Integer[1000000];
for(int i=0;i<1000000;i++)
r[i] = in.nextInt();
return r;
}


选择排序:

选择排序开始的时候,我们扫描整个列表,找到它的最小元素,然后和第一个元素交换(如果第一个元素就是最小元素,那么它就和自己交换。)。再次,在剩下的元素中找到最小元素,将它和数组的第二个元素交换位置,以此往复,直到整个数组有序。这种算法叫做选择排序,因为它每次都选择剩余元素之中最小的元素放在正确位置

public static void selection(Integer[] r) {
int N = r.length;
for (int i = 0; i < N - 1; i++) {
int min = i;//已知最小元素的索引
for (int j = i + 1; j < N; j++)
if (r[min] > r[j])//如果找到更小的元素,更新索引
min = j;
int temp = r[i];//交换位置
r[i] = r[min];
r[min] = temp;
}
}


算法分析:

对于长度为N的数组,选择排序需要大约(N^2-N)次比较和N次交换。

选择排序是一种容易理解和实现的简单排序算法:

1. 它的运行时间和输入无关: 也就是说,一个有序的数组和一个随机排序的数组所用的排序时间是相同的!对于任何输入来说,选择排序都是一个O(N^2)的算法。

2. 数据移动是线性的: 键的交换次数仅为O(N), 准确的是说n-1此,这个特点使得选择排序优于很多其他算法。

冒泡排序:

另一个非常直观的方法是冒泡排序,它比较表中的相邻元素,如果它们是逆序的话,就交换它们的位置。重复多次之后,最大的元素就“沉到”列表最后一个位置。第二遍操作将第二大的元素“沉下去”。第n-1遍之后,该列表就排好序了。

public static void bubble(Integer[] r) {
int N = r.length;
for (int i = 0; i < N - 1; i++) //第i遍,每次沉下一个最大的元素
for (int j = 0; j < N - 1 - i; j++) //扫描数组
if (r[j] > r[j + 1]) {//如果逆序就交换
int temp = r[j];
r[j] = r[j + 1];
r[j + 1] = temp;
}
}


算法分析:

对于大小为N的数组,冒泡排序的比较次数和选择排序一样大约为(N^2)/2, 但它的交换次数取决于特定的输入。最坏情况下就是遇到降序数组,这时交换次数和比较次数一样大约是(N^2)/2。根据冒泡排序的特点,我们可以提出下面的改良方案。

改良方案:

如果对列表比较一遍之后没有交换元素的位置,那么这个表已经有序,我们就可以停止这个算法了。

虽然对于某些输入,这个版本的冒泡排序可以比较快,但是最坏情况平均情况下,它依然是个时间复杂度为O(N^2)的算法。

但不管怎么样,冒泡排序除了名字好听之外,也就并没有什么优点了。它不是一个好的选择。

总结:

main函数代码如下,循环生成随机整数数组,进行排序,然后验证。

public static void main(String[] args) {
while (true) {
Integer[] r = randomArray();
//selection(r);
//bubble(r);
for (int x : r)
System.out.print(x + " ");
System.out.println("\n" + isSorted(r) + "\t" + r.length);
if(!isSorted(r))    break;
}
}


对于随机排序的无重复主键的数组,它们的运行时间是平方级别的O(N^2)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: