本周学习内容目录
一.算法
1.冒泡排序
(1)原理
- 1.从第一个数据开始,与第二个数据相比较,如果第二个数据小于第一个数据,则交换两个数据的位置
- 2.指针从第一个数据移向第二个数据,第二个数据与第三个数据相比较,如果第三个数据小于第二个数据,则交换两个数据的位置
- 3.依次类推,完成第一轮排序,第一轮排序结束后,最大的元素别移到了最右面
- 4.依照上面的过程进行第二轮排序,将第二大的排在倒数第二的位置
- 5.重复上述过程,每排完一轮,比较次数就减少一次
(2)例子
待排序数据:5,2,3,1
第一轮排序过程:
指针先指向5,5和3比较,5>2,交换2和5的位置,结果为:2,5,3,1
指针指向第二个元素5,5和3比较,5>3,交换5和3的位置,结果为:2,3,5,1
指针指向第三个元素5,5和1比较,5>1,交换5和1的位置,结果为:2, 3,1,5
第一轮排序结束后,最大的值5被移到了最右边
进行第二轮排序,过程同上,第二轮比较结果为:2,1,3,5
第三轮结果为:1,2,3,5
最终结果为:1,2,3,5,由上可知N个数据排序,需要进行N-1轮排序;第i轮排序需要的比较次数为N-i次
(3)编码思想
需要两层循环,第一层循环i表示排序的轮数,第二层循环j表示比较的次数。
(4)代码实现
import java.util.Arrays;
public class Test1 {
// 掌握冒泡排序的编写:每次从数组中找出最大值放在数组的后面去
public static void main(String[] args) {
// 定义一个数组
int[] arr = {5, 2, 3, 1};
// 1.确定总共需要做几轮
for (int i = 0; i < arr.length - 1; i++) {
// i = 0 1 2 [5, 2, 3, 1] 次数
// i = 0 第一轮 0 1 2 3
// i = 1 第二轮 0 1 2
// i = 2 第三轮 0 1
// 2.确定每轮比较几次
for (int j = 0; j < arr.length - i - 1; j++) {
// 定义一个if语句来判断数组前后值的大小,如果前面的数大于后i面,就交换
if (arr[j] > arr[j+1]){
// 定义一个临时变量
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
System.out.println(Arrays.toString(arr));
}
}
二.选择排序
(1)基本思想
在长度为N的无须数组中,第一次遍历n-1个数,找到最小的数值与第一个元素交换;
第二次遍历n-2个数,找到最小的数值与第二个元素交换
第n-1次遍历,找到最小的数值与第n-1个元素交换,排序完成
(2)代码实现
第一种:
import java.util.Arrays;
public class Test2 {
// 掌握选择排序
public static void main(String[] args) {
// 定义一个数组
int[] arr = {5, 1, 3, 2};
// 定义一个循环来控制交换几轮
for (int i = 0; i < arr.length - 1; i++) {
// 定义一个循环来控制每轮交换几次
for (int j = i + 1; j < arr.length; j++) {
// 判断前面与后面数的值的大小,如果前面大于后面,则交换、
if (arr[i] > arr[j]){
// 定义一个临时变量temp
int temp = arr[j];
arr[j] = arr[i];
arr[i] = temp;
}
}
}
System.out.println(Arrays.toString(arr));
}
}
第二种:
import java.util.Arrays;
public class Test2pro {
public static void main(String[] args) {
// 选择排序算法的优化版
// 定义一个数组
int[] arr = {5, 1, 3, 2};
// 定义一个循环来控制交换几轮
for (int i = 0; i < arr.length - 1; i++) {
int minIndex = i;
// 定义一个循环来控制每轮交换几次
for (int j = i + 1; j < arr.length; j++) {
// 判断前面与后面数的值的大小,如果前面大于后面,则交换、
if (arr[minIndex] > arr[j]){
minIndex = j;
}
// 决定是否交换
if (i != minIndex){
// 定义一个临时变量temp
int temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
}
System.out.println(Arrays.toString(arr));
}
}
三.二分查找算法
(1)概述
- 前提条件:数值中的数据必须时有序的
- 核心思想;每次排除一半的数据,查询数据的性能明显提高很多
定义一个中间值mid与要找的数据n比较,如果mid<n ,则把左边的全部去掉,如果mid>n ,则去掉右边的
(2)代码实现
public class Test3 {
public static void main(String[] args) {
// 1.先准备一个数组
int[] arr = {7, 15, 29, 37, 85, 138, 190};
System.out.println(binarySearch(arr, 138));
}
public static int binarySearch(int[] arr,int data){
// 2.定义两个变量,分别表示左边和右边
int left = 0;
int right = arr.length - 1;
// 3.定义一个循环来进行二分查找
while (left <= right){
// 定义一个中间数来与data比较
int middle = (left + right) / 2;
if (data > arr[middle]){
left = middle + 1;
} else if (data < arr[middle]) {
right = middle - 1;
}else {
return middle;
}
}
return -1;
}
}
四.正则表达式
1. 体验一下正则表达式来校验数据的合法性
对于同一个需求,正则表达式的代码展示
public static boolean checkQQ1(String qq){
return qq != null && qq.matches("[1-9]\\d{5,19}");
}
普通写法的代码展示
public static boolean checkQQ(String qq){
// 1.判断qq是否为null,0开头,(6-20)之间
if (qq == null || qq.startsWith("0") || qq.length() < 6 || qq.length() > 20){
return false;
}
// 2.判断出qq至少不是null,不是0开头,长度在6-20之间
// 判断qq中是否不全是数字
for (int i = 0; i < qq.length(); i++) {
char ch = qq.charAt(i);
if (ch < '0' || ch > '9'){
return false;
}
}
return true;
2.正则表达式的书写规则
- 字符类(只能匹配单个字符)
[abc]只能匹配a,b,c
[^abc]不能是abc
[a-zA-Z]只能是a-zA-Z的字符
System.out.println("a".matches("[abc]")); // [abc]只能匹配a ,b,c
System.out.println("e".matches("[abcd]")); // false
System.out.println("d".matches("[^abc]"));// [^abc]不能是abc
System.out.println("a".matches("[^abc]"));// false
System.out.println("b".matches("[a-zA-Z]"));// [a-zA-Z]只能是a-zA-Z的字符
System.out.println("2".matches("[a-zA-Z]"));// false
System.out.println("k".matches("[a-z&&[^bc]]"));// a到z 除了b和c
System.out.println("b".matches("[a-z[^bc]]"));// false
System.out.println("ab".matches("[a-zA-Z0-9]"));// false 注意:以上带【内容】的规则都只能用与匹配单个字符
- 预定义字符(只能匹配单个字符) . \d \D \s \S \w \W
. 可以匹配任意字符
\在Java中有特殊意义: \n换行 \t代表一个缩进。如果在Java中,希望\就是\必须转义
\d:0-9
\s:代表一个空白字符
\S:代表一个非空白字符
\w:[a-zA-Z_0-9]
\W不能是a-zA-Z_0-9
System.out.println("徐".matches("."));// .可以匹配任意字符
System.out.println("徐徐".matches("."));// false
// \在Java中有特殊意义: \n换行 \t代表一个缩进
// 如果在Java中,希望\就是\必须转义
System.out.println("\"");
System.out.println("3".matches("\\d"));// \d:0-9
System.out.println("a".matches("\\d"));// false
System.out.println(" ".matches("\\s"));// \s:代表一个空白字符
System.out.println("a".matches("\\s"));// false
System.out.println("a".matches("\\S"));// \S:代表一个非空白字符
System.out.println(" ".matches("\\S"));// false
System.out.println("a".matches("\\w"));// \w:[a-zA-Z_0-9]
System.out.println("_".matches("\\w"));// true
System.out.println("徐".matches("\\w"));// false
System.out.println("徐".matches("\\W"));// \\W不能是a-zA-Z_0-9
System.out.println("a".matches("\\W"));// false
System.out.println("23232".matches("\\d"));// false 注意:以上预定义字符都只能匹配单个字符
- 数量词:?* + {n} {n,} {n,m}
? 代表0次或1次
*代表0次或多次
+代表1次或多次
{3}代表要正好是n次
{3.}代表是>=3次
{3,9}代表是 大于等于3次,小于等于9次
System.out.println("a".matches("\\w?"));// ? 代表0次或1次
System.out.println("".matches("\\w?"));// true
System.out.println("abc".matches("\\w?"));// false
System.out.println("abc12".matches("\\w*"));// * 代表0次或多次
System.out.println(" ".matches("\\w*"));// true
System.out.println("abc12张".matches("\\w*"));// false
System.out.println("abc12".matches("\\w+"));// + 代表1次或多次
System.out.println(" ".matches("\\w+"));// false
System.out.println("abc12张".matches("\\w+"));// false
System.out.println("a3c".matches("\\w{3}"));// {3}代表要正好是n次
System.out.println("abcd".matches("\\w{3}"));// false
System.out.println("abc12张".matches("\\w{3,}"));// {3.}代表是>=3次
System.out.println("ab".matches("\\w{3,}"));// false
System.out.println("abcde徐".matches("\\w{3,}"));// false
System.out.println("abc232d".matches("\\w{3,9}"));// {3,9}代表是 大于等于3次,小于等于9次
- 其他几个常见的字符:(? !) 忽略大小写 或:| 分组:()
System.out.println("abc".matches("(?!abc)"));// true
System.out.println("ABC".matches("(?!abc)"));// true
System.out.println("aBc".matches("a((?!)b)c"));// false
System.out.println("ABc".matches("a((?!)b)c"));// false
3.正则表达式爬取
public static void method1(){
String data = "来黑马程序员学习Java.\n" +
" 电话:1866668888.19839014992\n"+
"或者联系邮箱;boniu@itcast.cn.\n" +
"座机电话:01036517895.010-98951256\n" +
"邮箱:boza@itcast.cn\n"+
"邮箱:dle009@163.com.\n"+
"热线电话:400-618-9090, 400-618-4000 ,4006184000 ,4006189090";
- 先定义爬取规则
String regex = "(1[3-9]\\d{9}|(0\\d{2,7}-?[1-9]\\d{4,19})|(\\w{2,}@\\w{2,20}(\\.\\w{2,10}){1,2})"
+ "|(400-?\\d{3,7}-?\\d{3,7}))";
- 把正则表达式封装成一个Pattern对象
Pattern pattern = Pattern.compile(regex);
- 通过Pattern对象去获取查找内容的匹配器对象
Matcher matcher = pattern.matcher(data);
- 定义一个循环开始爬取信息
while (matcher.find()){
String sc = matcher.group();
System.out.println(sc);
}
4.正则表达式做搜素替换,内容分割
public String replaceAll(String regex, String newStr):—>按照正则表达式匹配的内容进行替换
String s1 = "古力娜扎ai888迪丽热巴999aa5566马儿扎哈fbb卡尔扎巴";
System.out.println(s1.replaceAll("\\w+","-"));
String s2 = "我我我喜欢编编编程程";
System.out.println(s2.replaceAll("(.)\\1+", "$1"));
.public String[] spilt(String regex):—>按照正则表达式匹配的内容进行分割字符串,反向一个字符串数组
String s3 = "古力娜扎ai888迪丽热巴999aa5566马儿扎哈fbb卡尔扎巴";
String[] names = s3.split("\\w+");
System.out.println(Arrays.toString(names));
五.异常
1.概述
异常就是代表程序出现的问题
- 运行时异常:RuntimeException及其子类,编译阶段不会出现错误提醒,运行时出现的异常(如;数组索引越界异常)
- 编译时异常:编译阶段就会出现错误提醒的(如:日期解析异常)
2.JVM默认处理异常的方式
当代码出现了异常,那么就会在异常处创建一个异常对象,若程序没有自己处理异常的代码,就会将异常交给本方法的调用者处理。
JVM默认处理异常的方式:
- 将异常信息以红色字体展示在控制台上(异常原因,名字,位置)
- 停止程序运行,哪里出现异常就在哪里停止
3.异常处理方式
1.throws声明异常
格式:public void 方法()throws 异常类名
注意事项:
- 书写位置在方法的括号后面,表示声明一个异常
- 编译时异常必须要进行处理,throws声明异常表示,谁调用这个方法谁处理异常
- 运行时异常因为在运行时才会发生,所以在方法后面可以不写,默认交给jvm处理
public class Demo02 {
public static void main(String[] args) throws ParseException {
method1();//如果调用者没有处理异常的代码,最终交给Main方法调用者JVM处理异常
}
//throws声明,告诉调用者调用这个方法可能会发生异常
//若无异常,方法正常执行;若发生异常将异常交给调用者处理
private static void method1() throws ParseException {
String s = "2021年11月11日";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
Date d = sdf.parse(s);//有可能会产生异常
System.out.println(d);
}
}
2.throw抛出异常
- 格式:throw new 异常();
- 注意;这个格式是在方法内的,表示当前代码手动抛出一个异常,下面的代码不用再执行了
抛出异常的意义: - 在方法中,当传递的参数有误,没有继续运行下去的意义了,则采取抛出处理,表示让该方法结束运行
- 告诉调用者方法中出现了问题
public class ExceptionDemo {
public static void main(String[] args) {
int [] arr = null;
printArr(arr);//就会 接收到一个异常.
//我们还需要自己处理一下异常.
}
private static void printArr(int[] arr) {
if(arr == null){
//调用者知道成功打印了吗?
//System.out.println("参数不能为null");
throw new NullPointerException();
//当参数为null的时候,手动创建了一个异常对象,抛给了调用者
//调用者就知道没有打印成功
}else{
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
}
3.try-catch自己处理异常
此方法处理异常的好处:即使发生了异常,程序还可以执行下去
实例代码:
public class Demo01 {
public static void main(String[] args) {
int[] arr = null;
try {
//有可能会出现异常的代码
printArr(arr);
}catch (NullPointerException e){
//若出现了这样的异常,我们进行的操作
System.out.println("数组为空");
}
//程序不会终止,会继续执行
System.out.println("嘿嘿嘿");
}
private static void printArr(int[] arr) {
if (arr == null){
//抛出异常
throw new NullPointerException();
}else {
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
}
注意事项:
- 如果 try 中没有遇到异常,会把try中所有的代码全部执行完毕,不会执行catch里面的代码
- 如果 try 中遇到了异常,那么直接跳转到对应的catch语句中,try下面的代码就不会再执行了
- 如果出现的异常没有被捕获,那么try…catch就相当于没有写,异常默认交给虚拟机处理
- 若出现多个异常就写多个catch,如果多个异常之间存在子父类关系,那么父类要写在子类异常的下面
4.自定义异常类
自定义异常类:
- 当Java中提供的异常不能满足我们的需求时,我们可以自定义异常,让异常信息更加的简单
- 实现步骤:1.定义异常类;2.写继承关系;3.提供空参构造器;4.提供有参构造器
public class AgeIllegalException extends Exception{
public AgeIllegalException(){
}
public AgeIllegalException(String message){
super(message);
}
}