1、冒泡排序 Bubble Sort
最简单的排序方法是冒泡排序方法。这种方法的基本思想是,将待排序的元素看作是竖着排列的“气泡”,较小的元素比较轻,从而要往上浮。在冒泡排序算法中我们要对这个“气泡”序列处理若干遍。所谓一遍处理,就是自底向上检查一遍这个序列,并时刻注意两个相邻的元素的顺序是否正确。如果发现两个相邻元素的顺序不对,即“轻”的元素在下面,就交换它们的位置。显然,处理一遍之后,“最轻”的元素就浮到了最高位置;处理二遍之后,“次轻”的元素就浮到了次高位置。在作第二遍处理时,由于最高位置上的元素已是“最轻”元素,所以不必检查。一般地,第i遍处理时,不必检查第i高位置以上的元素,因为经过前面i-1遍的处理,它们已正确地排好序。这个算法可实现如下。
算法如下:
/**
* 冒泡排序(从小到大)
* 与右边元素比较, 大于交换, 否者下一个元素
* 比较次数:
* @param a
*/
private static void bubbleSort(int[] a) {
boolean flag = true; //标志循环是否停止
//外循环最坏情况n-1次
for (int out = a.length-1; flag && out > 0; out--) {
flag = false; //没有交换
//比较out-1次
for (int in=0; in<out; in++) {
//如果左边项大于右边项,交换位置
if (a[in]>a[in+1]) {
int temp = a[in];
a[in] = a[in+1];
a[in+1] = temp;
flag = true;
}
}
//System.out.print("1 ");
}
}
2、选择排序 Selection Sort
选择排序的基本思想是:对待排序的记录序列进行n-1遍的处理,第1遍处理是将L[1..n]中最小者与L[1]交换位置,第2遍处理是将L[2..n]中最小者与L[2]交换位置,......,第i遍处理是将L[i..n]中最小者与L[i]交换位置。这样,经过i遍处理之后,前i个记录的位置就已经按从小到大的顺序排列好了。
当然,实际操作时,也可以根据需要,通过从待排序的记录中选择最大者与其首记录交换位置,按从大到小的顺序进行排序处理。
算法如下:
/**
* 选择排序
* 把最小值与每一趟的开始位置交换L[1..n]最小值与L[1]置换、L[2..n]中最小值与L[2]置换
* 最坏情况交换了n-1次
* 有什么办法把已经排好后,停下来??
* @param a
*/
private static void selectionSort(int[] a) {
int out, in, min, len = a.length;
boolean flag;
for (out=0; out<len-1; out++) {
min = out; //最小值下标
flag = false;
for (in=out+1; in<len; in++) {
if (a[min] > a[in]){
min = in; //记录最小值下标
flag = true;
}
}
if (flag) { //最左边的值和最小值交换位置
int temp = a[out];
a[out] = a[min];
a[min] = temp;
}
}
}
3、插入排序 Insertion Sort
插入排序的基本思想是,经过i-1遍处理后,L[1..i-1]己排好序。第i遍处理仅将L[i]插入L[1..i-1]的适当位置,使得L[1..i]又是排好序的序列。要达到这个目的,我们可以用顺序比较的方法。首先比较L[i]和L[i-1],如果L[i-1]≤
L[i]騆[1..i]已排好序,第i遍处理就结束了;否则交换L[i]与L[i-1]的位置,继续比较L[i-1]和L[i-2],直到找到某一个位置j(1≤j≤i-1),使得L[j]
≤L[j+1]时为止。
简言之,插入排序就是每一步都将一个待排数据按其大小插入到已经排序的数据中的适当位置,直到全部插入完毕。插入排序方法分直接插入排序和折半插入排序两种,这里只介绍直接插入排序,折半插入排序留到“查找”内容中进行。
图1演示了对4个元素进行直接插入排序的过程,共需要(a),(b),(c)三次插入。
图1 对4个元素进行插入排序
在下面的插入排序算法中,为了写程序方便我们可以引入一个哨兵元素L[0],它小于L[1..n]中任一记录。所以,我们设元素的类型ElementType中有一个常量-∞,它比可能出现的任何记录都小。如果常量-∞不好事先确定,就必须在决定L[i]是否向前移动之前检查当前位置是否为1,若当前位置已经为1时就应结束第i遍的处理。另一个办法是在第i遍处理开始时,就将L[i]放入L[0]中,这样也可以保证在适当的时候结束第i遍处理。下面的算法中将对当前位置进行判断。
算法如下:
/**
* 插入排序(从小到大)
* 元素左边的序列有序, 向左端有序列插入
* 和冒泡相反的是比较元素左边元素的大小
* @param a
*/
private static void insertSort(int[] a) {
int out, in, len = a.length;
for (out=1; out < len; out++) {
int temp = a[out]; //下标为out,腾出位置
//此处的in可能取值为-1
for (in=out; in>0; in--) {
if (temp<a[in-1]) {
a[in] = a[in-1]; //前面的位置后移
}else {
break; //位置已经腾好,等待插入
}
}
a[in] = temp; //找到腾出的位置,插入待排项
}
}
private static void insertSort2(int[] a) {
int out, in, len = a.length;
for (out=1; out < len; out++) {
int temp = a[out];
in = out;
while(in>0 && a[in-1]>=temp) {
a[in] = a[in-1];
--in;
}
a[in] = temp;
}
}