break和continue的使用范围:
continue只能用于循环结构,也就是说只要有continue,肯定存在循环.
break用在switch语句和循环结构中.
break和continue单独存在时,下面不可以有任何语句,因为执行不到(会报错)
函数重载(overload)
同一个类中允许存在一个以上的同名函数,只要它们的 参数类型/参数个数/参数类型顺序 不同,跟 返回类型 无关.
Java中的数组:
首先了解下:
在函数中定义的一些 基本类型的变量(short,int,char,long,double,byte,boolean,float),和 对象的引用变量(int[ ] x等) 都是在函数的栈内存中分配,
当在一段代码块(也就是一堆花括号{ }之间)定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java会自动释放掉为该变量
所分配的内存空间,该内存空间可以立即被另作他用.
堆内存用来存放由 new创建的对象和数组 ,在堆中分配内存,由JVM的自动垃圾回收器来管理.在堆中产生了一个数组或对象后,还可以在栈中定义一个特殊
的变量,让栈中的这个变量的取值 等于 数组 或 对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量,以后就可以在程序中使用栈中的引用
变量来访问堆中的数组或对象,引用变量相当于是为数组或对象起的一个名称(叫代号也行).
引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到其作用域之外后被释放.
而数组和对象本身在 堆 中 分配,即使程序运行到使用new产生数组和对象的语句所在的代码块之外,数组和对象本身占据的内存不会被释放,数组和对象在没有引用
变量指向它时,才会变为垃圾,不能再被使用,但仍然占据内存空间不放,在随后一个不确定的时间被 垃圾回收器 收走(释放掉).这也是Java比较占内存的原因.
举例:
int[ ] x;//定义了一个数组x,这条语句的执行完后的内存状态如下
x=new int [3];//数组初始化,内存状态如下
然后测试一下各种类型数组的默认值:
class ArrayTest
{
public static void main(String[] args)
{
//int,double,float,char型数组默认值
int[] n=new int[3];
System.out.println("int "+n[1]);//0
char[] c=new char[3];
System.out.println("char "+c[1]);//ASCII码为0的空字符:'\0'
float[] f=new float[3];
System.out.println("float "+f[1]);//0.0f(加f为了说明是float型)
double[] d=new double[3];
System.out.println("double "+d[1]);//0.0
boolean[] b=new boolean[3];
System.out.println("boolean "+b[1]);//false
}
}
两个经典的排序冒泡和选择:
示例:
import java.util.*;
class sort
{
/*
冒泡排序:(从小到大,从零趟开始为了操作方便)
算法思想:
相邻两个数比较,两两比较得到的较大数不断后移,
最终每趟最大沉底.
示例:下标 0 1 2 3 4
i 5 3 7 9 1
3 5 7 9 1 5>3交换
第零趟: 3 5 7 9 1 5<7不动
3 5 7 9 1 7<9不动
3 5 7 1 9 9>1交换-->9为最大,arr[4]为9
共比较4(arr.length-0(趟数)-1)次
第一趟: 3 5 7 1 -->9不用在参与比较
3 5 7 1 3<5不动
3 5 7 1 5<7不动
3 5 1 7 7>1交换-->7为次大,arr[3]为7
共比较3(arr.length-1-1)次
第二趟: 3 5 1 -->7不用再参与比较
3 5 1 3<5不动
3 1 5 5>1交换-->arr[2]为5
共比较2(arr.length-2-1)次
第三趟: 3 1 -->5不用再参与比较
1 3 3>1交换-->arr[1]为3
共比较1(arr.length-3-1)次
共走了4(arr.length-1)趟
最后一定剩余一个数字1,不用再参与比较,肯定最小
*/
//交换
public static void swap(int[] b,int i,int j)
{
int temp=b[i];
b[i]=b[j];
b[j]=temp;
}
//冒泡排序
public static void bubbleSort(int[] a)
{
for(int i=0;i<a.length-1;++i)//控制趟数
for(int j=0;j<a.length-i-1;++j)//控制每趟比较的次数
if(a[j]>a[j+1])
swap(a,j,j+1);
}
/*
选择排序:(从小到大)
算法思想:
每一趟从待排序的数据元素中选出最小(或最大)的一个元素,
顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。
示例:下标 0 1 2 3 4
5 3 7 9 1
i
3 5 7 9 1 5>3交换
第零趟: 3 5 7 9 1 3<7不动
3 5 7 9 1 3<9不动
1 5 7 9 3 3>1交换-->此时arr[0]为1,并且最小
共比较4(arr.length-0-1)次
5 7 9 3 5<7不动
第一趟: 5 7 9 3 5<9不动
3 7 9 5 3<5交换-->此时arr[1]为3,次小
共比较3(arr.length-1-1)次
第二趟: 7 9 5 7<9不动
5 9 7 5<7交换-->此时arr[2]为5.
共比较2(arr.length-2-1)次
第三趟: 7 9 9>7交换-->此时arr[3]为7.
共比较1(arr.length-3-1)次
共走了4(arr.length-1)趟,最后剩余一个9,为最大,arr[4]为9
*/
//选择排序
public static void selectSort(int[] b)
{
for(int i=0;i<b.length-1;++i)//控制趟数
for(int j=i+1;j<b.length;++j)//共比较(arr.length-1)-(i+1)+1
if(b[i]>b[j]) //即arr.length-i-1
swap(b,i,j);
}
//选择排序第二种写法:
public static void selectSort_2(int[] c)
{
int k=0;
for(int i=0;i<c.length-1;++i)
{
k=i;
for(int j=i+1;j<c.length;++j)
if(c[k]>c[j])
k=j;
if(k!=i)
swap(c,k,i);
}
}
/*
这种写法和上面最大区别是:
k中每次存放较小元素的下标,直到一趟走完
此时k中存放这一趟最小元素下标
这时在和第i个位置的元素交换
*/
//打印数组
public static void showArray(int[] arr)
{
System.out.print("[");
for(int i=0;i<arr.length;++i)
if(i!=arr.length-1)
System.out.print(arr[i]+",");
else
System.out.println(arr[i]+"]");
}
//Test
public static void main(String[] args)
{
int[] arr={7,3,9,11,1,6,5};
int[] arr_2={6,2,3,1,11};
int[] arr_3={9,8,10,2,11,3};
bubbleSort(arr);
System.out.println("bubbleSort: ");
showArray(arr);
selectSort(arr_2);
System.out.println("slectSort: ");
showArray(arr_2);
selectSort(arr_3);
System.out.println("selectSort_2: ");
showArray(arr_3);
//Arrays.sort(arr_2);实际开发中使用
//showArray(arr_2);
}
}
运行结果:
最大值与最小值:
class MaxMin
{
//相当于冒泡/选择排序的一趟
//可以一次遍历同时找出最大值和最小值
public static void main(String[] args)
{
int max,min;
int[] arr={3,2,1,6,9,5};
max=min=arr[0];//max和min的初始值可以为数组中任何两个值,但下面的循环必须从下标0(i=0)开始
for(int i=1;i<arr.length;++i)
if(arr[i]>max)
max=arr[i];
else
if(arr[i]<min)
min=arr[i];
System.out.println("max="+max+",min="+min);
}
}
运行结果:
折半(二分查找):
举例:
class BiSearch { /*
折半(二分)查找:
算法思想:
要求序列必须有序(升序/降序),因为只有这样才能确定
数据的范围,通过不断的折半来缩小查找数据的范围
设查找数据为key
①通过两个变量min和max来指定数据的范围,要求min<=max
(min=max表示只有一个数据时)
②首先与mid=(min+max)/2比较,如果key=mid查找成功,直接返回
mid,如果key<mid,则min=mid-1,缩短查找范围,此时在让key与
mid=(max+min)/2比较,若key>mid,则max=mid+1,之后再与新的mid
比较,依次类推找到则返回,未找到则min>max.
*/
public static int biSearch(int[] arr,int key)
{
int max=arr.length-1,min=0,mid;
while(max>=min)
{
mid=(max+min)/2;
if(key==arr[mid])
return mid;//返回key在数组中的下标
else
if(key<arr[mid])
max=mid-1;
else
min=mid+1;
}
return -1;//表示未找到
}
public static void main(String[] args)
{
int[] arr={3,5,7,9,10,11};
System.out.println("keyIndex="+biSearch(arr,11));
}
}
折半查找过程(以上面为例)
查找成功:
示例2:
已知有序数组,要求在有序数组中插入一个元素,使之仍然有序.
class BiSearch_2{ //已知有序数组,要求在有序数组中插入一个元素,使之仍然有序
/*
思想:
①首先我们要找到该元素插入的位置,才能进行操作
②由于数组有序,通过折半查找来确定其位置
③把该位置(包括这个位置)的元素(从后向前)逐个后移,
为新插入的元素
空出一个位置
*/
public static int biSearch(int[] arr,int key)
{
int max=arr.length-2,min=0,mid;
while(max>=min)
{
mid=(max+min)/2;
if(key==arr[mid])
return mid;//返回key在数组中的下标
else
if(key<arr[mid])
max=mid-1;
else
min=mid+1;
}
return min;//由图可知min就是该元素的插入位置
}
//数组中的元素后移,即赋值过程
public static void backWard(int[] arr,int site,int key)//site为插入位置
{
int i;
for(i=arr.length-2;i>=site;--i)//例子:site=3,arr.length=7
arr[i+1]=arr[i];
arr[i+1]=key;//此时i=2,因此插入位置为i+1
}
public static void main(String[] args)
{
int[] arr={3,5,7,9,10,11,0};//已知数组的元素为6个,最后一个0
//为了让数组多开辟一个空间,存放插入元素
int index;
index=biSearch(arr,8);
System.out.println("keyIndex="+index);
backWard(arr,index,8);
//打印
for(int i=0;i<arr.length;++i)
System.out.print(arr[i]+" ");
}
}运行结果:
查找过程:
注意:折半查找优点是比较次数少,查找速度快,平均性能好;
其缺点是要求待查表为有序表,且插入删除困难。因此,折半查找方法适用于不经常变动而查找频繁的有序列表。
进制转换:
①十进制转二进制(除二取余法,仅适用于正数)
class ArrayTest_2{ //十进制转二进制
/*
算法思想:
①利用乘2取余的方法
②考虑到是逆序输出可以用顺序栈(后进先出)方式输出
*/
public static void toBi(int number)
{
int[] stack=new int[32];
int top=-1;//栈顶指针(类似指针功能)
while(number!=0)
{
stack[++top]=number%2;
number/=2;
}
while(top!=-1)//出栈
System.out.print(stack[top--]);
}
//法二,利用java中提供的方法
public static void toBi_2(int number)
{
StringBuffer sb=new StringBuffer();//定义了一个存数据的容器
while(number!=0)
{
sb.append(number%2);//向容器中添加
number/=2;
}
System.out.print(sb.reverse());//通过StringBuffer中的reverse功能
//逆序输出
}
public static void main(String[] args)
{
toBi(20);
System.out.println();
toBi_2(20);
}
/*
该方法只能计算正数
*/
}
②十进制转十六进制(利用移位和按位与)
class ToHex{ //十进制-->十六进制
/*
算法思想:
①首先该数与低四位为1,其余位为0(15)数相与(&)可得到该数低四位
②使该数右移(>>>)四位,在与15相与又得到四位,依此类推
知道原数变为0停止
注意:这里用>>>而不用>>原因是考虑到负数会一直补1,
当然可以通过-1(补码全为1)来决定结束,但无法输出
符号位的十六进制,而>>>可以把负数的符号位也转成
十六进制
*/
public static void toHex(int number)
{
StringBuffer sb=new StringBuffer();//定义了一个存数据的容器
int Hex;
while(number!=0)
//for(int i=0;i<8;++i)//强制把32位都转换:200->0000C8
{ //而while则为:C8
Hex=number&15;
if(Hex>=10)
sb.append((char)(Hex-10+'A'));
else
sb.append(Hex);
number >>>= 4;
}
System.out.print(sb.reverse());
}
public static void main(String[] args)
{
toHex(-200);
System.out.println("\n"+Integer.toHexString(-200));
}
}
③十进制转R进制(查表法)
class Convert{
//查表法将十进制转换成R(二,八,十六)进制
/*
数组下标: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0 1 2 3 4 5 6 7 8 9 A B C D E F
包括二进制,八进制,十六进制值恰好对应了数组的下标.
*/
//二进制
public static void toOct(int number)
{
trans(number,1,1);
}
//八进制
public static void toBi(int number)
{
trans(number,7,3);
}
//十六进制
public static void toHex(int number)
{
trans(number,15,4);
}
public static void trans(int number,int and,int offset)//分别接收原数,需要与的值,
//需要移位的值
{
if(number==0)//为0下面不在执行
{
System.out.println(0);
return;
}
char[] table={'0','1','2','3',
'4','5','6','7',
'8','9','A','B',
'C','D','E','F'};
char[] stack=new char[32];
int top=-1;
while(number!=0)
{
stack[++top]=table[number & and];
number >>>= offset;
}
while(top!=-1)
System.out.print(stack[top--]);
System.out.println();
}
public static void main(String[] args)
{
toBi(-80);
toHex(-80);
toOct(-80);
}
}
二维数组:
在Java中并没有真正的多维数组,只有数组的数组,虽然在应用上很像C语言中的多维数组,但还是有区别的.在C语言中定义一个二维数组,必须是一个x*y的二维矩阵块.而Java中的多维数组并不一定是规则的矩阵形式定义一个多维数组:int[][] xx;//int xx[][],int[] xx[];它表示 一个数组引用变量xx,第一个元素变量为xx[0],第n个元素变量为xx[n-1].xx中的每个元素变量(xx[0]~xx[n-1])正好又是一个整数类型的数组引用变量.
int[ ][ ] xx;
xx=new int[3][ ];
解析:这两句代码表示数组xx有三个元素,每个元素都是int[ ]类型的一维数组.相当于定义了三个数组
int[ ] xx[0],int[ ] xx[1],int[ ]
由于xx[0],xx[1],xx[2]都是数组引用变量,必须对它们赋值,指向真正的数组对象.才可以引用这些数组中的
元素.
xx[0]=new int[3];
xx[1]=new int[2];
另:
二维数组的静态初始化:
int[ ][ ] xx={{3,2,7},{1,5},{6}};
示例1:
class ArrayDemo1 { public static void main(String[] args)
{
int[] arr = new int[2];//建议这种方式,定义一个int型数组的引用变量 arr
int arr[] = new int[2];
//静态初始化
int[] arr = new int[]{3,1};//new int[]中不能指定长度,编译不能通过
//可能出现元素个数和指定长度不同
int[] arr = {3,1};//静态初始化简化形式
System.out.println(arr[3]);//编译可以通过,编译时期没有创建数组也就是说在运行时期才在堆内存中为数组开辟空间.
//在运行时期发生数组角标越界异常
arr=null;
System.out.println(arr.length);//编译依然可以通过,原因同上.
//运行时期发生错误,arr不再引用数组,无法操作数组中的元素
//发出空指针异常
//二维数组静态初始化
int[][]a=new int[][]{{4,2},{5,6,7}};//①
//int[][]a={{4,2},{5,6,7}};//等价于①
}
}
示例2:
class DoubleArray{ public static void main(String[] args)
{
int[][] xx=new int[3][2];//二维数组中的三个元素,每个元素指向一个长度为2的一维数组System.out.println("x\t"+xx);//[[代表二维数组,I->Integer(整形),数组中的元素类型 //@后面由哈希函数算出哈希址 System.out.println("x[0]\t"+xx[0]);
int[][] y=new int[4][];
System.out.println("y\t"+y);
System.out.println("y[0]\t"+y[0]);
int[][] x=new int[3][];//每个引用数组的长度可以不一样
x[0]=new int[3]; //在内存中的情况如下图:
x[1]=new int[1];
x[2]=new int[2];
}
}
二维数组在内存中: