一、选择排序
1、思想
我们一定要理解选择排序的思想,假设是按着升序排序的方式,
- 首先找到最小的数,然后将第一个数组的第一个数据和它进行交换
- 然后找到第二个小的数,将它和数组的第二个树进行交换
- 依次下去
2、代码
- 这里我们使用了Comparable接口,这样的好处是,当我们自定义的类只要实现了Comparable接口,并且实现compareTo方法都可以调用这算法来进行排序
package cn.mldn;
public class SelectionSort {
public static void main(String[] args) {
Integer[] j = {10,7,4,5,2,9};
show(j);
sort(j);
show(j);
}
private static boolean less(Comparable v, Comparable w) {
return v.compareTo(w) < 0;
}
private static void exch(Comparable[] a,int i, int j) {
Comparable t = a[i];
a[i] = a[j];
a[j] = t;
}
private static void show(Comparable[] a) {
for(int i = 0;i < a.length;i++) {
System.out.print(a[i] + "郑光光");
}
System.out.println();
}
public static boolean isSorted(Comparable[] a) {
for (int i = 0; i < a.length; i++) {
if (less(a[i],a[i-1])) {
return false;
}
}
return true;
}
private static void sort(Comparable[] a) {
int N = a.length;
for (int i = 0; i < N; i++) {
int min = i;
//当i = 1的时候,这个内部的for循环结束后就找到了最小的数
//当i = 2的时候,这个内部的for循环结束后就找到了第二小的数的数
for (int j = i + 1; j < N; j++) {
if (less(a[j],a[min])) {
min = j;
}
}
//所以我们的交换应该写到这来
exch(a, i, min);
}
}
}
3、补充知识
今天在用dos命令启动java文件的时候一直报错,所以我又去复习的一遍,你如果看我这篇文章也跟我来一起吧。
- 首先来看我创建的java文件的位置【在cn和mldn不是目录,是我在项目里面的包】
- 当我进入到这个目录
报了一个错【这个错误不影响啥,先往后面看】
- 然后再执行下面的【我感觉没问题啊】
- 但是不要忘记的我们的【这里面重复了】
- 应该回退这样执行
ok了没事了
二、插值排序(插入排序)
1、一定要理解的思路
- 插值排序是将一个待排序的数组,将其分为两部分,假设我们选择下标为x的点进行分割,要对x和x前面部分进行排序,每次插入的下一个x,依次下去
2、代码
package cn.mldn.Insertion;
public class InsertionSort {
public static void main(String[] args) {
Integer[] j = {10,7,4,5,2,9};
show(j);
InsertedSort(j);
show(j);
}
private static boolean less(Comparable a, Comparable b) {
return a.compareTo(b) < 0;//说明a小于b
}
//满足的情况下就交换
private static void exch(Comparable[] c,int i,int j) {
Comparable t = c[i];
c[i] = c[j];
c[j] = t;
}
//用于显示数组中的内容
private static void show(Comparable[] c) {
int N = c.length;
for (int i = 0; i < N; i++) {
System.out.print(c[i] + " ");
}
System.out.println();
}
private static boolean isSorted(Comparable[] c) {
for (int i = 0; i < c.length; i++) {
if (less(c[i],c[i-1])) {
return false;
}
}
return true;
}
private static void InsertedSort(Comparable[] c) {
for (int i = 1; i < c.length; i++) {
for (int j = i; j > 0 ; j--) {
if (less(c[j], c[j-1])) {
exch(c, j, j - 1);
}
}
}
}
private static void InsertedSort2(Comparable[] c) {
for (int i = 1; i < c.length; i++) {
for (int j = i; j > 0 && less(c[j], c[j-1]) ; j--) {
exch(c, j, j - 1);
}
}
}
}
三、前面两种算法的比较
1、图解过程
2、测试一下时间复杂度
- 以后的时间复杂度的测试都是这样编写了,如果你电脑比较牛逼的话,你可以把这个N的值变大一点,而且你如果愿意等的话,我电脑不够牛逼,所以为八万
public static void main(String[] args) {
int N = 80000;
Integer[] j = new Integer[N];
for (int i = 0; i < N; i++) {
j[i] = (int)Math.random()*N;
}
long l = System.currentTimeMillis();
sort(j);
long e = System.currentTimeMillis();
System.out.println("所用时间为:" + (e - l));
}
- 看结果
- 原因:选择排序的时间复杂度为N(N - 1)/ 2 ~ N*N /2,而我们的插值排序的算法的时间复杂度为N
四、希尔排序
1、思路
首先这个很重要,很重要的:它其实就是外部先将数组分成若干个数组,又进行了插值排序【一定要记得它内部还是一个插值排序的过程】
2、代码实现
import java.util.Arrays;
public class ShellSort {
public static void main(String[] args) {
int N = 8;
Integer[] j = {10,2,4,6,8,9,3};
show(j);
/*for (int i = 0; i < N; i++) {
j[i] = new Integer ((int)Math.random()*N);
}*/
ShellSort(j);
show(j);
/*long l = System.currentTimeMillis();
sort(j);
long e = System.currentTimeMillis();
System.out.println("所用时间为:" + (e - l));*/
}
private static void show(Comparable[] a) {
for(int i = 0;i < a.length;i++) {
System.out.print(a[i] + " ");
}
System.out.println();
}
private static boolean less(Comparable a , Comparable b) {
return a.compareTo(b) < 0;
}
private static void exch(Comparable[] c, int i, int j) {
Comparable t = c[i];
c[i] = c[j];
c[j] = t;
}
//这个版本是跟着书上敲代码的,你如果能看懂那就看这个,如果看不懂就跟着我下面的理解或许可以
private static void sort(Comparable[] c) {
int N = c.length;
int h = 1;
while (h < N/3) {
h = 3 * h + 1;
}
while(h >= 1) {
for (int i = h; i < N; i++) {
for (int j = i; j >=h; j-=h) {
if (less(c[j],c[j-h])) {
exch(c,j,j-h);
}
}
}
h = h / 3;
}
}
//这个是我自己能理解的版本
public static void ShellSort(Comparable[] arr) {
//通过这个循环我找到了步长
for (int k = arr.length / 2; k > 0; k = k / 2) {
//通过上面的步长我找到了第一个位置【数组下标为0的个往后移动了步长的那个点】
for (int i = k; i < arr.length; i++) {
//仔细一看,这个内部其实就是一个查找排序,只是它移动的步长不是1而已,所以不能理解先去理解上面的插值排序
for (int j = i - k; j >= 0; j -= k) {
//如果当前元素大于加上步长的那个元素,则交换
if (less(arr[j+k],arr[j])) {
exch(arr,j+k,j);
}
}
}
}
}
}