程序调试
数组基础
引入数组
1.在程序中保存数据使用哪种方式,又有什么特点?
使用变量保存数据,1个变量只能存一个数据。。。
2.比如有10个学生的成绩需要保存起来?
定义10个变量保存数据没有任何问题
提出问题如果我想对这10个学生的成绩进行排序该怎么实现? 100个呢?
回顾:3个变量找最大值最小值,如果要排序呢?
int num1=?,num2=?,num3=?;
int max=num1>num2?num1:num2;
max=max<num3?num3:max;
int min=num1<num2?num1:num2;
min=min>num3?num3:min;
-------------------------------------------------
3个数排序: 6种排法
4个数排序: 24种排法
----------------------------
<1>.使用数组可以很好的解决上述问题
对于排序问题:冒泡排序,选择排序,插入排序,快速排序,希尔排序...
不仅如此一个数组可以存储多个数据
数组:数组的本质就是一个变量...(引用类型)
数组概述
数组:用来存储一组数据类型相同的数据(多个数据,多个数据必须属于同一种类型)
数组的定义方式
数组的基本格式:
方式1: 定义了一个长度为10的空数组
数据类型[] 变量名=new数据类型[数组的长度];
举例子说明:
int[] arr01=new int[10]//建议使用此种写法...
<==>
int arr01[]=new int[10]
定义了一个int类型的数组,长度为10(arr01只能存储10个int类型的数据)
定义方式2: 定义数组,并且往数组中直接添加数据,(数组的长度=数据的个数)
数据类型[] 变量名={数据1,数据2,数据3,数据4,...}
int[] arr02={67,56,89,45,69};
其他任意类型写法与上述一样...
字符串数组:
String[] arr03={"jack","rouse","tina","charles"};
往数组中添加以及修改数据(元素)
int[] arr01=new int[10];
使用下标往数组中添加元素
//1.将数据插入到数组中的1号位置(数组编号是从0开始,下标0 代表数组中第一个位置,依次类推)
arr01[0]=100;
//2.将数据插入到数组中的5号位置
arr01[4]=300;
-----------------------------------------------
//3.将数据插入到数组中的11号位置(数组越界) 错误写法
arr01[10]=500;
--------------------------------------------------
//4.将5号位置的300修改成999
arr01[4]=999; //修改完成
扩展:
获取数组的长度:arr01.length(数组中能够存放的最大数据量/数组的最大下标+1)
arr01.length=数组的最大下标+1
<==>
最大下标=arr01.length-1;
练习1:
控制台输入5个成绩,将这5个成绩保存到指定数组中,要求打印第一个和第五个学生的成绩,如果第三个学生的成绩没有及格将第三个学生的成绩修改成60分。
数据的遍历
int[] arr01=new int[?];
分析
取出数组中元素
arr01[0]:取出1号位置元素 第一次循环
arr01[1]:取出2号位置元素 第二次循环
.....
arr01[arr01.length-1]: 取出最后一个元素 第arr01.length 次循环
从数组中逐一取出数据,只需要改变下标即可,其他内容固定
而且下标的取值范围也是固定的为[0,arr01.length-1]或者 [0,arr01.length) 建议
for(int i=0;i<arr01.length;i++){
sout...(arr01[i]);
}
<1>.从控制台输入5句话,将5句话存入数组中,要求使用简单for循环 顺序遍历这5句话,然后再写一个简单for循环要求倒序输出这5句话?
//1.定义数组 5(String)
//2.定义for循环输入5句话并且顺序保存到数组中
//3.定义for循环遍历输出这5句话
//4.定义for循环倒序遍历输出这5句话.
<2>.定义一个字符数组,往字符数组中存入字母(大写,小写字母),以及数字(0-9)
//1.定义数组(62)
//2.循环存入小写字母 'a'-'z'
//3.循环存入大写字母'A'-'Z'
//4.循环存入数字'0'-'9'
实现随机验证码
<3>.实现登录+验证码功能
//1.输入用户名
//2.输入密码
//3.输入验证码(随机产生一个验证,看不清,可以换一张):要求使用数组
验证码输入正正确的前提下才会去验证用户名以及密码
(适当考虑优化)
---------------------------------------------------------------------------------
<4>.数据统计的问题,String[] strArr01={"apple","orange","banana","watermelon","apple","watermelon","banana","banana"};
统计各个水果出现的次数?
apple 2
orange 1
watermelon 2
banana 3
<5>.数组去重的问题
String[] strArr01={"apple","orange","banana","watermelon","apple","watermelon","banana","banana"};
去重之后==>{"apple","orange","watermelon","banana"}
public class Solution {
public static void main(String[] args) {
String[] arr = {"apple","banana","orange","apple","juice"};
Arrays.sort(arr);
int n = arr.length;
for (int i = 0; i < n; i++) {
System.out.println(arr[i]);
}
System.out.println("========================");
int slow = 0; //慢指针
//快指针
for (int fast = 1; fast < n; fast++) {
if(!arr[fast].equals(arr[slow]))
arr[++slow] = arr[fast];
}
slow += 1;
String[] Arr = new String[slow];
for (int i = 0; i < slow; i++) {
Arr[i] = arr[i];
System.out.println(Arr[i]);
}
}
}
数组内存分析
一维数组内存图解
定义数组,会默认设置相应的默认值
<1>.整数类型数组:
byte,short,int,long默认值都是0
比如:
int[] arr01=new int[5];
arr01[0] 值为0
<2>.小数类型数组:
float,double默认值为 0.0
<3>.字符类型数组:' ';
<4>.boolean类型数组默认值 false;
<5>.引用类型的数组默认值:null;
"":属于字符串类型的一个数据,所以定义一个空字符串会占用内存空间
null:本身是一个不存在的数据,所以不会占用内存空间,可以作为所有的引用类型的初始值。
提前说明一下:作为类的属性,如果属性是应用类型,默认值就是null
多维数组(了解)
多维数组的基本使用
二维数组:就是将若干个一维数组作为另一个一维数组的元素
int[] arr01={1,3,4,6};
int[] arr02={2,4,8}
//1.方式一:定义数组
int[][] arr01= {{1,2,3},{4,5,6},{7,8}};
//2.方式二:定义一个空的二维数组 (由3个长度为5的一维数组组成)
int[][] arr02=new int[3][5];
//3.方式三:定义一个二维数组,指定元素的个数,但是元素的长度不固定(了解)
int[][] arr03=new int[3][];
arr03[0]=new int[]{1,2,3};
arr03[1]=new int[]{4,5};
arr03[2]=new int[] {6,7,8,9};
遍历以及修改二维数组中的元素:
三维数组:
就是将若干个二维数组作为另一个一维数组的元素
依次类别:
多维数组的内存图解
补充
数组的拷贝
数组拷贝:将一个数组复制一份粘贴给另一个数组
数组的浅拷贝
数组的浅拷贝:将数组的地址赋值给另一个变量
int[] arr01=new int[3];
int[] arr02=arr01;
arr02[0]=999;
请问arr01[0]是0还是999呢?(如下图所示)
999
数组深拷贝
数组的深拷贝:就是将数组中的元素一一对应赋值给另一个数组
方式一:
int[] arr01={56,67,78};
int[] arr02=new int[arr01.length];
for(int i=0;i<arr01.length;i++){
arr02[i]=arr01[i];
}
arr02[0]=999;
arr01[0]=? //999还是56 ;
56
方式二:
int[] arr01={56,67,78};
//克隆:深拷贝
int[] arr02=arr01.clone();
arr02[0]=999;
arr01任然是56;
System.arrayCopy方法
public class Solutio_07 {
public static void main(String[] args) {
int[] array = {1,2,3,4,5,6};
int[] array2 = new int[6];
System.arraycopy(array,0,array2,0,array.length);
System.out.println("拷贝数值类型:");
System.out.println(Arrays.toString(array));
System.out.println(Arrays.toString(array2));
}
}
System.arrayCopy方法
数组排序
1.冒泡排序
1.冒泡排序的排序原则:
<1>.相邻2个元素之间两两比较,满足交换条件则进行交换。
<2>.这样每一轮下来都可以找到一个最大值(顺序排列)或者一个最小值
<3>.如果数组中由n个元素,总共需要比较n-1轮?
<4>.每一轮都是在剩余的元素中,相邻2个元素进行两两比较,比较的次数随着轮数的增加而减少?
每一轮比较(n-当前的轮数)
补充一个内容:
int num1=100;
int num2=200;
如何交换num1与num2的值?
方式1:(必须掌握)
int temp=num1;//100
num1=num2;//200
num2=temp;//100
方式2:不使用中间遍历(自行理解)
num1=num1+num2;//300
num2=num1-num2;//100
num1=num1-num2;//200
冒泡排序的代码实现:
<1>.总共比较n-1轮即可 (外层循环决定比较的轮数)
<2>.每一轮比较的次数为 n-对应的轮数(内层决定对应轮数比较的次数)
int[] arr= {45,24,78,67,44,100,97,12,190};
//1.外层循环决定比较的轮数(轮数=arr.length-1)
for(int i=1;i<arr.length;i++) {
//2.内层循环决定对应轮数比较的次数(比较的次数=arr.length-对应的轮数)
for(int j=0;j<arr.length-i;j++) {
//3.顺序排:小的要在上面
if(arr[j]>arr[j+1]) {//满足顺序排列的条件,进行交换
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
//2.遍历数组
for(int i=0;i<arr.length;i++) {
System.out.println(arr[i]);
}
冒泡排序第一轮:
冒泡排序第二轮
2.选择排序
int[] arr={40,34,57,68,45};
选择排序比较的原则:
<1>.假设一个位置为最大值或者最小值与其他的元素进行一一比较(打擂台思想)
<2>.由于每一轮都能够找到一个最大值或者一个最小值,所以完全排好序,需要比较arr.length-1轮
<3>.每一轮比较的次数逐渐递减(对应轮数比较的次数=arr.length-轮数)
代码实现:
1.利用外层循环控制比较轮数(arr.length-1)
2.利用内层循环控制对应轮数比较的次数(arr.length-轮数)
int[] arr= {40,34,68,57,45,100,90,78};
for(int i=0;i<arr.length-1;i++)
{//1.比较轮数=length-1
//对应length-轮数
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;
}
}
}
System.out.println(Arrays.toString(arr));
第一轮循环
第二轮循环
动态数组(扩展)
1.循环往数组中添加数据,如果超过数组的长度,那么要求自动扩容1.5倍
arr.length+arr.length>>1