-------android培训、java培训、期待与您的交流-------
01数组(静态初始化-常见问题)
int[] arr = new int[3];
System.out.println(arr[2]);
int[] arr = new int[3];
System.out.println(arr[3]); //编译通过,运行时报错
//ArrayIndexOutOfBoundsException:3 操作数组时,访问到了数组中不存在的角标
int[] arr = new int[3];
arr = null; //arr都不再指向数组了,和数组都没关系了,你怎么能操作数组中的1角标元素呢
System.out.println(arr[1]);
//NullPointerException: 空指针异常:当引用没有任何指向值为null的情况,该引用还在用于操作实体
02数组(常见操作-遍历)
数组的操作
获取数组中的元素(最常见的操作),通常会用到遍历
int[] arr = new int[3];
for(int x=0; x<3; x++)
{
System.out.println("arr["+x+"]="+arr[x]+";");
}
int[] arr ={3,6,5,1,7,8};
//数组中有一个属性可以直接获取到数组元素个数:length
//使用方式:数组名称.length =
System.out.println("length:"+arr.length);
for(int x=0; x<arr.length; x++)
{
System.out.println("arr["+x+"]="+arr[x]+";");
}
但凡有数组的情况下,通常都要用到for循环(因为要将里面的数据取出来用)。
小练习:
//定义功能,用于打印数组中的元素,元素间用逗号隔开
public static void printArray(int[] arr) // 没有结果,因为打印出去了
// 有未知内容参与运算吗? 要打哪个数组不知道, 接收进来一个数组类型的参数
{
System.out.print("[");
for(int x=0; x<arr.length; x++)
{
if(x!=arr.length-1)
System.out.print(arr[x]+",");
else
System.out.println(arr[x]+"]"); //打完最后一个元素换行
}
}
System.out.println(arr); //输出数组地址 嘻哈值(十六进制)
03数组(常见操作-获取最值)
给定一个数组{5,1,6,4,2,8,9}
1.获取数组中的最大值,以及最小值 只适用与数值型数组
思路:
1.获取最值需要进行比较,每一次比较都会有一个较大的值,因为该值不确定,通过一个变量进行临时存储
2.让数组中的每一个元素都和这个变量中的值进行比较
如果大于了变量中的值,就用该变量记录最大值
3.当所有的元素都比较完成,那么该变量中存储的就是数组中的最大值了
步骤:
1.定义变量,初始化为数组中任意一个元素即可
2.通过循环语句堆数组进行遍历
3.在变量过程中定义判断条件,如果遍历到的元素比变量中的元素打,就赋值给该变量
需要定义一个功能来完成,以便提高复用性
1.明确结果,数组中的最大元素 int
2.未知内容:一个数组:int[]
public static int getMax(int[] arr) // 获取最大值 定义一个变量接收要存的数组
{
int max = arr[0];
for(int x=1;x<arr.length; x++) // 对数组进行遍历
{
if(arr[x]>max) // 遍历到的元素大于我变量里存的那个
max = arr[x]; // 用变量记录住大的那个元素
}
return max;
}
获取最大值的另一种方式:
可不可以将临时变量初始化为0呢?可以,这种方式,其实是在初始化为数组中任意一个角标
0不是作为元素存在,而是作为角标存在
public static int getMax_2(int[] arr)
{
int max = 0;
for(int x=1;x<arr.length; x++) // x是1,1角标的元素
{
if(arr[x]>arr[max]) // max是0,0角标的元素 两个比较
max = x; // 用max记录住大的元素的角标
}
return arr[max];//返回的时候,max中存的就已经是数组中最大元素的角标,那么你用这个角标去拿数组中的元素就是数组中的最大值
}
获取最小值
public static int getMin(int[] arr)
{
int min = 0;
for(int x=1; x<arr.length; x++)
{
if(arr[x]<arr[min])
min = x;
}
return arr[min];
}
获取double类型数组的最大值,因为功能一致,所以定义相同函数名称,以重载形式存在
public static double getMax(double[] arr)
04数组(排序-选择排序)
//内循环结束一次,最值出现头角标位置上
每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。 选择排序是不稳定的排序方法
public static void selectSort(int[] arr)
{
for (int x=0; x<arr.length-1;x++) // 遍历数组中的第一个元素 拿这个元素和其他元素挨个比 列的概念 内循环做的动作
//当取到最后一个角标时,就剩一个数了,不需要就行比较了,所以在取时没有遍历到最后一个角标 因此这里是length-1 这里-1可以减少一次比较
{
for(int y=x+1; y<arr.length; y++); //外循环在控制次数
{ //x+1 如果写成x 那么你拿外循环的0角标元素和内循环的0角标元素比 就没有意义 应该和1角标元素比 所以写成x+1 就能够保证一直是前后这么比的
if(arr[x]>arr[y])
{
int temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
}
}
}
选择排序法的第一层循环从起始元素开始选到倒数第二个元素,主要是在每次进入的第二层循环之前,将外层循环的下标赋值给临时变量,接下来的第二层循环中,如果发现有比这个最小位置处的元素更小的元素,则将那个更小的元素的下标赋给临时变量,最后,在二层循环退出后,如果临时变量改变,则说明,有比当前外层循环位置更小的元素,需要将这两个元素交换
05数组(排序-冒泡排序)
冒泡排序:相邻的两个元素进行比较,如果符合条件换位
冒泡排序,是指计算机的一种排序方法,它的时间复杂度为O(n^2),虽然不及堆排序、快速排序的O(nlogn,底数为2),但是有两个优点:1.“编程复杂度”很低,很容易写出代码;2.具有稳定性,这里的稳定性是指原序列中相同元素的相对顺序仍然保持到排序后的序列,而堆排序、快速排序均不具有稳定性。不过,一路、二路归并排序、不平衡二叉树排序的速度均比冒泡排序快,且具有稳定性,但速度不及堆排序、快速排序。冒泡排序是经过n-1趟子排序完成的,第i趟子排序从第1个数至第n-i个数,若第i个数比后一个数大(则升序,小则降序)则交换两数
冒泡排序(BubbleSort)的基本概念是:依次比较相邻的两个数,将小数放在前面,大数放在后面。即在第一趟:首先比较第1个和第2个数,将小数放前,大数放后。然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后。至此第一趟结束,将最大的数放到了最后。在第二趟:仍从第一对数开始比较(因为可能由于第2个数和第3个数的交换,使得第1个数不再小于第2个数),将小数放前,大数放后,一直比较到倒数第二个数(倒数第一的位置上已经是最大的),第二趟结束,在倒数第二的位置上得到一个新的最大数(其实在整个数列中是第二大的数)。如此下去,重复以上过程,直至最终完成排序。
由于在排序过程中总是小数往前放,大数往后放,相当于气泡往上升,所以称作冒泡排序。
用二重循环实现,外循环变量设为i,内循环变量设为j。假如有10个数需要进行排序,则外循环重复9次,内循环依次重复9,8,...,1次。每次进行比较的两个元素都是与内循环j有关的,它们可以分别用a[j]和a[j+1]标识,i的值依次为1,2,...,9,对于每一个i,j的值依次为1,2,...10-i。
在许多程序设计中,我们需要将一个数列进行排序,以方便统计,而冒泡排序一直由于其简洁的思想方法而倍受青睐。
第一圈:最值出现了最后位
public static void bubbleSort(int[] arr)
{
for (int x=0; x<arr.length-1;x++)
{
for(int y=0; y<arr.length-x-1; y++); //-x:让每一次比较的元素减少,-1:避免角标越界
{
if(arr[y]>arr[y+1]) // >从大到小,< 从小到大
{
int temp = arr[y];
arr[y] = arr[y+1];
arr[y+1] = temp;
}
}
}
}
排序方式中最快的是希尔排序:三层循环加上位运算 速度最快,效率最高
学这些的目的:明白一些排序的算法;为了应付面试
为什么性能低:原理(每一次符合条件,我们都会在数组当中对数组内部的元素进行位置的置换,而堆内存中换位置比较消耗资源,)我们能不能说:如果两个数需要换位置的话,先不置换他们的位置,先把他们需要置换位置的角标以及元素在栈内存中定义两个变量临时记录下来,当我比较完后我取最终换位置的值就可以了 就是把在堆内存中频繁的换位置转移到栈内存当中,堆内存中第一圈比较就换一次位置
06数组(排序-位置置换功能抽取)
发现无论什么排序,都需要对满足条件的元素进行位置置换,所以可以把这部分相同的代码提取出来,单独封装成一个函数
public static void swap(int[] arr,int a,int b)
{
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp; // 用异或方式也行,不用第三方变量
}
Arrays.sort(arr);//java中已经定义好的一种排序方式。开发中,对数组排序,要使用该句代码
07数组(折半查找)
数组中的查找操作
//定义功能,获取key第一次出现在数组中的位置,如果返回是-1,那么代表该key在数组中不存在
public static int getIndex(int[] arr,int key)
{
for(int x=0; x<arr.length; x++)
{
if(arr[x]==key)
return x;
}
return -1; //数组的角标都是从0开始的,没有找到可以用一个负数表示,代表这个角标不存在,也就是这个数不存在
}
折半查找:提高效率,但是必须要保证该数组时有序的数组
public static int halfSearch(int[] arr,int key)
{
int min,max,mid;
min = 0;
max = arr.length-1; //最大角标
mid = (max+min)/2;
//折半的动作在没有找到时会重复的去做,所以要用循环来表示
while(arr[mid]!=key) //拿中间值的元素不等于key来作为条件
{
if(key>arr[mid])
min = mid + 1;
else if(key<arr[mid])
max = mid - 1;
if(min>max)
return -1;
mid = (max+min)/2;
}
return mid;//如果连个条件都没满足相当于找到了,return角标值
}
折半的第二种方式:
其实就是不断的找中间值
public static int halfSearch_2(int[] arr,int key)
{
int min =0,
max =arr.length-1,mid;
while(min<=max)
{
mid = (max+min)>>1;//相当于除2
if(key>arr[mid])
min = mid + 1;
else if(key<arr[mid])
max = mid - 1;
else
return mid;
}
return -1;
}
08数组(十进制-二进制)
public static void toBin(int num) //因为要打印所以没有返回值类型
{
while(num>0)
{
System.out.println(num%2); //num%2是那个二进制的值
num = num/2; num要逐渐变小
}
}
public static void toBin(int num)
{
StringBuffer sb = new StringBuffer();//用来存放数据(容器)
while(num>0)
{
sb.append(num%2); //添加方法:算一个数加一个(都存放在内存中)
num = num/2;
}
System.out.println(sb.reverse()); //sb是存的顺序 sb.reverse是将存放的数据进行反转
}
09数组(十进制-十六进制)
public static void toHex(int num)
{
for(int x=0;x<8;x++) //因为十六进制中一共是八组二进制
{
int temp = num & 15;
if(temp>9)
System.out.println((char)temp-10+'A')
else
System.out.println(temp);
num = num >>> 4;
}
}
public static void toHex(int num)
{
StringBuffer sb = new StringBuffer();
for(int x=0;x<8;x++)
{
int temp = num & 15;
if(temp>9)
//System.out.println((char)(temp-10+'A'))
sb.append((char)temp-10+'A')
else
//System.out.println(temp);
sb.append(temp);
num = num >>> 4;
}
System.out.println(sb.reverse());
}
10数组(查表法十进制-十六进制)
0 1 2 3 4 5 6 7 8 9 A B C D E F ==十六进制中的元素
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
先把十六进制中的这些元素全都列出来存到一个表里(这个表里面都有一一对应的关系),存完以后拿每一次&完15后的值去到存放位置去找,就可以找到对应的十六进制中的元素。
查表法:将所有的元素临时存储起来,建立对应关系。每一次&15后的值作为索引去查建立好的表,就可以找对应的元素。这样比-10+'a'简单的多
这个表怎么建立呢? 可以通过数据的形式来定义。
1_ 结果是反着的
public static void toHex(int num)
{
//数组应该定义什么类型的元素(表里面是数字和字母,所以用char类型)
char[] chs = {'0','1','2','3',
'4','5','6','7',
'8','9','A','B',
'C','D','E','F',};
for(int x=0; x<8; x++)
{
int temp = num & 15;
System.out.println(chs[temp]);
num = num >>> 4;
}
}
2_ 结果中会有很多空位
//发现终于出结果了,但是是反着的。想要正过来呢?可以通过StringBuffer功能来完成,但是这个工具还没有学习。所以可以使用已经学习过的容器:数组来完成存储
public static void toHex(int num)
{
char[] chs = {'0','1','2','3',
'4','5','6','7',
'8','9','A','B',
'C','D','E','F',};
//定义一个临时容器:数组。因为你查表查到的都是字符,存的时候也是字符数组
//字符数组在内存中一被定义,它的默认初始化值是'\u0000'(相当于一个空类(空格))
char[] arr = new char[8];
for(int x=0; x<8; x++)
{
int temp = num & 15;
arr[x] = chs[temp];
num = num >>> 4;
}
//存储数据的arr数组遍历
for(int x=0; x<arr.length; x++)
{
System.out.print(arr[x]+",");
}
3_ 倒着打印
//要想反转,倒着打印
for(int x=0; x<arr.length; x++) // for(int x=arr.length-1;x>=0; x--)
{ //最终正确结果,空位也没有了,正常结果也出来了
System.out.print(arr[x]+","); // for(int x=pos-1;x>=0; x--)
}
4_ 去掉0 但是x就不爽了
while(num!=0)
{
int temp = num & 15;
arr[x] = chs[temp];
num = num >>> 4;
}
5_ 定义一个指针 最终结果
char[] arr = new char[8];
int pos = 0; //定义一个指针
while(num!=0)
{
int temp = num & 15;
arr[pos] = chs[temp]; // arr[pos++] = chs[temp];
pos++; // 和 arr[pos++] 性质一样
num = num >>> 4;
}
//存储数据的arr数组遍历
for(int x=pos-1;x>=0; x--)
{
System.out.print(arr[x]+",");
}
}
————————————
正着打印
char[] arr = new char[8];
int pos = arr.length-1;
while(num!=0)
{
int temp = num & 15;
arr[pos--] = chs[temp];
num = num >>> 4;
}
for(int x=pos; x<arr.length; x++)
{
System.out.print(arr[x]+",");
}
下面一种结果是最终的最完美结果
char[] arr = new char[8];
int pos = arr.length;
while(num!=0)
{
int temp = num & 15;
arr[--pos] = chs[temp];
num = num >>> 4;
}
System.out.println("pos="+pos);
for(int x=pos; x<arr.length; x++)
{
System.out.print(arr[x]+",");
}
11数组(查表法十进制-二进制)
public static void toBin(int num)
{
char[] chs = {'0','1'}; //定义二进制的表
char[] arr =new char[32]; //定义一个临时存储容器
int pos = arr.length; //定义一个操作数组的指针
while(num!=0)
{
int temp = num & 1;
arr[--pos] = chs[temp];
num = num >>> 1;
}
for(int x=pos; x<arr.length; x++)
{
System.out.print(arr[x]);
}
}
12数组(进制转换优化)
将上述两个功能中的共性内容抽取出来
十进制——>二进制
public static void toBin(int num)
{
trans(num,1,1);
}
十进制——>八进制
public static void toBin(int num)
{
trans(num,7,3);
}
十进制——>十六进制
public static void toBin(int num)
{
trans(num,15,4);
}
//功能函数
public static String trans(int num,int base,int offset) //转换方法;num未知;&上的数未知;
{ // 偏移位不一样
if(num==0)
{
System.out.println(0); // 打印完后,下面的程序不需要在内存中运行,直接一个return,结束程序
return;
}
char[] chs = {'0','1','2','3',
'4','5','6','7',
'8','9','A','B',
'C','D','E','F',};
char[] arr =new char[32];
int pos = arr.length;
while(num!=0)
{
int temp = num & base;
arr[--pos] = chs[temp];
num = num >>> offset;
}
for(int x=pos; x<arr.length; x++)
{
System.out.print(arr[x]);
}
}
13数组(二维数组)
数组中的数组
int[] arr = new int[3]; 一维数组
格式1:int[][] arr = new int[3][2];
定义了名称为arr的二维数组
二维数组中有3个一维数组
每一个一维数组中有2个元素
一维数组的名称分别为arr[0],arr[1],arr[2]
给第一个一维数组1角标位赋值为78写法是:arr[0][1] = 78;
格式2:int[][] arr = new int[3][];
二维数组中有3个一维数组
每一个一维数组都是默认初始化值null
可以对这三个一维数组分别进行初始化
arr[0] = new int[3];
arr[1] = new int[1];
arr[2] = new int[2];
System.out.println(arr.length);//打印是二维数组的长度3;
System.out.println(arr[0].length);//打印二维数组中第一个一维数组长度
int[][] arr = {{3,5,1,7},{2,3,5,8},{6,1,8,2},};//有什么应用:数据存储:数据间有关系,再找到关系再进行存储,这就是二维数组 数组的二维方式是用角标来标识的
int sum = 0;//一说求和,就定义一个变量
for(int x=0; x<arr.length; x++)
{
for(int y=0; y<arr[x].length; y++)
{
sum = sum + arr[x][y];
}
}
System.out.println("sum"+sum);
——————————————————————————————————————————————
&14数组(二维数组练习)
一维数组定义方式:int[] x; int x[];
二维数组定义方式:int[][] y; int y[][]; int[] y[];
int[] x,y[];//x一维,y二维 基本上不这样定义
分开来就是
int[] x;
int[] y[];
a
x[0] = y;//将一个二维数组赋值给一个一维数组中的元素,error
b
y[0] = x;//将一个一维数组赋值给一个二维数组,yes
c
y[0][0] = x;//二维数组中的一维数组元素把它赋值为一个一维数组是不合适的,error
d
x[0][0] = y;//x根本就不是二维数组,error
e
y[0][0] = x[0];//元素给元素赋值,yes
f
x=y;//error