算法之路漫漫,还只是个初学者,仅做笔记,有很多不好的地方提前致歉。
代码都已上传到git/github,其中包括在力扣上的一些题解(目前较少)以及笔记。
git:https://gitee.com/yayako/algorithm.git
github:https://github.com/yayakoBlessing/algorithm.git
官方库jar包已上传至百度云
链接:https://pan.baidu.com/s/182L-CZHq–NimCPii95zAg
提取码:xgxb
文章目录
算法比较 封装
为了方面,算法比较的方法封装的比较麻烦。
/**
* 算法比较(基于不同算法对同一数组的排序的用时比较)
*
* @param s 名称
* @param baseSorts 算法类
*/
public static void timeRandomInput(String[] s, BaseSort[] baseSorts) {
List<Comparable[]> a = new ArrayList<>(T);
Comparable[] b;
double[] total, pre = new double[s.length];
int n;
// // 专为 2.1.27 使用,生成从2^7~2^16长度的测试数组
// for (int i = 7; i <= 16; i++) {
// n = (int) Math.pow(2, i);
// 生成从100~100000数量级长度的测试数组
for (int i = 2; i <= 5; i++) {
n = (int) Math.pow(10, i);
System.out.println();
System.out.println("ArraySize = " + n);
// 每个数量级的排序都要分别进行T次,所以需要初始化T个相同长度的不同数组
for (int j = 0; j < T; j++) {
b = ArrayGenerate.random(n);
a.add(b);
}
total = SortCompare.compare(baseSorts, a, n);
for (int k = 0; k < baseSorts.length; k++) {
System.out.println(s[k] + ":" + total[k] + "\tnow/pre = " + total[k] / pre[k]);
pre[k] = total[k];
}
a.clear();
}
}
/**
* 综合比较
*
* @param baseSorts 需要进行比较的各算法类型
* @param a 排序对象数组
* @param n 数组长度
* @return 用时数组
*/
public static double[] compare(BaseSort[] baseSorts, List<Comparable[]> a, int n) {
Comparable[] b;
int j;
double[] total = new double[baseSorts.length];
for (int i = 0; i < T; i++) {
b = new Comparable[n];
j = 0;
for (BaseSort baseSort : baseSorts) {
System.arraycopy(a.get(i), 0, b, 0, n);
total[j++] = SortCompare.time(baseSort, b);
}
}
return total;
}
/** 构造随机数组 */
public static Comparable[] random(int n) {
Comparable[] a = new Comparable[n];
for (int i = 0; i < n; i++) a[i] = Math.random() * 100;
return a;
}
2.1.11
题目
将希尔排序中实时计算递增序列改为预先计算并存储在一个数组中。
评估
数组长度从100~100000数量级长度,各排序分别执行5次取其总用时
预先计算递增序列并存储在一个数组的方式只能在对小规模数组进行排序时有所优化。
代码实现
Math.log(2 * (n / 3) + 1) / Math.log(3)) + 1 这个是用数组规律算出来的长度
/**
* 将希尔排序中实时计算递增序列改为预先计算并存储在一个数组中。
*
* @author cyy
*/
public class ex11 implements BaseSort {
public static void main(String[] args) {
String[] s = {
"原版用时", "改版用时"};
BaseSort[] baseSorts = {
new Shell(), new ex11()};
SortCompare.timeRandomInput(s, baseSorts);
}
@Override
public void sort(Comparable[] a) {
int n = a.length;
int i, j, h, k;
int[] tmp = new int[(int) (Math.log(2 * (n / 3) + 1) / Math.log(3)) + 1];
for (i = 0, h = 1; i < tmp.length; i++, h = 3 * h + 1) tmp[i] = h;
for (k = 0; k < tmp.length; k++) {
for (i = h = tmp[k]; i < n; i++)
for (j = i; j >= h && Common.less(a[j], a[j - h]); j -= h) Common.exch(a, j - h, j);
}
}
}
2.1.12
题目
令希尔排序打印出递增序列的每个元素所带来的比较次数和数组大小的比值。
编写一个测试用例对随机 Double 数组进行希尔排序,验证该值是一个小常数,数组大小按照 10 的幂次递增,不小于 100。
评估
代码实现
/**
* 令希尔排序打印出递增序列的每个元素所带来的比较次数和数组大小的比值。
*
* <p>编写一个测试用例对随机 Double 数组进行希尔排序,验证该值是一个小常数,数组大小按照 10 的幂次递增,不小于 100。
*
* @author cyy
*/
public class ex12 {
private static void sort(Comparable[] a) {
int N = a.length;
System.out.println();
System.out.println("ArraySize = " + N);
int h = 1;
while (h < N / 3) h = 3 * h + 1;
int i, j, ctime;
while (h >= 1) {
ctime = 0;
for (i = h; i < N; i++) {
for (j = i; j >= h && less(a[j], a[j - h]); j -= h, ctime++) {
exch(a, j - h, j);
}
}
System.out.println(
"CompareTimeOf h ="
+ h
+ ":"
+ ctime
+ "\t\tCompareTime/ArraySize = "
+ ((float) ctime / N));
h /= 3;
}
}
public static void main(String[] args) {
for (int i = 2; i < 6; i++) {
sort(ArrayGenerate.randomDouble((int) Math.pow(10, i)));
}
}
}
2.1.24
题目
插入排序的哨兵。
在插入排序的实现中先找出最小的元素并将其置于数组的最左边,这样就能去掉内循环的判断条件 j>0。
使用 SortCompare 来评估这种做法的效果。
注意:这是一种常见的规避边界测试的方法,能够省略判断条件的元素通常称为哨兵。
评估
数组长度从100~100000数量级长度,各排序分别执行5次取其总用时
改版后的插入排序性能有所提升
代码实现
/**
* 插入排序的哨兵。 在插入排序的实现中先找出最小的元素并将其置于数组的最左边,这样就能去掉内循环的判断条件 j>0。 使用 SortCompare 来评估这种做法的效果。
* 注意:这是一种常见的规避边界测试的方法,能够省略判断条件的元素通常称为哨兵。
*
* @author cyy
*/
public class ex24 implements BaseSort {
public static void main(String[] args) {
String[] s = {
"原版用时", "改版用时"};
BaseSort[] baseSorts = {
new Insertion(), new ex24()};
SortCompare.timeRandomInput(s, baseSorts);
}
@Override
public void sort(Comparable[] a) {
int n = a.length;
int i, min = 0;
for (i = 0; i