Java进阶2 排序查找与Lambda、正则表达式



● 导图

在这里插入图片描述

一、 基础算法

1.排序

1.1 冒泡排序

冒泡排序: 相邻的数据两两比较,小的放前面,大的放后面。

核心思想:

  1. 相邻的元素两两比较,大的放右边,小的放左边。
  2. 第一轮比较完毕之后,最大值就已经确定,第二轮可以少循环一次,后面以此类推。
  3. 如果数组中有n个数据,总共我们只需要执行n - 1 轮的代码就可以。

冒泡排序的应用

现在有一个数组:{2,4,5,3,1};想从小到大排序,这里就可以使用冒泡排序。

代码实现

public static void main(String[] args) {
        //1.定义数组
        int[] arr = {2,4,5,3,1};

        //2.利用冒泡排序将数组中的数据变成 1 2 3 4 5

        //外循环:表示要执行多少轮,如果有n个数据,那么就执行 n - 1 轮。
        for (int i = 0; i < arr.length - 1; i++) {
            //内循环:每一轮循环中比较数据并找到当前的最大值
            //-1:为了防止索引越界
            //-i:提高效率,每一轮执行的次数应该比上一轮少一次。
            for (int j = 0; j < arr.length - 1 - i; j++) {
                //i 依次表示数组中的每一个索引:0 1 2 3 4
                if (arr[j] > arr[j + 1]){
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }

1.2 选择排序

选择排序:从0索引开始,拿着每一个索引上的元素跟后面的元素依次比较,小的放前面,大的放后面,以此类推。

选择排序的实现:

  1. 从0索引开始,跟后面的元素一一比较。
  2. 小的放前面,大的放后面。
  3. 第一轮循环结束后,最小的数据已经确定。
  4. 第二轮循环从1索引开始以此类推。
  5. 第三轮循环从2索引开始以此类推。
  6. 第四轮循环从3所以开始以此类推。

选择排序的应用

还是以冒泡排序的题为例子:有一个数组:{2,4,5,3,1};想从小到大排序。

代码实现

public static void main(String[] args) {
        //1.定义数组
        int[] arr = {2,4,5,3,1};

        //外循环:表示循环几轮
        //i:表示这一轮中,拿着i索引上的数据跟后面的元素进行比较并交换
        for (int i = 0; i < arr.length - 1; i++) {
            //内循环:每一轮拿着i跟i后面的数据进行比较交换
            for (int j = i + 1; j < arr.length; j++) {
                if(arr[i] > arr[j]){
                    int temp = arr[i];
                    arr[i] = arr[j];
                    arr[j] = temp;
                }
            }
        }
    }


2. 查找

2.1 基础查找

从索引值0开始挨个往后查找,若查到想要的元素值,则停止。

public static void main(String[] args) {
        int[] arr = {131,127,147,81,103,23,7,79};

        find(arr,127);

    }

    public static int find(int[] arr,int num){
        for (int i = 0; i < arr.length; i++) {
            if(num == arr[i]){
                System.out.println("索引值为:"+i);
                return 1;
            }
        }
        System.out.println("没有查找到该元素");
        return 0;
    }

假设我们要查找的元素是79,如果是基本查找的话,只能从0索引开始一个一个往后找,但是如果元素比较多,需要查找的元素比较靠后的话,这样查找的此处就比较多。性能比较差

2.2 二分查找

二分查找的主要特点是,每次查找能排除一半元素,这样效率明显提高。但是二分查找要求比较苛刻,它要求元素必须是有序的,否则不能进行二分查找。

现在有如下一个需求:

定义一个方法利用二分查找,查询某个元素在数组中的索引,数组如下: {7,23,79,81,103,127,131,147}

代码实现

public static void main(String[] args) {
        int[] arr = {7,23,79,81,103,127,131,147};
        System.out.println("查找元素的索引为:"+Index(arr,131));;

    }

    public static int Index(int[] arr,int num){
        //1.定义两个变量记录查找范围
        int max = arr.length-1;
        int min = 0;

        //2.利用循环不断地去找要查找的数据
        while (true) {
            if(min > max){
                return - 1;
            }
            //3.找到min和max的中间值
            int mid = (max + min) / 2;
            //4.拿着mid指向的元素跟要查找的元素进行比较
            if(arr[mid] > num){
                //4.1 num在mid的左边
                //min不变,max = mid -1;
                max = mid - 1;
            }else if(arr[mid] < num){
                //4.2 num在mid的右边
                //max不变,min = mid + 1;
                min = mid + 1;
            }else{
                return mid;
            }
        }
    }

二分查找小结:

1.二分查找的优势。

提高查找效率

2.二分查找的前提条件。

数据必须是有序的,如果数据是乱的,先排序再用二分查找得到的索引就没有实际意义,只能确定当前数字在数组中是否存在,因为排序后数字的位置可能会发生改变。

3.二分查找的过程

  • min和max表示当前要查找的范围
  • mid是在min和max中间的
  • 如果要查找的元素在mid的左边,缩小范围时,min不变,max等于mid减1
  • 如果要查找的元素在mid的右边,缩小范围时,max不变,min等于mid加1
  • 如果要查找的元素恰好等于mid,那么就返回。

二、Lambda表达式

1)初识Lambda

以下有段代码,使用Arrays中的sort方法来对数组进行排序。

Integer[] arr = {2,3,4,1,5,7,8,9,6};

//使用匿名内部类来实现排序
Arrays.sort(arr,new Comparator<Integer>(){
	@Override
	public int compare(Integer o1,Integer o2){
		return o1 - o2;
	}
});

//使用Lambda表达式来优化这段代码
Arrays.sort(arr, (Integer o1 - Integer o2)->{
	return o1 - o2;
	}
);

2)函数式编程

面向对象:先找对象,让对象做事。
函数式编程:是一种思想特点。
函数式编程思想,是忽略面向对象的复杂语法, 强调做什么,而不是谁去做。 而Lambda表达式就是函数式思想的体现。

3).Lambda表达式的标准格式

