您的位置:首页 > 编程语言 > Java开发

JAVA基础之数组

2016-05-22 13:19 363 查看
数组的概念:

同一种数据类型的集合就叫数组。

它的第一种格式:

元素类型 [] 数组名 =new 元素类型[元素个数或数组长度];

new是数组里面的关键字,在这里可以翻译成新建的意思。

比如: */

int [] arr = new int [8];

/*这个数组的意思就是说,新建了一个int类型,名字叫arr的数组,里面可以存放8个数据。

在数组中,默认是给里面存储的数据进行编号的,从0开始。

中括号[]里面的数字叫角标,专业名词叫索引。

假如我们要输出里面的数值,打印在控制台上,可以这样。*/

System.out.println(arr[6]);//意思就是我们要打印新建数组里面5号角标的数据。

/*因为暂时还没有给新建的数组赋值,所以里面所有角标的默认数值是0

这是java底层的默认设置

而且因为编号是从0开始的,我们新建数组里面可以存放8个数据,所以最大的编号是7。

假如我们要给新建的数组里的某个角标赋值,应该是这样。*/

arr[7]=45;

System.out.println(arr[7]);

/*JAVA虚拟机在内存中的划分

1.寄存器

2.本地方法区

3.方法区

4.栈内存

存储的都是局部变量(函数内的变量都叫局部变量,包括循环结构中的变量)

而且变量所属的作用域一旦结束,该变量自动释放。

5.堆内存

存储的是数组和对象(其实数组就是对象)

意思就是说凡是new都建立在堆中。

每一个变量都有默认初始化值,根据类型的不同而不同。

int 是0,小数是0.0或0.0f,boolean是false,char是'\u0000'

每一个实体存储都有对应的首地址值。

垃圾不定时自动回收机制。

数组的第二种定义格式:

元素类型 [] 数组名 =new 元素类型[]{元素,元素,元素......}

比如: */

int [] add=new int []{23,2,45,56,54};

System.out.println(add[0]);

/*上面这种格式就是创建数组的同时,给每个角标同时赋值,数据的先后顺序会被默认从0开始编号。

这种创建格式中括号[]里面就不能填角标了,是语法错误,编译会失败。

这第二种格式还可将右边的new关键词和数据类型以及中括号[]直接省略,只将大括号里的内容保留

就是这样。*/

int [] aee={23,2,45,56,54};

System.out.println(aee[3]);

/*这样也是可行的,不算语法错误。

如果要将数组里面所有的值都打印出来,我们可以用循环的方法。

就是这样: */

for (int a=0;a<aee.length ;a++ )//定义数组角标变量,从0开始,每次自增,则打印一次。

{

System.out.println("aee ["+a+"] ="+aee[a]);//aee.length是数组角标长度的意思。

//长度减一就是编号最大值。

}

System.out.println("-----------------");

/*这种将数组内的所有数据输出查看的方式叫做 遍历.

最值:获取数组中的最大值或最小值。

练习:

获取aee数组中的最大的值。

既然获取最大值,就得进行比较,数组中的数据很多,就要进行多次比较。

所以我们可以用循环来进行操作。*/

int a=aee[0];//我们从数组的第一个编号开始,依次进行比较。

//这里a的初始化值千万别写成0,虽然这道题写0也可以,但是意义不同。

//赋值0就相当于重新找的第三方数据进行比较,而不是在数组中进行比较。

//如果非要赋值为0.那这个0就不是具体的数据了

//而是数组的角标

for (int b=1;b<aee.length ;b++ )//这里是遍历aee数组中的数值。角标设定为变量,依次自增。

{

if (aee[b]>a)//如果某个角标大于0角标。

{

a=aee[b];//就将这个大于的值赋给a,不大于则不赋值。

}

}

System.out.println("a="+a);//所以最后剩下的角标必定就是数组中最大的数。

//我们还可以用函数的方法来找出这个值。

System.out.println("-----------------");

int c=getMax(aee);//在调用函数的时候要注意,括号后面只需要写数组名就可以了。

System.out.println("c="+c);

System.out.println("-----------------");

System.out.print("排列前的数组顺序是aee[");

for (int b=0;b<aee.length ;b++ )

{

System.out.print(aee[b]+",");

}

System.out.print("]");

System.out.println();

/* //上面是排序前的数组遍历输出

//下面是排序后的数组遍历输出。

//这两者遍历是一回事,我们同样可以给两个遍历编写一个函数功能,以提高代码复用性。

System.out.print("排列后的数组顺序是aee[");

tangYi(aee);//这里是调用函数内已经排列好的数组。因为下面写了遍历函数,所以只能注释掉。

for (int ew=0;ew<aee.length ;ew++ )

{

System.out.print(aee[ew]+",");

//这里是遍历数组里的值。

}

System.out.println("]");*/

System.out.println("-----------------");

//下面就是调用遍历功能函数的语句。 选择排序

bianLi(aee);

// tangYi(aee);//这句是调用排序功能,下面开始后排序就完成了。

