算法和语言无关、学习路径从线性(排序),树形结构,图形结构慢慢学~
在强调数据结构的重要性后,其中算法思想也是不容忽略:
以上所举的例子可以看出数据结构和算法之间的互相依托程度,例如在学习归并、快速排序时,实则也在探究分治算法……
每个细分领域都是算法,例如以下例子:
public static void sort(int[] arr){
int len = arr.length;
for(int i = 0; i < len; i ++){
int minIndex = i;
for(int j = i + 1; j < len; j ++){
if(arr[minIndex] > arr[j])
minIndex = j;
}
swap(arr, minIndex, i);
}
}
对于上述代码,只能适用于int类型,而不是能用于double,自定义类型排序。
public static void sort(Comparable[] arr){
int len = arr.length;
for(int i = 0; i < len; i ++){
int minIndex = i;
for(int j = i + 1; j < len; j ++){
if(arr[j].compareTo(arr[minIndex]) < 0)
minIndex = j;
}
swap(arr, minIndex, i);
}
}
随机生成算法
//生成有n个元素的随机数组,每个元素的随机范围为[rangL, rangR]
public static Integer[] generateRandomArray(int n, int rangL, int rangR){
assert rangL <= rangR;
Integer[] arr = new Integer[n];
for(int i = 0; i < n; i ++){
arr[i] = new Integer((int)(Math.random() * (rangR- rangL + 1) + rangL));
}
return arr;
}
测试性能算法
public static void testSort(String sortClassName, Comparable[] arr){
try {
//通过sortClassName获得排序函数的class对象
Class sortClass = Class.forName(sortClassName);
//通过排序函数Class对象获得排序方法
Method sortMethod = sortClass.getMethod("sort", new Class[]{Comparable[].class});
//排序参数只有一个,就是可比较的额数组
Object[] params = new Object[]{arr};
long startTime = System.currentTimeMillis();
sortMethod.invoke(null, params);
long endTime = System.currentTimeMillis();
assert isSorted(arr);
System.out.println(sortClass.getSimpleName() + ":" + (endTime - startTime) + "ms");
}catch (Exception e){
e.printStackTrace();
}
}
测试:
public static void main(String[] args) {
int N = 20000;
Integer[] arr = SortTestHelper.generateRandomArray(N, 0, 100000);
SortTestHelper.testSort("wang.sort.SelectionSort03.SelectionSort", arr);
return;
}
1. 代码实现注意:
public static void sort(Comparable[] arr) {
int n = arr.length;
for (int i = 1; i < n; i++) {
//寻找arr[i]的最佳插入位置
for(int j = i; j > 0 && arr[j].compareTo(arr[j-1]) < 0; j --){
//要是不熟悉泛型的话,直接写arr[i] < arr[j-1]
swap(arr, j, j-1);
}
/* 寻找元素arr[i]合适的插入位置 写法二
for( int j = i ; j > 0 ; j-- )
if( arr[j] < arr[j-1] )
swap( arr, j, j-1 );
else
break;
*/
}
}
插入排序的内循环在满足条件的情况下是可以提前结束的!而选择排序必须遍历每一次循环。所以插入排序理论上比选择排序更快一些。(比如一个值已经比插入点要大了,而它之后的点还比这个值大,那么就不用遍历前面而直接结束了,而选择排序里的for循环必须是len长度,要整个遍历一遍才行~)
在实际测试中,插入排序比选择排序稍微慢,原因是插入在执行内循环每次都执行了swap操作,这样会更耗时,其实涉及了三次赋值,更别说数组中索引值访问等消耗时间。
优化: 避免在内循环中使用swap,只进行一次赋值操作,在内循环结束后再进行一次赋值操作。逻辑并没有变,只是将之前的一次次交换修改成赋值操作、性能得到提高。
public static void sort(Comparable[] arr){
int n = arr.length;
for(int i = 1; i < n; i ++){
Comparable e = arr[i];
int j = i;
for( ; j > 0 && arr[j-1].compareTo(e) > 0; j --){
arr[j] = arr[j-1];
}
arr[j] = e;
}
}
所以一般来说,插入排序的优异性是因为在内循环中可以提前结束,所以在部分有序数组中进行排序效果会更好~
在20000个数据,依次是无序,稍微有序,几乎有序的情况下测试、提升到80000个数据继续测试、
可以发现,无序时,查找排序和优化后的插入排序差不多,而在几乎有序的情况下,插入排序的高效性。