() -> {

}
  • () 对应着方法的形参
  • -> 固定格式

4)Lambda的注意事项

  • Lambda表达式可以用来简化匿名内部类的书写
  • Lambda表达式只能简化函数式接口的匿名内部类的写法
  • 函数式接口: 有且仅有一个抽象方法的接口叫做函数式接口,接口上方可以加@Functionallnterface注解

5)Lambda表达式的省略写法

  • 参数类型可以省略不写
  • 如果只有一个参数,参数类型可以省略,同时()也可以省略
  • 如果Lambda表达式的方法只有一行,大括号,分号,return可以省略不写,注意:大括号,分号,return需要同时省略

6)Lambda表达式简化Comparator接口的匿名形式

看以下的一个需求:

定义数组并存储一些字符串,利用Arrays中的sort方法进行排序。

要求:

按照字符串的长度进行排序,短的在前面,长的再后面。(暂时不比较字符串里的内容)

代码实现

String[] arr = {"a","aaaa","aaa","aa"}

//如果要把数组中的数据按照指定的方式进行排序,就需要用到sort方法,而且要指定排序的规则

//匿名内部类解决
//Arrays.sort(arr,new Comparator<String>){
//	@Override
//	public int comapre(String o1,String o2){
//		//字符串的长度进行排序
//		return o1.length() - o2.length();
//	}
//});

//打印
System.out.println(Arrays.toString(arr));

//Lambda完整格式
Arrays.sort(arr,(String o1,String o2)->{
	return o1.length() - o2.length();
	}
);

//Lambda简写格式
//小括号:数据类型可以省略,如果参数只有一个,小括号可以省略
//大括号:如果方法体只有一行,return 分号,大括号都可以省略
Arrays.sort(arr,(o1,o2) -> o1.length()-o2.length());

Lambda小结

1.Lambda的基本作用?

简化函数式接口的匿名内部类的写法。

2.Lambda表达式有什么使用前提?

必须是接口的匿名内部类,接口中只能有一个抽象方法。

3.Lambda的好处?

Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码,它可以写出更简洁、更灵活的代码,作为一种更紧凑的代码风格,使java语言表达能力得到了提升。

三、正则表达式

正则表达式的规则

字符类(只匹配一个字符)

在这里插入图片描述
预定义字符(只匹配一个字符)

**加粗样式**
数量词

在这里插入图片描述

● 正则表达式的使用

字符类(只匹配一个字符)的使用