bianLi(aee);

System.out.println("-----------------");

//冒泡排序。

bianLi(aee);

// tangShan(aee);//这句是调用排序功能,下面开始后排序就完成了。

bianLi(aee);

System.out.println("-----------------");

int jiaoBiao=getOut(aee,54);//这是调用查找函数的语句。

System.out.println("jiaoBiao="+jiaoBiao);//输出对应的角标值。

System.out.println("-----------------");

int[] black={11,14,24,34,45,47,56,67,89,90};

int zheban=language(black,50);

System.out.println("这个值的角标是:"+zheban);

}

public static void bianLi(int [] aee)

{//这个函数就是遍历功能的函数。没有返回值,故写作void

System.out.print("[");//第一个中括号只能先输出,因为在循环里的话会输出很多次。

for (int b=0;b<aee.length ;b++ )

{//数组角标设为变量,依次遍历。

if (b!=aee.length-1)

{//如果角标不是最大角标值,就输出当前角标对应的数值,并在后面输出逗号。

System.out.print(aee[b]+",");

}

else//如果角标是最大角标值,证明遍历结束,输出当前角标对应的数值,并在后面输出第二个中括号。

{

System.out.println(aee[b]+"]");

}

}

}

public static int getMax(int []aee)

{

int c=aee[0];

for (int b=1;b<aee.length ;b++ )

{

if (aee[b]>c)

{

c=aee[b];

}

}

return c;

}

/*数组的选择排序

将数组中的数值按照从小到大的顺序依次排列。

选择排序的思想是将某一个角标依次和所有角标进行比较,确定最值后赋值给相应的角标。

int [] aee={23,2,45,56,54};

比如上面的aee数组,里面的数值顺序是杂乱的,我们要通过代码将里面的数值重新排序。

要排序的话,就得知道数值之间的大小,就得需要进行比较,

数组里面所有的数值都得比较就得需要遍历数组里的数据。

而且排序本身还涉及到数值互换的问题。

从0角标开始,依次比较,将最小的值赋给0角标。

从1角标开始,依次比较,将第二小的值赋给1角标。

在每个角标进行比较的时候,上一个角标是不用在比较的,因为已经比较过,已经确定了位置。

既然如此,代码就应该写成这样*/

public static void tangYi(int [] aee)

{//我们将这种排序方法定义在函数里面。我们只是将数组里数值的顺序打乱而已,所以不需要返回数组,

//所以用void

for (int a=0;a<aee.length-1 ;a++ )//外循环是要比较的角标,最后一个角标无需比较,因为没有

{//角标可以跟它比较,而角标自己比较又是毫无意义的。

for (int b=a+1;b<aee.length ;b++ )//内循环是被比较的角标,同一个角标无需比较,所以

{//我们将外角标的数值加上1就是它要依次比较的角标。

if (aee[a]>aee[b])//判定,如果a角标大于要比较的b角标,则将他们位置互换,

{//达到从小到大依次排列的目的。

int c=aee[a];

aee[a]=aee[b];

aee[b]=c;

/*上面三行语句就是前面学过的数值互换的方法,用定义第三方变量的方法来实现。

先将大的值赋值给临时第三方变量,再将小的值赋给原先大的值进行数值覆盖

最后将临时变量里的值赋给原先较小的值,数值互换就完成了。*/

}

}

}

}

/*冒泡排序,这是另一种排序思想。

也是将数组中的数值按从小到大的顺序排列。

和选择排序的区别就是,它是相邻两个角标进行比较,

比如0角标和1角标比较,1角标和2角标比较,2角标和3角标比较,以此类推...、

他的代码写法是这样:*/

public static void tangShan(int [] aee)

{

for (int a=0;a<aee.length-1 ;a++ )

{//外循环和选择排序是一样的,最后一个角标无需比较,因为没有跟他要进行比较的角标。

for (int b=0;b<aee.length-1-a ;b++ )

{//因为冒泡排序是相邻比较,也就是aee[b]与aee[b+1]相比较

//当b的角标值为数组中最大角标aee.length-1时,aee[b+1]就会越界,而且也没有比较的必要。

//因为那时就只剩下aee.length-1这一个角标了,所以这里要减一。

//我们只需要aee.length-2和aee.length-1(也就是aee[b+1])比较就足够了。

//减a的原因是每次循环比较后,就有一个最值确定,就没有比较的必要。

//随着循环比较次数的增加,最值的确定也在增加,这个增加的幅度刚好和外循环的a是一样的

//所以我们要减a。

if (aee[b]>aee[b+1])

{//冒泡排序是相邻的,所以我们用aee[b]和aee[b+1]相比较。

int c=aee[b];

aee[b]=aee[b+1];

aee[b+1]=c;

//执行语句是用第三方变量的方式进行位置互换,这个好理解。

}

}

}

}

/*以上两个排序我们发现,if语句里面的执行语句都是在进行互换,我们也可以用互换做一个函数功能。*/

public static void swap(int [] aee,int a,int b)

