写在笔记前面的话:笔记中用到的一些方法是算法第四版提供的stdlib.jar里的,大家可以点这里去官网下载
如果发生导入jar包后无法引用的情况,参考网页最下面的 Q&A 点击下载stdlib-package.jar再导入就行了
之前写排序算法时,比较,交换等步骤都写在一起,每个算法里面都要单独写一遍比较,交换,今天看了算法第四版,它的排序类算法都极其简洁,将比较,交换,判断是否有序,打印都单独写成方法以供调用,看过之后收益颇丰,现将模板整理如下。
//比较
Public static boolean less(Comparable c1, Comparable c2){
return c1.compareTo(c2) < 0;
}
//交换
Public static void exec(Comparable[] c,int I, int j){
Comparable c1 = c[i];
c[i] = c[j];
c[j] = c1;
}
//判断是否有序
Public static boolean isSorted(Comparable[] c){
for(int I = 0; I < c.length; i++){
if(less(c[i+1],c[i])) return false;
}
return true;
}
//单行中打印数组
Public static void show(Comparable[] c){
for(int I = 0; I < c.length; i++)
// StdOut是算法第四版中集成的打印类,也可以自己换成普通的打印方法
StdOut.print(a[i] + “”);
StdOu.println();
}
//main方法
Public static void main(String[] args){
得到初始数组c;
sort(c);
//若无序则中断程序,没搞明白为什么要加上这个
assert isSorted(c);
show(c);
}
顾名思义,即每次将一个最小值选择出来放在前面。
比如将数组【1,4,2,3,7,5】排序
step1:从第一个坑开始遍历数组,选出最小值1,放在第一个坑里面
step2:从第二个坑开始遍历数组,选出最小值2,放在第二个坑里面
.
.
.
step5:从第五个坑开始遍历数组,选出最小值5,放在第五个坑里面
现将代码整理如下
Selection 类
```
package sort;
/*
* 选择排序,每次循环选出最小值,将其依次插入
*/
public class Selection {
public static void sort(Comparable[] c) {
SortBasicClass sbc = new SortBasicClass();
for (int i = 0; i < c.length -1; i++) {
int min = i;
for (int j = i + 1; j < c.length; j++) {
//less方法,比较
if (sbc.less(c[j], c[min])) {
min = j;
}
}
//exec方法,交换
sbc.exec(c, i, min);
}
}
}
```
SortBasicClass类(前面所说的模板类,实现了比较,交换等必用的功能)
```
package sort;
import edu.princeton.cs.introcs.StdOut;
public class SortBasicClass {
// less方法,比较
public static boolean less(Comparable c1, Comparable c2) {
return c1.compareTo(c2) < 0;
}
// exec方法,交换
public static void exec(Comparable[] c, int i, int j) {
Comparable c1 = c[i];
c[i] = c[j];
c[j] = c1;
}
// isSorted方法,检查是否有序,若否则终止程序
public static boolean isSorted(Comparable[] c) {
for (int i = 0; i < c.length; i++) {
for (int j = i + 1; j < c.length; j++) {
if (less(c[j], c[i]))
return false;
}
}
return true;
}
// show方法,打印有序集合
public static void show(Comparable[] c) {
for (int i = 0; i < c.length; i++)
StdOut.print(c[i] + ",");
StdOut.println();
}
}
```
SortTestClass类(测试类,main方法)
```
package sort;
import java.util.Random;
import java.util.Scanner;
import edu.princeton.cs.introcs.StdRandom;
public class SortTestClass {
public static void main(String args[]) {
SelectionTest();
}
// 选择排序的测试,这里需要从控制台输入待排数据
public static void SelectionTest() {
System.out.println("please input...");
Scanner sc = new Scanner(System.in);
char[] ch = sc.nextLine().toCharArray();
Comparable[] c = new Comparable[ch.length];
for (int i = 0; i < ch.length; i++) {
c[i] = ch[i];
}
Selection.sort(c);
assert SortBasicClass.isSorted(c);
SortBasicClass.show(c);
}
}
```
将数组分为有序和无序两个部分,依次将无序部分的元素插入有序部分合适的位置中去。
同样以数组【1,4,2,3,7,5】为例
step1:有序部分无序部分以 ‘/’ 分割【1 / 4,2,3,7,5】,无序部分第一个元素是4,将4放在有序部分合适的位置即1的后面,排序后数组为 【1,4,2,3,7,5】
step2:有序部分无序部分以 ‘/’ 分割【1, 4 / 2,3,7,5】,无序部分第一个元素是2,将2放在有序部分合适的位置即1和4之间,排序后数组为 【1,2,4,3,7,5】
.
.
.
step6:有序部分无序部分以 ‘/’ 分割【1, 2,3,4 , 7 / 5】,无序部分第一个元素是5,将5放在有序部分合适的位置即3和7之间,排序后数组为 【1,2,4,3,5,7】
Insertion类
```
package sort;
/*
* 插入排序,依次将数插入合理的位置
*/
public class Insertion {
public static void sort(Comparable[] c){
for (int i = 0; i < c.length; i++) {
for (int j = i; j >0 && SortBasicClass.less(c[j], c[j-1]); j--)
SortBasicClass.exec(c, j, j-1);
}
}
}
```
测试类同上选择排序,代码如下
```
package sort;
import java.util.Random;
import java.util.Scanner;
import edu.princeton.cs.introcs.StdRandom;
public class SortTestClass {
public static void main(String args[]) {
InsertionTest();
}
// 插入排序的测试
public static void InsertionTest() {
Comparable[] c = new Comparable[100];
for (int i = 0; i < 100; i++) {
c[i] = StdRandom.uniform(1, 100);
// c[i] = Math.random();
}
Insertion.sort(c);
assert SortBasicClass.isSorted(c);
SortBasicClass.show(c);
}
}
```
在研究排序算法的性能时,可以写一个实验用例来做实验。
下面是我参照算法第四版SortCompare类写的一个方法,可以自行调整N,T的大小多次验证,我的计算机中选择排序的速度大概是插入排序的1.7倍。具体的排序算法可以根据上面的模板自行写出。
SortCompare类代码:
```
package sort;
import edu.princeton.cs.introcs.StdOut;
import edu.princeton.cs.introcs.StdRandom;
import edu.princeton.cs.introcs.Stopwatch;
//各种排序算法的比较
public class SortCompare {
public static void main(String [] args){
double SelectionTime = TimeRandomInput("Selection",100,20000);
double InsertionTime = TimeRandomInput("Insertion",100,20000);
StdOut.println("Selection costs " + SelectionTime + " seconds");
StdOut.println("Selection costs " + InsertionTime + " seconds");
StdOut.printf("Selection divided by Insertion is %.2f", SelectionTime/InsertionTime);
}
//排序以及其花费的时间
public static double time(String alg,Double[] d){
Stopwatch timer = new Stopwatch();
if(alg.equals("Selection")) Selection.sort(d);
if(alg.equals("Insertion")) Insertion.sort(d);
return timer.elapsedTime();
}
//生成随机数组,并调用排序算法
public static double TimeRandomInput(String alg,int N,int T){
double total = 0.0;
Double[] d = new Double[N];
for (int i = 0; i < T; i++) {
for (int j = 0; j < d.length; j++) {
d[j] = StdRandom.uniform();
}
total += time(alg,d);
}
return total;
}
}
```