JAVA基础
第一个java程序
-
源代码编写
用记事本或IDE等工具完成代码输出,报春后缀名为.java的Java源文件
-
源代码编译
用javac命令 使用java编译器对源文件进行语法检查,如果没有语法错误,编译成功后将生成后缀名为.class的字节码文件
-
运行字节码
使用java命令启动JVM虚拟机,并使用java解释器将字节码文件编译机器代码,执行并显示结果
转义字符\
-
\n:换行
-
\t:水平制表符,补全当前字符串长度至8的整数倍,根据字符段长度补1~8个空格
-
\:转义字符
-
\\n \\t
第一个\表示转义,第二个\表示输出的字符\
上面输出为:\n 和 \t
-
\\windows\\Syetem
-
第一个\表示转义,第二个\表示输出的字符,第三个\表示转义,第四个\表示输出的字符\,第五个\表示转义,第6个\表示输出的字符\
上面输面输出为:\windows\System
Local和Math函数
- Local
- LocalDate.now():获取本地日期,年月日
- .getYear():获取年份
- .getMonth();获取月份,获取英文
- .getMonthValue();获取月份,获取数字
- .getDayOfYear();获取今天是今年的第多少天
- .getDayOfMonth;获取今天是这个月的第多少天
- .getDayOfweek;获取星期几
- LocalTime.now():获取本地时间钟分秒
- LocalDateTime.now();获取本地地日期年月日+时间钟分秒
- LocalDate.now():获取本地日期,年月日
- Math
- .PI:输出Π(pai:3.1415926)
- .sqrt(a):开a的平方
- .pow(a,b):幂运算,输出a的b次方
- .random():生成0-1之间随机数
- abs():取绝对值
变量和数据类型
变量
概念
- 程序运行期间内容可以发生改变的量
- 从内存角度来解释:变量是代表内存中的一个存储单元
- 从作用角度来解释:变量用于保存程序在运行过程中产生的临时数据
- 从语法角度来解释:变量是使用不同数据类型,来进行定义保存数据的语法形式
关键字
java关键字是java语言保留供内部使用的,关键字也可称为保留字,不能使用关键字作为变量名或方法名
关键字
命名要求
- 变量名有英文字母,下划线,$符号,数字组成,其中数字不能做开头,不能使用java关键字作为变量名
- 驼峰命名法
- 类:大驼峰命名法,不管多少个单词首字母大写,eg:Myname
- 方法:小驼峰命名法,超过两个单词时每个单词首字母大写,eg:MyName
基本数据类型
四类八种:
-
数值型:
- 整数类型:byte,short,int,long
- 浮点数类型:float,double
-
非数值型
- 字符类型:char
- 布尔类型:boolean
-
1byte(字节)=8bit(位)
-
bit:计算机能识别的最小单位,1bit存放一位0/1
-
1字节等于8位,8位0/1,其中第一位表示正负(0代表正1代表负)所以byte的范围是-(2的七次方)到(2的七次方-1)
-
1字节:byte
2字节:short char
4字节:int boolean float
8字节:long double
-
整型
-
byte:
-
范围:-128~127
-
定义语法:
byte a;
-
-
short:
-
范围:-32768~32767
-
定义语法:
short a;
-
-
int:
-
范围:-2147483648~2147483647(-2的31次方到2的31次方-1)
-
定义语法:
int a;
-
-
long:
-
范围::
**-**9223372036854775808 ~ **+**9223372036854775807 (-2的63次方到2的63次方-1)
-
定义语法:
long a; long a1=90000000000L;
-
注:定义变量时赋值需要在后面加上l或者L;
浮点型
浮点类型数值就是小数,因为小数用科学计数法表示的时候,小数点是可以”浮动“的,如1234.5可以表示12.345×10的平方,所以称为浮点数
定义小数默认double
存贮方式
float 4个字节 32位 eg:
123.456
x
1
0
5
123.456x10^5
123.456x105
最高位:符号位 存放正负
符号位下7位:存储幂指数 存放10的6次方的6
剩下23位:有效位 存放123.456
-
float
-
范围:最大可表示3.4×10的38次方
-
定义语法:
float a; float a1=3.14f;
注:定义变量时赋值需要在后面加上f或者F
-
-
double
-
范围:最大可表示1.79×10的308c次方
-
定义语法:
double a;
-
字符类型
char类型表示一个字符,该类型只能表示非负值,java中ASCII值可以用char和Unicode表示
定义语法:
char a;
char a1='9';
注:char类型使用单引号,且仅有一个字符
布尔类型
boolean类型只有true和false两个值,布尔类型是关系运算的计算结果
定义语法:
boolean a1=true;
boolean a2=false;
引用类型
除8中基本数据类型外,其余类型都是引用数据类型,最常见的是String字符串,用于保存若干的字符
定义语法:
String str1="我本将心照明月";
注:String类型使用双引号
常量
-
定义:
**在程序运行期间,固定不变的量;**常量值又称为字面常量,它是通过数据直接表示的
-
常量定义:
定义变量时,如果加上final关键字,这个变量就变成了常量。定义常量时,必须精选初始化赋值,之后就不可以再次赋值,再次赋值会导致编译错误。一般情况下常量名使用大写字母表示
final double PI=3.14; double r=5.0; double area=PI*r*r; PI =300; //编译错误,常量不允许被修改
-
常量的作用:
用有意义的变量名来避免魔法数字,例如不要再代码中到处写3.15;而是定义一个PI来表示3.14;如果需要提高计算精准度,我们住需要在定义PI处修改,而不必所有地方替
变量定义
赋值
要在取值范围之内赋值
byte a = 127;
byte b = 128;
打印a输出127,打印b输出-128
类型转换
自动类型转换
取值范围小转换为取值范围大的类型
大范围类型 变量名 = 小范围的变量名
byte a = 10;
int b = a;
float f1 = 12.3F;
double d = f1;
b输出10,d输出12.3
强制类型转换
取值范围大转换为取值范围小的类型
小范围的数据类型 变量名 = (小范围的数据类型)大范围的变量名
int a = 10;
byte b = (byte)a;
System.out.println(b);
double d = 12.5;
float f = (float)d;
System.out.println(f);
不加强制类型转换报错
强制类型转换会出现的两个问题
-
溢出
范围大转化为范围小时,值大于小范围的取值时就会出现溢出问题
int a = -129; byte b = (byte)a; System.out.println(b);
a进行强制类型转换溢出,b会输出127
-
精度丢失
当高精度的值强制转化为低精度的值时就会出现精度丢的问题
float f = 12.5F; int c = (int)f; System.out.println(c);
当float类f型强制转化为整型c时,c精确度是1,f精确度是0.1,造成小数位的丢失,c会输出12
运算符
算数运算符
单目运算符:+(取正),-(取负)
双目运算符:+,-,×,/,%
单目运算符
取正:+
取负:-
双目运算符
-
+加
-
数字+数字:
-
数字+字符串
-
字符串+字符
int a = 10; int b = 10; String s="中国人"; System.out.println(a+b); //输出:20 System.out.println(a+s); //输出:10中国人 System.out.println(a+s+b); //输出:10中国人10
-
-
-减
只能进行数字减数字
int b = 10;
float f = 11.5F;
float f1 = 1.5F;
System.out.println(f-b); //输出1.5
System.out.println(b-f1); //输出8.5
- *乘
只能进行数字乘数字
-
/除
- 整数/整数=整数
- 整数/浮点数=浮点数
-
%取余
- 整数%整数=整数
- 整数%浮点数=浮点数
赋值运算符
+=,-=,*=,/=,%=
int a=2;
a +=4; //相当于a=a+4即a=2+4,其他同理
自增减运算符
单独使用,符号前后代表的值一样
混合使用
++在前,先自增,-- 在前,先自减
++在后,先赋值,-- 在后,先赋值
自增:++
int a=10;
int b=a++;
int c=++a;
//a输出12(自加了两次)b输出10(第二行a先赋值给了b,再自家),c输出12(第二行自加一次,第三行先自自加又赋值给了c)
自减:同理自加
不同类型的运算
-
不同类型的运算,结果去大范围的
-
char类型可以进行运算
// ASCII码表 - 小码表 存储0-177之间内容 // Unicode码表 - 大码表 char c = 'A'; char c1 = 65; char c2 = (char)(c+32); int a = c; System.out.println(c); System.out.println(c1); System.out.println(c2); System.out.println(a);
c输出A,c1输出A,c2输出B,a输出65
-
boolean类型不可做运算
-
byte,short,char
byte,short,char运算
byte,short,char进行运算时,将其转为int
byte a = 10; byte b = 10; byte c = (byte)(a+b); int c1 = a+b; byte b1 = 10; byte b2 = (byte)(b1+10); System.out.println(c); System.out.println(c1); System.out.println(b2);
第三行若不加强制类型转换(byte),则报错;byte类型的a和b在运算时转换为int类型,定义int类型c1则正确;计算b2时,byte类型b1自动转换为int类型,所以把(b1+10)强制类型转换为byte类型
关系运算符
==,!=,>,<,>=,<=
int a=10;
int b=18;
System.out.println(a > b); //输出布尔类型,true/false
逻辑运算符
左右两边为boolean类型,运算得到boolean类型
短路与非短路区别:当短路能确认结果是就不会再进行计算,而非短路会全部算完
-
与
- 短路与&&:
- 前面为假不进行后面的运算,直接返回false
- 两边为真,则为真,有假则假
- 非短路与&
- 两边为真,则为真,有假则假(不具备短路路运算)
- 短路与&&:
-
或
- 短路或||:
- 前面为真不进行后面的运算,直接返回true
- 有真则真,都假则假
- 非短路或|
- 有真则真,都假则假(不具备短路路运算)
- 短路或||:
-
非
!:取反
位运算
-
&按位与
两个都为1,结果为1
可用此判断奇偶数
int a=5; int b=6; int c=a&1; int d=b&1; System.out.println("a是奇数"+(c==1)); System.out.println("b是偶数"+(d==0));
-
|按位或
两个中有1,结果为1
-
~按位取反
- 原码,反码,补码:
原码:数的二进制表示就是原码
反码:正数–>正数的反码等原码
负数–>符号位不变,其他位取反
补码:正数–>正数的补码等于原码
负数–>负数的补码的等于补码+1
- !!!按位取反的步骤:
正数按位取反:二进制原码–>二进制原码取反–>二进制原码取反-1–>(二进制原码取反-1)再取反符号位不参与–>二进制结果
负数按位取反:二进制原码–>反码:符号位不变其他位取反–>补码:反码+1(得到补码符号位为0,正数)–>二进制结果(正数的原码反码补码相同,上一步得到一个整数的补码,既是此数的原码)
-
^按位异或
相同为0,不同为1
aab=b;
abb=a;
可以用于两个数字交换
int a=2; int b=4; a=a^b; b=a^b; a=a^b; //输出结果a为4,b为2,实现了交换
-
<< / >> 左移 /右移
左移:十进制5左移2 0000 0101 将变为0000 1010
右移:十进制8右移1 0000 1000 将变为0000 0100
左移1相当于×2,左移2相当于×4
右移1相当于除,右移2相当于除4
条件运算符
表达式1 ?表达式2 :表达式3
表达式1返回值为boolean类型,true执行表达式2,false执行表达式3;表达式2和表达式3的类型必须相同
用处:取两个数的较大值或较
int a = 2;
int b = 4;
int c = a > b ? a : b;
//若a>b,则取a;否则取b
引用数据类型
字符串-String
字符串类型String是我们开发中最常使用的引用类型,我们用双引号引起来的内容就是字符串
字符串的拼接
- Java的编译器对字符串进行特殊处理,可以使用+连接任意字符串和其他数据类型,简化字符串的处理
- Java的编译器对字符串进行特殊处理,可以使用+连接任意字符串和其他数据类型,简化字符串的处理
eg:int age=25;String s = "age is " + age;
常用字符串方法
-
获取字符串长度:public int length()
-
查找指定下标的字符:public char charAt (int index)
-
字符串的比较方法
a.equals(b)方法比较public boolean equals(Object c)是否完全相同
忽略大小写比较用publicboolean equalslgonreCase()
String s4 = "abcd"; String s5 = "abcD"; System.out.println("s4和s5是否相等:" + s4.equals(s5)); System.out.println("s4和s5忽略大小是否相等:" + s4.equalsIgnoreCase(s5));
-
大小写转换
转化大写:Stringupper=str.toUpperCase();
转化小写:Stringlower=str.toLowerCase();
String s5 = "abcD"; System.out.println("将s5都转为小写" + s5.toLowerCase()); System.out.println("将s5都转为小写" + s5.toUpperCase());
字符串的截取方法
publicStringsubstring(intindex):截取从参数位置一直到字符串末尾,返回新字符串。[begin,end]
publicStringsubstringintbegin,intend):截取从begin开始,一直到end结束,中间的字符串[begin,end)
String s6 = "210623200102030405";
String s7 = s6.substring(14);
System.out.println(s7);
//输出0405
String s8 = s6.substring(6,14);
System.out.println(s8);
//输出20010203
字符串的特点
字符串的内容永远不变
String s="hello";
System.out.println(s);
//显示hello
s="world";
System.out.println(s);
//显示world
//变的不是字符串,而是变量指向,s指向了world
原来的字符串"hello"还在,只是我们无法通过变量s访问它而已。因此,字符串的不可变是指字符串内容不可变。
空值null
-
引用类型的变量可以指向一个空值null,它表示
不存在,尚未分配内存空间,即该变量不指向任
何对象
-
String s1 = “”; // 空字符串,已经分配内存空间
System.out.println(s1); // 空
System.out.println(s1.length()); // 0
-
String s2 = null; // 空值,尚未分配内存空间
System.out.println(s2); // null
System.out.println(s2.length()); // 空指针异常
-
空值null和空字符串的区别
- 空间:null未分配空间,空字符串已经分配内存空间
- 长度:s2.length()空指针异常,s1.length()长度为0
数组
为什么用数组
如果说程序中,需要存储大量的相同类型的一组数据,如果直接使用变量来进行存储,每个变量只能存储一个值,就需要大量的变量。
- 代码过于臃肿
- 程序的可读性差
- 数据维护较差
- 变量的容器小,数组的容器大
数组的定义
- 一组相同数据类型的数据,在内存中开辟连续的内存空间,按照一定的先 后次序排列组合而成。
- 其中 ,每一个数据称作一个元素 ,每个元素可以通过一个索引(下标)来访问它们
数组声明
- 数据类型[] 数组名
- 数据类型 数组名[]
注意:
- 声明的时候并没有实例化任何对象,只有在实例化数组对象时,JVM才分配空间,这时才与长度有关
- 声明一个数组的时候并没有数组 真正被创建
- 构造一个数组,必须指定长度
数组的初始化
初始化
所谓初始化就是给数组中的数组元素分配内存空间,并为每个数组元素赋初始值
-
默认初始值:
int:0 float:0.0 boolean:false String:null char:不可见的字符
**注意:**java中的数组必须先初始化然后才可以使用(只声明不能使用)
初始化方式
动态初始化
-
类型[] 数组名=new 类型[长度] 声明并创建数组
-
先声明,再创建(分配内存空间)
数据类型[] 数组名;
数组名 = new 数组类型[长度];
//1
String[] arr8=new String[3];
//2
String[] a;
a = new String[5];
静态初始化
类型[] 数组名 = new 类型[]{元素0,元素1,…}
int[] a = new int[]{1,2,3,4,5,6,7}
//括号中不写长度
直接指定初始化元素,这样就不必写出数组大小,而是由编译器自动推算数组大小
静态省略初始化
数组类型[] 数组名 = {元素0,元素1,…}
int[] a ={1,2,3,4,5,6,7}
省略静态初始化不能拆分为两个步骤
访问数组元素
- 取值
取值格式:数据类型 变量名 = 数组名[索引值];
索引值的取值范围:0到数组长度-1
- 赋值
赋值格式:数组名[索引值] = 对应类型的值;
- 可能出现的问题
数组索引值越界异常:ArrayIndexOutOfBoundsException;
引用数据类型的值为null,继续对变量(对象)进行操作,这时候就会报错,空指针异常:NullPointerException;
数组的内存分析
数组不可变性,同理String类型字符串,改变的是指向
-
栈
存放基本数据类型的变量,以及引用变量的引用
特点:函数中的变量所占用的空间,执行后就会销毁
-
堆
new出来的东西,执行后堆内存的内容(对象)会被标记垃圾,等带垃圾回收机制来回收
数组中的特殊值0和null
-
针对数组本身
-
int[] a = new int [0];
-
int[] b = new int[]{};
-
数组为null,系统没有为其分配内存空间(没有地方只能流浪)int[] c = null;
-
-
数组元素内容
数组元素的值为0或者为null(即默认初始化时侯为空,或者里面素服赋值为n)
Arrays工具类
-
将数组转化为字符串
static String toString(int[] a);
Arrays.toString()方法返回指定数组内容的字符串表示形式
-
填充
-
排序
-
查找
-
拷贝
-
比较长短
数组的特点:
- 定长。容量固定。数组一旦创建后,那么长度不能更改。(容量,长度,都是指存储的数量)
- 存储的数据类型 (可以是任意数据类型)必须都一致。不允许出现混合类型
- 在内存中空间连续
- 数组是引用类型的数据,存在栈和堆的地址引用关系。数组变量属于引用类型 ,数组也是对象
输入和输出语句
输出
print()、println() 和printf()区别
- print():不换行,里面需要写内容
- printlf():自动换行,可以不写内容
- pritnf():不换行,格式化输出,占位
格式化符号
- %d:整数类型占位
- %f:浮点类型占位
- %s:各种类型占位
- %e:浮点类型科学计数法占位
- %x:整数类型十六进制占位
输入
Scanner输入导入import java.util.Scanner;
Scanner sc = new Scanner(System.in);
//数据类型 变量名 = sc.next*();
*可选:
int:.nextInt();
double:.nextdouble();
String:.nextLine();
流程控制
流程控制:用来控制程序中的各语句执行程序的语句,可以把语句组合成能完成一定功能的小逻辑模块
顺序
顺序结构代表先执行a,再执行b的逻辑,按照顺序执行
System.out.println("111");
System.out.println("222");
//运行结果
//111
//222
选择(分支)
if语句
区间判断
单分支
语法格式if…
if(布尔表达式1){
表达式1成立时,执行代码块
}
注意事项:
- 代码块中可以包含多条语句
- if语句块只有一行语句时,可以省略花括号
双分支
语法格式if…else…
if(布尔表达式1){
条件1成立时,需要做的事情
}else{
条件1成立时,需要做的事情
}
注意事项:
- 在语法结构中,else并不是必须的
- else语句块只有一行语句时,可以省略号{}
多分支
语法格式if…else if …else
if(布尔表达式1){
表达式1成立时,需要做的事情
}else if(布尔表达式2){
表达式2成立时,需要做的事情
}else{
不满足上述所有条件做的事情
}
注意事项:
-
使用多个if判断时,需要注意判断顺序(if语句执行顺序是从上到下执行
正确的方式是按照判断范围从大到小依次判断或者改写成从小到大依次判断
-
注意边界条件
-
浮点数判断:由于浮点数在计算机中常常无法精确表示,并且计算可能出现误差,因此,判断浮点数相等用==判断可能存在不准确的情况。
-
引用数据库类型使用equals判断相等
注意事项
- 前面条件为true执行完前面的代码块则代码就结束了。取消 && 条件
- 语句交度else可不写
- 从语法角度,if后面的大括号可以省略情况(if内语句块只有一条语句)同理else也相同
switch语句
等值判断,多分支选择语句
语法格式
switch(表达式){
case 常量表达式1:语句1;break;
case 常量表达式2:语句2;break;
case 常量表达式3:语句3;break;
default:
语句;
}
-
switch:判别表达式取值类型
- 基本数据类型:byte,short,int,char
- 引用数据类型:String(jdk7后添加),枚举
-
csae后面常量不可重复
-
default默认执行
-
语法具有穿透性(向下穿透性时不进行比较)
-
break作用:跳出switch结构(可阻断穿透)
if与switch区别
- 判断条件:
- if:区间判断或等值判断
- switch:等值判断
- 等值判断效率:switch效率更高,switch直接取值跳到对应case,不需要层层判断
循环
“循环结构”代表“如果… ,则重复执行…”的逻辑。就是让计算机根据条件做循环计算,在条件满足时继续循环,条件不满足时退出循环。
while循环
语法:
while(条件判断){
//循环体,条件为为真执行
//自加语句!!!eg:i++;
}
注意:
- 先判断再执行
- 自加语句一定得有,用于循环结束条件,避免产生死循环
do……while循环
语法:
do{
//循环体
//自加语句
}while(条件判断)
注意:
- 先执行一次再判断是否执行后续循环,条件拍段为真执行,为假则结束
- 自加语句
for循环
语法:
for(初始化变量;条件判断为true;步进语句){
//循环体
}
//省略条件判断语句:死循环
//省略条件判断语句和步进判断语句:死循环
//省略初始化变量、条件判断、步进语句:死循环
foreach方法语法:
for(数据类型 元素名:变量名){
//循环体
}
//eg:foreach方法遍历数组
String[] array = {"Java","C++","vscode","web"};
for(String s:array) {
System.out.println(s);
}
注意:
- 执行顺序:初始化变量—>判断条件—>循环体—>步进语句
- 初始化变量只执行一次,后面每次循环不进行初始化
- 如果条件判断取消了默认为true
- 循环体只有一条语句可以省略花括号
- 初始化变量、条件判断、步进语句都可省略,分号不能省略
循环使用场景:
- for循环一般执行循环次数固定且明确的
- while循环与do…while循环更适合不固定次数的循环,因为它们的语法结构更容易表达一个boolean类型的条件表达式
循环控制语句:
-
break:break(在循环和switch中都是结束循环或者分支语句的意思)
起别名braek:
f1:for( ; ;) //f1起别名 { break f1; //停止f1对应的此层循环 }
-
countinue:countinue 结束本次循环(不执行循环体内continue以后的代码,for,去执行步进语句while或者do while去执行条件判断)
数组操作
数组遍历
所谓遍历,是指沿着某条搜索路线,依次对树(或图)中每个节点均做一次访问
两种方法
-
for循环
实现案例:
public class main{ public static void main(String[] args){ int[] ns = { 1, 4, 9, 16, 25 }; for(int i = 0; i < ns.length;i++) //i<ns.length或i<=ns.length-1 { int n = ns[i]; System.out.println(n); } } }
for循环通过索引来访问,即数组的下标
- 索引值从0开始
- 索引值不能超出范围
-
foreach循环
实现案例:
public class Main{ public static void main(String[] args){ int[] ns = { 1, 4, 9, 16, 25}; for(int n : ns ){ System.out.println(n); } } }
foreach循环直接迭代数组的每个元素,而不是索引值
- foreach更加简洁
- foreach无法拿到数组的索引值
冒泡排序
- 冒泡排序步骤
- 比较相邻的元素。如果第一个比第二个大,就交换位置。
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个元素。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
- 冒泡排序特点
每一轮循环后,最大的一个数被交换到末尾,因此,下一轮循环就可以“排除”最后的数(不参与),每一轮循环都比上一轮循环的结束位置靠前一位。
-
记忆
N个数字排序 俩俩比较小考前 总共比较N-1轮(外部循环) 每轮比较N-1-i(内部循环)
-
冒泡排序案例
public static void main(String[] args) { int[] ns = {3,2,4,5,10,11,128,7,8,6}; int length = ns.length; for(int i = 0;i<length-1;i++) { for(int j = 0;j<length-1-i; j++) { if(ns[j]>ns[j+1]) { int temp = ns[j]; ns[j] = ns[j+1]; ns[j+1] = temp; } } } System.out.println("冒泡排序后"); System.out.println(Arrays.toString(ns)); }
-
Arrays工具类排序
Arrays.sort()方法;
import java.util.Arrays; //导入Arrays工具类 public class Test05 { public static void main(String[] args) { int[] ns = {3,2,4,5,10,11,128,7,8,6}; System.out.println("排序前"+Arrays.toString(ns)); Arrays.sort(ns); //默认升序 System.out.println("排序后"+Arrays.toString(ns); } }
折半查找/二分查找
用于查找元素
-
可以通过循环遍历或者Arrays工具类两种方式进行查找
-
Arrays.binarySearch(a, key)方法
import java.util.Arrays; //导入Arrays工具类 public class Test01 { public static void main(String[] args) { int[] a = {1,2,3,4,5,6,7}; int i = Arrays.binarySearch(a, 5); //(Object[],Object) //第一个参数写数组名,第二个参数写目标元素 System.out.println(i); //输出元素5的下标 } } //若找不到则i输出为负数
-
双指针遍历查找:通过两个下标分别从数组得头部和尾部,同时 对该数组进行遍历,将数组中的每个元素与指定元素进行比较
-
折半查找:前提数组有序,如果需要进行指定元素的查找,可以用折半查找算法,提高查找元素的效率
实现案例:
// 折半查找(二分查找)查找数组元素11 public static void main(String[] args) { int[] a = {2,3,4,5,6,7,8,9,11,12,16,19}; int target = 11; int index = -1; int low = 0; int height = a.length; while(low <=height) { int mid = (low+height)/2; if(target == a[mid]) { index = mid; break; } if(target> a[mid]) { low +=1; } if(target < a[mid]) { height = height-1; } } System.out.println("下标是"+index); }
-
总结:
- 查找指定元素分为两种情况:无序数组查找和有序数组查找
- 无序数组可以通过遍历数组或Arrays工具类两种方式查找指定元素
- 有序数组可以通过折半查找查找指定元素
洗牌算法
用于数组乱序
实现案例:
public static void main(String[] args) {
int[] a = {0,1,2,3,4,5,6,7,8,9,10};
for (int i = 0; i < a.length-1; i++) {
int index = (int)(Math.random()*i);
int temp = a[i];
a[i] = a[index];
a[index] = temp;
}
System.out.println(Arrays.toString(a));
}
//实现步骤:
//有数组a等待乱序
//从a中随机抽取一个为乱序的元素
//将该元素与数组a中最后一个为乱序的元素交换
//重复上两步
数组合并
用于数组合并
-
无序数组:复制元素方式
-
循环方法
-
System.arraycopy()方法
import java.util.Arrays; public class Test09 { public static void main(String[] args) { int[] ns = {1,2,3,4,5}; int[] newns = new int[10]; System.arraycopy(ns, 2, newns, 4, 3); System.out.println(Arrays.toString(newns)); //参数一:被复制数组名 //参数二:被复制的起始元素下标 //参数三:复制后的新数组 //参数四:新数组存放复制元素的起始 //参数五:复制的长度 } } //输出结果:[0, 0, 0, 0, 3, 4, 5, 0, 0, 0]
-
-
有序数组:
-
循环方法: 实现案例
public static void main(String[] args) { int[] a1 = {1,3,5,7,9}; int[] a2 = {2,4,6,8}; int[] a3 = new int[a1.length+a2.length]; for(int i=0;i<a1.length;i++) { a3[i]=a1[i]; } for(int j =a1.length,i=0 ;j<a1.length+a2.length; j++,i++) { a3[j] = a2[i]; } System.out.println(Arrays.toString(a3)); }
-
双指针: 实现案例
public static void main(String[] args) { int[] a1 = {1,3,5,7,9}; int[] a2 = {2,4,6,8}; int L = a1.length + a2.length; int[] a3 = new int[L]; for (int i = 0,j =a1.length; i<a1.length||j<L ; i++,j++) { if(i<a1.length) { a3[i] = a1[i]; } if(j<L) { a3[j] = a2[j-a1.length]; } } System.out.println(Arrays.toString(a3)); }
-
-
有序数组合并且合并后数组有序: 前提合并的两个数组有序
实现案例
//合并数组且合成后的数组有序 int[] a1 = {2,4,6,8,10}; int[] a2 = {1,3,5,7,9}; int[] a3 = new int[a1.length+a2.length]; int i=0,j=0,k=0; while (i<a1.length&&j<a2.length) { if(a1[i]<a2[j]) { a3[k] = a1[i]; i++; k++; }else if(a1[j]>a2[i]) { a3[k] = a2[j]; j++; k++; } } //存放剩余的 if(i<a1.length) { for(int m=i; m<a1.length ; m++) { a3[k] = a1[m]; k++; } } if(j<a2.length) { for(int n=j; n<a2.length ;n++) { a3[k] = a2[j]; k++; } } System.out.println(Arrays.toString(a3));
数组旋转
-
循环
public class Test01 { public static void main(String[] args) { int[] ns = {1,3,4,5,6,7,8}; int[] newns = new int[7]; int temp=4; for(int i = 0;i<ns.length;i++) { newns[(i+temp)%ns.length] = ns[i]; //核心思想 } System.out.println(Arrays.toString(newns)); } } //输出结果:{6,7,8,1,3,4,5}
-
双指针循环(冒泡排序思想)
//右旋转 public class Test02 { public static void main(String[] args) { int[] ns = {1,3,5,7,9}; int count = 3; //右旋转位数 for(int i = 0;i<count;i++) { for(int j=ns.length-1 ; j>0 ;j--) { int temp = ns[j]; ns[j] = ns[j-1]; ns[j-1] = temp; } } System.out.println(Arrays.toString(ns)); } } //输出结果:{7,9,1,3,5}
二维数组操作
public class Test04 {
public static void main(String[] args) {
int[][] a = {
{1,2,3,12,34,9},
{2,3,4,6,7,8,},
{3,4,5}
};
//二维数组赋值,可不写元素,但是逗号“,”不能省略
System.out.println(Arrays.deepToString(a));
//Arrays方法输出二维数组
System.out.println("--------------------");
for(int i=0;i<a.length;i++) {
for(int j=0;j<a[i].length;j++) {
System.out.printf(" %d " ,a[i][j]);
}
System.out.println();
}
//for循环输出二维数组
System.out.println("-------------------");
for (int[] is : a) {
for (int i : is) {
System.out.printf(" %s ",i);
}
System.out.println();
}
//foreach循环输出二维数组
}
}