- 1、O(n^2)排序算法之选择排序**
- 2、O(n^2)排序算法之插入排序**
一、选择排序
-
1、实现思路: 从最左边下标开始,将该下标的元素和它右边所有元素比较,每一趟遍历找出最小元素的下标,然后将最小下标的元素和该下标元素互换,即每一趟遍历都将最小值放在开始遍历的最左的下标位置
-
2、int类型数组的选择排序算法
/**
*
* @author eric
* 从最左边下标开始,将该下标的元素和它右边所有元素比较,每一趟遍历找出最小元素的下标
* 然后将最小下标的元素和每一趟遍历开始的最左边下标的元素互换,即每一趟遍历都将最小值放在开始遍历的最左的下标位置
*/
public class SelectionSort {
// 我们的算法类不允许产生任何实例
private SelectionSort() {
}
public static void sort(int[] arr) { // 左边要比较到倒数第二个下标
int len = arr.length;
for (int i = 0; i < len - 1; i++) {
// 寻找[i, n)区间里的最小值的索引
int minIndex = i;
for (int j = i + 1; j < len; j++) {
// 每一趟遍历找出最小元素的下标
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
// 交换开始遍历的最左和最小下标的元素
if (i != minIndex) {
swap(arr, i, minIndex);
}
}
}
/**
* 交换两个下标的元素
*
* @param arr 要排序的数组
* @param i 下标1
* @param j 下标2
*/
private static void swap(int[] arr, int i, int j) {
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
}
-
3、实现了Comparable接口的类,支持泛型排序
- 1、实现了Comparable接口的类
/** * * @author eric * */ // 实现了Comparable接口的类,支持排序 public class Student implements Comparable<Student> { private String name; private int score; public Student(String name, int score) { this.name = name; this.score = score; } // 定义Student的compareTo函数 // 如果分数相等,则按照名字的字母序排序 // 如果分数不等,则分数高的靠前 @Override public int compareTo(Student that) { if (this.score == that.score) return this.name.compareTo(that.name); if (this.score < that.score) return 1; else if (this.score > that.score) return -1; else // this.score == that.score return 0; } // 定义Student实例的打印输出方式 @Override public String toString() { return "Student: " + this.name + " " + Integer.toString(this.score); } }
-
2、支持泛型排序实现类
public class SelectionSort2 { // 我们的算法类不允许产生任何实例 private SelectionSort2(){} /** * 支持泛型比较 * @param arr */ public static <T extends Comparable<T>> void sort(T[] arr){ int len = arr.length; for (int i = 0; i < len - 1; i++) { // 寻找[i, n)区间里的最小值的索引 int minIndex = i; for (int j = i + 1; j < len; j++) { // 使用compareTo方法比较两个Comparable对象的大小 if (arr[j].compareTo(arr[minIndex]) < 0) { minIndex = j; } } swap(arr, i, minIndex); } } private static void swap(Object[] arr, int i, int j) { Object t = arr[i]; arr[i] = arr[j]; arr[j] = t; } public static void main(String[] args) { // 测试Integer Integer[] a = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }; SelectionSort2.sort(a); for (int i = 0; i < a.length; i++) { System.out.print(a[i]); System.out.print(' '); } System.out.println(); // 测试Double Double[] b = { 4.4, 3.3, 2.2, 1.1 }; SelectionSort2.sort(b); for (int i = 0; i < b.length; i++) { System.out.print(b[i]); System.out.print(' '); } System.out.println(); // 测试String String[] c = { "D", "C", "B", "A" }; SelectionSort2.sort(c); for (int i = 0; i < c.length; i++) { System.out.print(c[i]); System.out.print(' '); } System.out.println(); // 测试自定义的类 Student Student[] d = new Student[4]; d[0] = new Student("D", 90); d[1] = new Student("C", 100); d[2] = new Student("B", 95); d[3] = new Student("A", 95); SelectionSort2.sort(d); for (int i = 0; i < d.length; i++) System.out.println(d[i]); } }
二、插入排序
-
1、普通插入排序实现思路:从右边开始起将相邻元素两两比较后排序。第一趟将最左边两个元素比较排序,右边的大于(或小于)左边的话,两者调换元素位置;第二趟从最左边三个元素右边开始将两两比较排序,… 最后一次是所有元素的相邻元素从右边开始将两两比较排序
for (int i = 1; i < len; i++) { // 寻找元素arr[i]合适的插入位置 for( int j = i; j > 0 && arr[j].compareTo(arr[j-1]) < 0 ; j--) { swap(arr, j, j-1); } }
-
改进版插入排序:
- 耗时改进点:每次两两比较后如果有需要都互换位置(耗时:交换每次都需要三次赋值操作,访问数组和访问相应下标的数组数据),改进后每次将每次都要交换操作变成有必要时一次赋值来节省时间
- 实现思路:因为每一趟遍历排序后(0 —> i-1下标的元素已排好序); 下一趟开始遍历前先复制一份i 下标的元素,然后将i 下标元素和 i - 1 下标元素比较,没互换的需要,此趟直接排序完成(非常省时);如有需要互换,将 i - 1下标元素放到 i 下标位置,原复制出来的 i 下标元素值再和 i - 2下标元素比较,如有需要互换,将 i - 2 下标元素放到 i - 1 下标位置;没需要互换,将复制出来的 i 下标元素值放在 i - 1 下标位置,此趟排序完成 … 即上一趟排好序的数不断往前推, i 下标元素找到属于自己的位置, 就是每一趟排序完成。
int j; for(int i = 1; i < intArray.length; i++){ int temp = intArray[i]; j = i; while (j > 0 && temp < intArray[j-1]){ intArray[j] = intArray[j-1]; j--; } intArray[j] = temp; }
-
时间复杂度:==> 对于几乎有序的数组,插入排序效果非常高,时间复杂度近乎O(n)