public static void main(String[] args) {
        //public boolean matches(String regex);判断是否与正则表达式匹配,匹配则返回true

        //只能是a b c
        System.out.println("-------1-------");
        System.out.println("a".matches("[abc]")); //true  //只能是abc中的一个
        System.out.println("z".matches("[abc]")); //false //z不属于abc
        System.out.println("ab".matches("[abc]"));//false //[]一个中括号只能判断一个字符
        System.out.println("ab".matches("[abc][abc]")); //true //两个[] 就可以判断两个字符

        //不能出现a b c(除abc外的其他值)
        System.out.println("-------2-------");
        System.out.println("a".matches("[^abc]")); //fase //a属于abc
        System.out.println("z".matches("[^abc]")); //true //z不属于abc
        System.out.println("zz".matches("[^abc]")); //false
        System.out.println("zz".matches("[^abc][^abc]")); //true

        //a-z  A-z(包括头尾的范围)
        System.out.println("-------3-------");
        System.out.println("a".matches("[a-zA-z]")); //true //a属于a-z
        System.out.println("z".matches("[a-zA-z]")); //true //z属于a-z
        System.out.println("aa".matches("[a-zA-z]")); //false //一个[]只能判断一个字符
        System.out.println("zz".matches("[a-zA-z]")); //false
        System.out.println("zz".matches("[a-zA-z][a-zA-Z]")); //true
        System.out.println("0".matches("[a-zA-z]")); //false
        System.out.println("0".matches("[a-zA-Z0-9]")); //true
        System.out.println("0".matches("[0-9]")); //true

        //[a-d[m-p]] a到d,或m到p
        System.out.println("-------4-------");
        System.out.println("a".matches("[a-d[m-p]]")); //true
        System.out.println("d".matches("[a-d[m-p]]")); //true
        System.out.println("m".matches("[a-d[m-p]]")); //true
        System.out.println("p".matches("[a-d[m-p]]")); //true
        System.out.println("e".matches("[a-d[m-p]]")); //false
        System.out.println("0".matches("[a-d[m-p]]")); //false

        //[a-z &&[def]] a-z和def的交集,为:d,e,f
        System.out.println("-------5-------");
        System.out.println("a".matches("[a-z &&[def]]")); //false
        System.out.println("d".matches("[a-z &&[def]]")); //true
        System.out.println("0".matches("[a-z &&[def]]")); //false
        //注意:如果要求两个范围的交集,那么需要写符号 &&
        //如果写成了一个&,那么此时&表示就不是交集了,而是一个简简单单的&符号
        System.out.println("a".matches("[a-z &&[def]]")); //true

        //[a-z &&[^bc]] a-z和非bc的交集(等同于[ad-z])
        System.out.println("-------6-------");
        System.out.println("a".matches("[a-z &&[^bc]]")); //true
        System.out.println("b".matches("[a-z &&[^bc]]")); //flase
        System.out.println("0".matches("[a-z &&[^bc]]")); //false

        //[a-z &&[^m-p]] a-z 和 非m-p的交集(等同于[a-lq-z])
        System.out.println("-------7-------");
        System.out.println("a".matches("[a-z &&[^m-p]]")); //true
        System.out.println("m".matches("[a-z &&[^m-p]]")); //false
        System.out.println("0".matches("[a-z &&[^m-p]]")); //false
}

预定义字符(只匹配一个字符)

使用预定义字符正则表达式的时候,先要注意几个点:

  1. 在Java中,\代表转义字符,意义为:改变后面那个字符原本的含义。
  2. " 在Java中表示字符串的开头或者结尾。
  3. "\连用成:\",此时 \ 表示转义字符,改变了后面那个双引号原本的含义,把它变成了一个普普通通的双引号。
  4. 而在Java中想要表示\,则需要在\前再加上一个反斜杠,:\\,改变后面\原本的含义,把它变成一个普普通通的\

预定义字符的使用

public static void main(String[] args) {
        // .表示任意一个字符
        System.out.println("你".matches("..")); //false
        System.out.println("你a".matches(".."));//true

        // \\d只能是任意的一位数字
        //简单来记:\\ 表示 \
        System.out.println("a".matches("\\d")); //false
        System.out.println("3".matches("\\d")); //true
        System.out.println("333".matches("\\d")); //false

        // \\w只能是一位单词字符 [a-zA-Z_0-9]
        System.out.println("z".matches("\\w")); //true
        System.out.println("2".matches("\\w")); //true
        System.out.println("21".matches("\\w\\w")); //true
        System.out.println("你".matches("\\w")); //false

        // \\W非单词字符
        System.out.println("你".matches("\\W")); //true
}

数量词

public static void main(String[] args) {

        //数量词: 必须都是数字、字母、下划线,至少6位
        System.out.println("2442fsfsf".matches("\\w{6,}")); //true
        System.out.println("244f".matches("\\w{6,}")); //false

        //必须是数字和字符 必须是4位
        System.out.println("23dF".matches("[a-zA-Z0-9]{4}")); //true
        System.out.println("23_F".matches("[a-zA-Z0-9]{4}")); //false
        System.out.println("23dF".matches("[\\w &&[^_]]{4}")); //true
        System.out.println("23_F".matches("[\\w &&[^_]]{4}")); //false
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值