黑马程序员Java基础第三章-----数组,算法(冒泡,选择,折半查找)

来源:互联网 发布:淘宝的代购可信吗 编辑:程序博客网 时间:2024/06/05 18:17

------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------

.数组

数组的定义:数组是存放确定数目的同类元素的容器。

数组的特点:1.数组在初始化时,就要明确他能容纳哪一类元素,容纳多少个元素。

                     2.数组只要被定义了,数组的长度就不能发生改变了

                     3.数组可以通过下标来访问和修改元素,但是数组不能增加和删除元素(长度不可以变化)

数组的存储位置:数组属于引用类型,在堆内存中开辟空间,存储数组元素。

数组的分类:一维数组  二维数组   多维数组

1.一维数组

有三种初始化方式:

       1).方式1:int[]  arr = new int[]{3 ,5,8};

       2) 方式2:int[] arr = {3,5,8};

       2) 方式3:int[] arr = new int[3];

       第一种方式可以不在中括号中指定数组的长度,这时候java会根据后面大括号中的元素的个数来确定数组的长度。

       第二种方式是先在堆内存中创建一个数组,并将其中的值指定为确定值,然后将它赋给引用变量

       第三种方式是直接在堆内存中new一个可以装3个整数的数组空间,但其中的元素没有指定,但堆内存会对他们进行默认初始化,初始化值是0。

记住:数组变量arr是在栈内存,而开辟的数组的内存空间在堆内存中。然后将堆内存中的数组空间的起始地址赋值给了栈内存中的arr变量。

           数组的内存空间是一片连续的内存空间,通过数组的首地址和数组元素的类型可以计算出数组中任意给定位置的元素地址,只不过这些被JVM底层封装起来了,我们只需要拿着下标就可以访问对应的位置的元素。

数组的操作和属性:

我们使用一个例子来说明,例:int[] arr = new int[5];

1).数组的第一个元素的索引:数组的下标从0开始

2).数组的容量:数组的容量是5,也可以通过arr.length来获得,得到的值也是5

3).数组的元素的下标:0   1   2    3    4       注意:没有5下标,访问5下标会报数组越界异常

4).数组元素的访问:arr[0]的值是第一个索引位置的元素    

                                   arr[4]是最后一个索引位置的元素

                                   没有arr[5]这个元素,会报数组越界异常

5).数组元素的赋值:arr[3] = 10 ;将int型的值10赋值给数组中的下标为3的元素,也就是第四个元素。也可以使用具有确定值的表达式,数组中的元素给元素赋值。

6).变量arr代表的是数组的地址(首地址),所以我们输出数组的每个元素不能直接使用System.out.println(arr),这样输出的是数组的地址的哈希值;而是要使用循环来遍历数组,并在循环中使用System.out.println(arr[x]);来输出每个元素。

7)数组的生命周期:

①基本类型变量:int a = 10 ; void sum(int b){.......}   sum(a);  在调用sum函数后,访问变量a,a的值还是10 ;

②数组类型变量:int[] arr = new int[3] ;  void sum(int[] b){.......}  sum(arr);在调用sum函数后,访问数组arr,此时arr的中的元素值已经改变了。

我们稍作分析,既可以发现:

对于基本类型变量,在调用函数时int b = a ;将a的值赋给变量b,在函数中操作的都是变量b,而变量b在函数结束后,就是释放了,而a的值自始至终没有发生改变。

对于数组类型变量,在调用函数时int[] b = arr ;将数组arr的地址赋值给了变量b,b就指向了arr。在函数中操作变量b时,其实就是在操作b指向的堆内存中的数组中的元素。在函数结束后,我们再来访问arr中的元素时,实际上元素已经发生了改变。

数组中的两个元素交换顺序的方法,有三种:

1.定义第三方变量:(最简单,也最容易想到,推荐使用)

                                int temp = arr[x] ;

                                arr[x] = arr[y] ;

                                arr[y] = temp ;

2.使用加减法的方式:(技巧型)

                                arr[x] = arr[x] + arr[y] ;

                                arr[y] = arr[x] - arr[y] ;

                                arr[y] = arr[x] - arr[y] ;

3.使用异或的方式:(技巧型)一个数异或另外一个连续两次,得到的还是这个数本身。

                                 arr[x] = arr[x] ^ arr[y];

                                 arr[y] = arr[x] ^ arr[y] ;

                                 arr[x] = arr[x] ^ arr[y] ;

以上3中方式都能使任意两个数的值发生交换,不仅仅局限在数组中的元素,数据交换我们要在后面的排序中要使用到,所以要记住。

2.二维数组

二维数组的定义:数组中的元素还是一个数组,那么这个数组就是一个二维数组。

二维数组的定义:

方式1:int[][] arr = new int[4][5];

     定义了一个二维数组,arr中包含4个一维数组,每个一维数组的长度是5,就是每个一维数组中有5个int类型的数据元素。

方式2:int[][] arr = new int[4][];

     定义了一个二维数组,arr中包含4个以为数组,但是这些一维数组没有初始化,也没有分配内存空间,一维数组的长度也没有明确。

方式3:int[][] arr = {{1,3,6},{2,5},{3,6,0,1}};

     定义了一个数组,并且对数组中的元素进行了初始化。

比较分析上面方式可得:

1.二维数组的第一维的长度一定要指定,第二维可以不指定。可以等到初始化二维数组的元素一维数组时,在指定。

2.二维数组中的元素(一维数组)的长度可以不相同,不要求每个一维数组的长度相同。但类型要相同。

3.变量arr代表的其实是二维数组的地址,而arr[0]代表的是第一个一位数据的地址,arr[1]代表的是第二个以为数组的地址。

其实底层,二维数组中存储的是对应的一维数组的地址,就是说arr[1]指向第二个一维数组。

对于第一种方式初始化,二维数组中都存储了一维数组的地址,分别指向了对应的一维数组,一维数组已经初始化了,可以直接赋值访问等操作。

对于第二种方式初始化,因为只初始化了第一维,只是说明了这个二维数组中可以存放几个一维数组,但这几个一维数组并没有初始化,于是第一维中就没有一维数组的地址可以存。堆内存中的数据JVM对它们先进行默认初始化接着进行显示初始化,但是此时无法显示初始化(没有一维数组地址),所以堆内存的第一维中的元素的值就是默认初始化的值。JAVA基本类型的初始化根据类型而定,引用类型的默认初始化值都是null,所以此时arr[0],arr[1],arr[2],arr[3]的值都是null;

我们对二种方式的数组进行初始化的方式:

int[][] arr = new int[4][];

arr[0] = new int[3];

arr[1] = new int[4];

arr[2] = new int[2];

arr[3] = new int[5] ;

用这种方式分别对第一维中的每一个元素进行初始化。把一维数组对象赋给第一维的中的元素,其实就是把地址赋给它,让它指向对应的一维数组,所以我们打印二维数组的arr[x],其实打印的就是一维数组的地址。

二.算法(冒泡,选择,折半查找)

1.冒泡排序:将相邻的元素进行比较,比较完一轮就可以确定一个最大值(最小值)在最大索引位置,接着继续下一轮循环直到所有的元素有序。

2.选择排序:将第一个元素和其他的所有的元素比较,比较完后可以度确定一个最大值(最小值)在最小索引位置,接着用第二个元素去和所有的比较,置之所有的 元素有序。

3.折半查找:只能对有序的集合或者数组进行折半查找,无序的不能折半。取出整个数组中间位置的元素和要查找的元素进行比较,当中间元素小于要找的元素时,在对中间以右的元素去中间元素和要查找的元素对比。如果中间元素大于要查找的元素,就对中间位置以左的元素去中间元素和要查找的元素比较。直到查找到和要查找的元素相等数据,此时返回钙元素的位置。或者起始角标大于终止角标时,也会结束。此时返回要查找元素在有序集合中插入并保证集合依然有序的位置的负数减1。

class Array01 {public static void main(String[] args) {//------------冒泡排序------------------int[] arr1 = {6,3,7,9,1,0,5};System.out.println("排序前的原始数组:");show(arr1);bubbleSort(arr1);System.out.println("冒泡排序后的数组:");show(arr1);//------------选择排序------------------int[] arr2 = {3,2,6,5,1,9,0};System.out.println("排序前的原始数组:");show(arr2);selectSort(arr2);System.out.println("选择排序后的数组:");show(arr2);//------------二分查找---------------------//二分查找(数组元素必须有序,才可以二分查找)int index = binarySearch(arr2,4);if(index>=0)System.out.println("找到元素,它的位置位置是:"+index);elseSystem.out.println("没有找到元素,元素的插入位置是:"+(-(index+1)));}//冒泡排序public static void bubbleSort(int[] arr){for(int x=0;x<arr.length;x++)//循环完,所有的元素就会有序{for(int y=0;y<arr.length-x-1;y++)//循环完一次,就会将最大值排到最末位置上{if(arr[y]>arr[y+1]){swap(arr,y,y+1);//交换元素}}}}//选择排序public static void selectSort(int[] arr){for(int x=0;x<arr.length-1;x++)//控制是哪个元素和剩余的比自己索引打的所有元素比较{for(int y=x+1;y<arr.length;y++)//比这个元素索引大的元素都要一次和这个元素比较{if(arr[x]>arr[y]){swap(arr,x,y);}}}}//二分查找,若找得到元素则返回元素的位置,若找不到元素则返回元素应该在数组中插入的位置的负数减1public static int binarySearch(int[] arr,int key){int max = arr.length-1 ;int min = 0 ;int mid ;while(min<max){mid = (max + min ) >> 1 ;//取的集合的中间的索引位置值if(arr[mid]>key)//小于中间元素,max要改变max = mid -1 ;else if(arr[mid]<key)//大于中间元素,min要改变min = mid + 1 ;elsereturn mid ;}return -min-1 ;//当不满足循环条件时,min的位置就是要插入的位置}//交换数组中指定的两个元素,采用定义三方变量的方式交换public static void swap(int[] arr,int index1,int index2){int temp = arr[index1] ;arr[index1] = arr[index2] ;arr[index2] = temp ;}public static void show(int[] arr){for(int i=0;i<arr.length;i++){if(i==arr.length-1)System.out.println(arr[i]+"]");else if(i==0)System.out.print("["+arr[i]+",");elseSystem.out.print(arr[i]+",");}}}
运行结果:
<img src="http://img.blog.csdn.net/20150403210833027?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFrZXJzOF8yNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />







0 0