{//因为我们是在数组中替换两个数值的位置,所以我们得把数组的变量提取出来,这里就是三个变量。

int c=aee[a];

aee[a]=aee[b];

aee[b]=c;

}

//下面是选择排序的执行语句调用

/* public static void tangYi(int [] aee)

{

for (int a=0;a<aee.length-1 ;a++ )

{

for (int b=a+1;b<aee.length ;b++ )

{

if (aee[a]>aee[b])

{

swap(aee,a,b);

}

}

}

}

//下面是冒泡排序。

public static void tangShan(int [] aee)

{

for (int a=0;a<aee.length-1 ;a++ )

{

for (int b=0;b<aee.length-1-a ;b++ )

{

if (aee[b]>aee[b+1])

{

swap(aee,b,b+1);

}

}

}

}*/

/*选择排序和冒泡排序还有互换函数,还有调用函数的正确写法,都要重点掌握。

数组的常见功能,查找。

查找某个数值在数组里的角标位置。*/

public static int getOut(int [] aee,int key)

{//key就是具体的数值。

for (int a=0;a<aee.length ;a++ )

{//遍历数组。

if (aee[a]==key)

{//如果某个角标里的数值与我们需要找的数值相等,那么就返回这个数值的角标值。

return a;

}

}

return -1;//如果没找到,就返回-1,因为角标是从0开始排序的,返回-1就能代表没有找到这个数值。

}

/*以上的角标查找方法是基于无序排列的数组的,而对于有些有序排列的数组,我们还有另外一种

查找方法,就是折半查找,也叫做二分查找。

有序排列的意思就是从小到大,或从大到小的排列。

我们要寻找其中某一个数值的角标,想要快速的找到其角标的话,最好的方法就是将其角标长度一分为二,

以缩小最佳范围。这种方法我们需要知道角标头,角标尾和中间角标。

角标头我们用min来表示 中间角标用mid来表示 角标尾我们用max来表示。

比如下面这个数组:

11 14 24 34 45 47 56 67 89 90

0 1 2 3 4 5 6 7 8 9

min mid max

这就是这个数组中各项数据的指标和具体位置。我们知道,中间角标的位置其实就是角标头和角标尾相加再除以2

所得到的结果,在java中,整数做运算之后还是整数,如果有小数的部分就直接舍弃掉.

上面数组角标头和角标尾相加除以2之后的结果是4,所以4是中间角标。

比如我们想要知道56这个数值在数组中的角标位置,首先就是确定中间角标的位置缩小范围,

如果比中间角标里的数值小我们就将目标放到左边去进一步缩小范围,反之就是右边。

很明显,56这个值在4角标的后面,所以我们还得看向右边。

然后重复第一步,把右边这一段看成一个整体,再一分为二,取其中间角标再来进行判断。

所以我们首先要确定好下一段,这个下一段肯定就是中间角标值的下一个角标值为角标头,角标尾不变。

这里要注意,是不可能用中间角标值作为下一段的角标头的,因为中间角标是用来说缩短范围的,数值不是比它里面的数值大就是小,如果是等于的话我们就不用再进行判断了。

中间角标值的下一个角标值作为角标头,然后又是这个角标加上角标尾,再除以2确定中间角标值用于判断缩小范围如此循环,因此,我们的代码就可以这样写。*/

public static int language(int[]black,int key)

{//定义折半查找功能函数。

int min,mid,max;//定义角标头,尾,中间三个角标值的变量。

min=0;//头为min

max=black.length-1;//尾为max,这里先定义max再定义mid是因为java是从上往下执行的,而max的值我们还没

//确定,如果先定义mid的话,会找不到max,会报错。

mid=(min+max)/2;//中间为mid

while (black[mid]!=key)//进入多次循环

{

if (key>black[mid])//如果查找的值大于中间角标,则向右。

{

min=mid+1;//角标头就为中间值加1.

}

else if (key<black[mid])//如果小于,则向左。

{

max=mid-1;//角标尾就为中间值减1。

}

if (max<min)//如果角标尾比角标头大,说明没有这个值。

{

return min;//就返回-1,循环就此结束。

}

mid=(min+max)/2;//首轮查找完后,min或max都改变了位置,所以我们要重新计算mid的值。

}

return mid;//如果循环结束不是因为返回-1,说明就查找到了这个数,返回我们找到的这个数的角标

//也就是中间值,就可以了。

}

/*折半查找练习

这是一道面试题。

在一个有序的数组中插入一个数值,不改变数组有序排列的基础下,求这个数值应该放在哪个角标位置。

这是一道思想上的问题,我们要想到,只要是有序查找,最快的方法都是折半查找。我们要寻找这个数的角标位置

在查找的时候首先可以肯定是找不到的,程序会返回-1,这个时候我们就知道,在返回-1这个结果时,

相当于max跑到了左边,而min却要跑到右边,,刚好要动时,程序就返回了,停止循环了,

所以我们在这个时候,只要返回的是min就能确定他的角标值。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: