import java.util.Arrays;
import java.util.Comparator;
import java.util.Random;
public class TestArrSort {
public static void main(String[] aa) {
// sort1();
// sort2();
// sort3();
myTestArraysSort();
}
public static void sort1() {
Integer[] nums = new Integer[10];
//数组下标范围是0-9
//随机数
Random random = new Random();
for (int i = 0; i < 10; i++) {
//注意这里nums[i]是整数integer对象,不是整型int
nums[i] = random.nextInt(1, 101);
}
//有必要系统研究一下Arrays类,当然前提是会用,
System.out.println("排序前:" + Arrays.toString(nums));
//升序排序,参数是Object类,使用了多态
Arrays.sort(nums);
//排序后结果输出
System.out.println("升序排序后:" + Arrays.toString(nums));
//降序排序
//创建了一个接口,这个接口应该有一个方法比较compare
//这就是规范
//然后我们覆盖方法之后就能排序了 。
//当然,是不是很疑惑,前面也排序了,但是没有new接口(其实接口也是不能new的,我们new的应该是一个具体实现类,具体我还需要学习。)
//答案就是:前面的排序是人家默认就有的接口,这里是我们写方法覆盖前面方法
//不要忘了最终目的,实现降序排序
Arrays.sort(nums, new Comparator() {
@Override
public int compare(Integer obj1, Integer obj2) {
//前者减后者
// 注意obj1还是对象,不是整型值,这里绝对不是 5-1 那么简单
//如果是这样,那么是升序,也就是没有覆盖的方法
// return obj1-obj2;
//后者减前者--最终实现降序排序
return obj2 - obj1;
}
});
System.out.println("降序排序后:" + Arrays.toString(nums));
//idea又给我提示了说有更简单的方法,于是我就用了一下,毕竟应该是更简单的方法思想更好。
//最终就是这样, 我的jdk版本是17,这里是jdk8的最重要的新特性Lambda 表达式
//具体我也不会,暂时没有学
//我研究了一下,找到了等价关系,我想升序,所以把用前者减后者了,
Arrays.sort(nums, (obj1, obj2) -> obj1 - obj2);
//测试--
System.out.println("升序排序后:" + Arrays.toString(nums));
//先给它降序一下
Arrays.sort(nums, (obj1, obj2) -> obj2 - obj1);
//我把降序改为升序,然后idea又提示我有新的方法,我又点了一下
//于是就变成了这样,这点我就没有办法修改了--其实可以继承然后覆盖方法,似乎又回到了降序最初的方法。给我在这里整死循环呢
//所以这个目前来说只能升序
//为了测试我在上面补充了降序
Arrays.sort(nums, Comparator.comparingInt(num -> num));
//测试--
System.out.println("升序排序后:" + Arrays.toString(nums));
//我首先写一个...我看过老师的一个例子,稍微修改了一下
//仅供参考,
for (int i = 0; i < nums.length / 2; i++) {
//i是待交换的下标,
//随机下标范围:[length/2+1,length)
int j = random.nextInt(nums.length / 2 + 1, nums.length);
//两两交换num[i]和[end]
//新建地址temp
Integer temp = nums[i];
//上面是地址拷贝,下面也是
nums[i] = nums[j];
nums[j] = temp;
}
System.out.println("乱序排序后:" + Arrays.toString(nums));
//不扯了,继续按照规范,新建接口,然后写覆盖方法实现乱序
Arrays.sort(nums, new Comparator() {
@Override
public int compare(Integer obj1, Integer obj2) {
//前者减后者
// 注意num1还是对象,不是整型值,这里绝对不是 5-1 那么简单
//如果是这样,那么是升序,也就是没有覆盖的方法
// return obj1-obj2;
//后者减前者--最终实现降序排序
// return obj2-obj1;
//乱序
return Math.random() < 0.5 ? 1 : -1;
}
});
// Arrays.sort(nums, (obj1, obj2) -> Math.random()<0.5?1:-1); //这样写也可以
System.out.println("乱序排序后:" + Arrays.toString(nums));
}
//sort1是Integer类的排序,然后就是String类的排序
public static void sort2() {
//问题一:String类怎么排序
//按照首字母的ASCII码(值)大小,字符串长度,如果字符串是汉字,汉字首字母的笔画(感觉String已经不能表示汉字类了)...
var lang = new String[]{"java", "C", "C++", "B", "go", "python", "javascript", "A"};
//排序前
System.out.println(Arrays.toString(lang));
//按照ASCII码大小升序排序
Arrays.sort(lang);
System.out.println("按首字符的ASCII升序:" + Arrays.toString(lang));
//降序
//这是一个新的方法
Arrays.sort(lang, Comparator.reverseOrder());
//也可以自己写
// Arrays.sort(lang, (obj1,obj2)->obj2.charAt(0)-obj1.charAt(0));
System.out.println("按首字符的ASCII降序:" + Arrays.toString(lang));
//乱序
Arrays.sort(lang, (obj1, obj2) -> Math.random() > .5 ? 1 : -1);
System.out.println("按首字符的ASCII降序:" + Arrays.toString(lang));
//按字符个数/字符串长度排序
//有点类似Integer; 同样强调obj1,obj2是String类型
Arrays.sort(lang, (obj1, obj2) -> obj1.length() - obj2.length());
//下面是idea给我提示的另一种写法
// Arrays.sort(lang, Comparator.comparingInt(String::length));
System.out.println(Arrays.toString(lang));
//降序
//这是一个新的方法
Arrays.sort(lang, (obj1, obj2) -> obj2.length() - obj1.length());
System.out.println(Arrays.toString(lang));
//乱序:这个不受排序方式影响,和前面一样
Arrays.sort(lang, (obj1, obj2) -> Math.random() > .5 ? 1 : -1);
System.out.println(Arrays.toString(lang));
}
//最后自定义类排序
public static void sort3() {
//定义users数组
User[] users = new User[6];
//赋值
users[0] = new User(1, "秦始皇", "123456");
users[1] = new User(2, "汉武帝", "123456");
users[2] = new User(3, "唐太宗", "123456");
users[3] = new User(4, "宋太祖", "123456");
users[4] = new User(5, "成吉思汗", "123456");
//users[5]是null --- 会影响排序
System.out.println("排序前" + Arrays.toString(users));
//开始排序
//默认是按照id排序,因为我就是那样赋值的。
//按姓名排 对应String类
//按照id排 对应Integer类
//按照id倒序
//开始我的错误写法,没有理解obj1是什么,obj就是数组的元素。
//也就是user对象,obj2-obj1这不行,不符合要求
//应该是拿到数组元素后,调用数组的方法,得到ID属性
//然后比较ID属性大小。这个思路有点像用对象数组遍历
Arrays.sort(users, new Comparator() {
@Override
public int compare(User obj1, User obj2) {
//排除null
if (obj1 == null) {
if (obj2 == null) {
return 0;
}
return 1;
}
if (obj2 == null) {
return -1;
}
return obj2.getId() - obj1.getId();
}
});
//对象数组遍历,我使用for in语句
for (User user : users) {
//得到user元素了
//我可以用user对象输出
if (user == null) {
continue;
}
System.out.printf("姓名:%s,密码:%s%n", user.getName(), user.getPwd());
}
//总结,刚开始我没有转过来弯
//我的理解是
//在重写的方法中,方法参数就是obj1,obj2。它们的类型是万能的,可以装下任何类型
//类似Object,var关键字
//即,我知道我拿到了数组元素。
// 我想比较数值元素的大小,那么就应该想好怎么用拿到的元素。
//不就是用数值元素的一种值的比较
//拿到元素就可以比较元素大小+我知道你是在参数中给我了数组元素 --- 我觉得这是一种设计思想
//以下是我的错误写法
// Arrays.sort(users,(obj1,obj2)->obj2-obj1);
// Arrays.sort(users,(obj1,obj2)->obj2.getId()-obj1.getId());
//按照user的姓名首字母排序,
Arrays.sort(users, new Comparator() {
@Override
public int compare(User obj1, User obj2) {
if (obj1 == null) {
if (obj2 == null) {
return 0;
}
return 1;
}
if (obj2 == null) {
return -1;
}
return obj2.getName().charAt(0) - obj1.getName().charAt(0);
}
});
System.out.println(Arrays.toString(users));
}
//最后的最后为了探究Arrays数组的sort 公共静态方法是怎么具体实现的,所以我把细节我做了探究
public static void myTestArraysSort() {
Integer[] integers = new Integer[]{23, 11, 88, 45, 108, 55, 34, 200, 90};
Arrays.sort(integers, new Comparator() {
@Override
public int compare(Integer obj1, Integer obj2) {
System.out.printf("obj1=%d,obj2=%d%n", obj1, obj2);
return obj1 - obj2;
}
});
//结果
// obj1=11,obj2=23
// obj1=88,obj2=11
// obj1=88,obj2=23
// obj1=45,obj2=23
// obj1=45,obj2=88
// obj1=108,obj2=45
// obj1=108,obj2=88
// obj1=55,obj2=45
// obj1=55,obj2=108
// obj1=55,obj2=88
// obj1=34,obj2=55
// obj1=34,obj2=23
// obj1=34,obj2=45
// obj1=200,obj2=45
// obj1=200,obj2=88
// obj1=200,obj2=108
// obj1=90,obj2=55
// obj1=90,obj2=108
// obj1=90,obj2=88
//分析 第1次 11和23比较 排好了 11 23
//分析 第2次 88和11比较
//分析 第3次 88和23比较 排好了 11 23 88
//分析 第4次 45和23比较 2分+插入排序 中间+1找 发现比23大
//分析 第5次 45和88比较 排好了 11 23 45 88
//分析 第6次 108和45比较 中间+1, 发现比45大
//分析 第7次 108和88比较 排好了 11 23 45 88 108
//... 观看上面结果
System.out.println(Arrays.toString(integers));//[11, 23, 34, 45, 55, 88, 90, 108, 200]升序
//结论
//1、方法参数是插入排序中带比较的元素,第一个参数是每次待排的元素,从下标1开始(第二个元素)。
//2、如果返回值大于0,那么obj1在obj2后面
//3、如果返回值小于0,那么obj1在obj2前面,
//例子最小的数去找位置时(obj1),它小于每一个obj2, 返回值 obj1-obj2(<0)则是正序,
//例子最小的数去找位置时(obj1),它小于每一个obj2, 返回值 obj2-obj1(>0)则是倒序,
//4、用二分法定位,排到第一个或最后一个位置结束。 二分法可以减少查找次数
//参数代表每次22比较的元素,返回值正负决定放的位置。
}
}
//我的自定义类就放在这里,就是练习而已
//只能是缺省的class
//不能有main方法
class User {
public User() {
}
public User(int id, String name, String pwd) {
this.id = id;
this.name = name;
this.pwd = pwd;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public String getPwd() {
return pwd;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
private int id;
private String name;
private String pwd;
@Override
public String toString() {
return "姓名:" + name + "密码:" + pwd;
}
}