黑马程序员_四 【数组操作】【数组的简单应用】

来源:互联网 发布:萧山网络问政 编辑:程序博客网 时间:2024/05/16 05:57


--------------------- android培训java培训、java学习型技术博客、期待与您交流! -------------------



 1 数组开篇

数组是java中学习的第一个引用数据类型。这也是java数组的一个特色。在创建了数组后,将在堆内存中开辟内存空间,通过引用来操作数组实体。下面是个小例子:

有方法 ,对数据进行交换

int x=2,y=3;//传递到a和b

swap(x,y);

swap(int a,int b)

{

//a=x;

//b=y;//隐式赋值

int temp=a;

a=b;

b=temp;

}

这样交换后的结果是,形参做了交换,而实参还是原来的值,如上隐式赋值。基本数据类型变量在栈内存中,做完交换动后就出栈了,原来的值不变。

有方法,对数组进行排序

int[] arr={1,2,3};

public void selectSort(int[] arr)

{

//排序;

}

排序后,arr数组发生变化,为什么呢?因为数组是引用型的,存放在堆内存当中,arr传递之后,改变的就是原数组,形参也是引用型的,传递的是地址,而不是实际的数组实体,形参会指向实体做操作,直接改变原数组。

如下内存图进行分析:

    栈内存   堆内存


 2  数组操作

数组是一个存储数据的容器,存在对该容器的常用操作,对数组的常用操作:赋值,取最值,查找,删除,排序等。

首先创建一个数组:创建数组常见有四种种操作

|----数据类型 变量名 [] =new 数据类型[数组长度];

|----数据类型 变量名 [] ={数据1,数据2,数据3......};

|----数据类型 [] 变量名=new 数据类型[数组长度];

|----数据类型 [] 变量名={数据1,数据2,数据3......};

其中后两种较为常用,如果在已知数据的情况下可以用最后一种出阿哥就爱你数组。

罕见创建数组方式:

|----数据类型 [] 变量名1 ,变量名2[] =new 数据类型 [数组长度] [ ];

这样就创建了两个数组,变量名1数组是一维数组引用,变量名2是个二维数组引用。

特点:如果[]在变量前面,对后面的变量都有作用,若变量在[]前面,[]只对和自己挨着的变量有效(这里的“变量名2),对“变量名1”是无效的。

注意:这时的“变量名1”数组引用,在进行初始化时不能使用  变量名1={数据1,数据2......};这种方式,应使用  变量名1=new int[数组长度];

数组的赋值:数组的赋值很简单,一个数组引用可以接收同类型数组的实体赋值。

如:int []  a;

Int []  b={1,2,3,4};

//b数组赋给a数组引用

a=b;

这样引用a就指向了b数组的实体。操作a的效果和操作b是一样的。如下内存图:

栈内存 堆内存


取最值

取最值也是简单地操作:

通过判断比较,得出最值。下面是一个小示例:

public class Test{public static void main(String[] args){//已知一个整型数组int[] arr={23,24,13,45,61,98,87,36};//取出最大值int index=getMax(arr);System.out.println("最大值角标是:"+index+";最大值是:"+arr[index]);}public static int getMax(int[] arr){//定义最大值角标int max=0;for(int i=0;i<arr.length;i++){if(arr[i]>arr[max])max=i;}return max;}}


排序

排序是数组中较为重要的操作。数组的常见排序方法有:冒泡排序,选择排序,插入排序,堆排序,基数排序,桶排序,快速排序等。这里学生用,选择排序、冒泡排序和快速排序为例,简单阐述数组的排序操作。

选择排序

分析:选择排序是用最最前面的数与后面的数依次进行比较,满足条件则换位,再用此位置继续比较,比较一轮后,首位置上的数是一个最值;再进行第二轮比较后,第二位置上是第二最值,以此类推,完成排序。

分析图:



上图只画出了两轮的比较过程,以此类推,可以得到一个从小到大排序的数组。

下面是选择排序的程序代码示例:

/*

选择排序示例:

两层循环,外层控制循环的轮数;内层循环控制每一轮比较的次数。

逐一完成比较,每一轮比较结束,将把每一轮中最小的按照次序靠前排列。

例如:

下面的第一个24,24和后面的数值进行比较,当比较到22时,比24小,进行交换,交换后,

arr[0]=22; arr[5]=24;接下来,内层循环再循环时,还是arr[0]和后面的arr[6]进行比较,

只不过这时的arr[0]=22;在比较的话,就去寻找是否有比22还小的,没有,则退出内层循环,

再进行下一轮内层循环。

*/

class Test{public static void main(String[] args) {//自定义一个int型数组int[] arr={24,35,42,51,33,22,34,31};//调用选择排序方法sortAndPrintArray(arr);}public static void sortAndPrintArray(int[] arr){/*外层循环为比较的轮数,最后一轮应该是倒数第二个元素和最后一个元素比较,最后一个元素没有必要自己再进行比较,所以一共比较length-1轮*/for (int i=0;i<arr.length-1;i++ ){//内层循环是每一轮比较的次数,逐轮递减;for (int j=i+1;j<arr.length ;j++ ){if(arr[i]>arr[j])//若满足,则进行交换{//进行交换arr[i]=arr[i]^arr[j];arr[j]=arr[i]^arr[j];arr[i]=arr[i]^arr[j];}}}//简单输出排序后的数组for (int i=0;i<arr.length ;i++ ){System.out.println("arr["+i+"]"+"="+arr[i]);}}}


冒泡排序

形象的说法,通过第一轮的比较后,可得出最大值,把最大值放在最后。

相邻两个数进行比较,大者靠后排,再次比较,故能得出最大值,并在最后面。

分析图:



上图也只画出了两轮的比较过程。和选择排序比较,知识换了一下比较位置,操作还是类似的。下面是冒泡排序的程序示例:

/*冒泡排序:外层循环 控制比较的轮数;内层循环 控制每一轮比较的次数。注意的是,内层循环每次都是从0角标开始,故int j=0;改变条件控制每一轮比较的次数:j<arr.length-1-i;随着比较轮数的增加,对应的比较的次数在减少,例如:第一轮比较,32和14比较,进行交换,交换之后 arr[2]=14, arr[3]=32;接下来,arr[3]和arr[4]比较,即32和24比较,再次交换,以此类推,完成 第一轮比较。*/class Test{public static void main(String[] args) {//定义一个int型数组int[] arr={12,23,32,14,24,52,19};bubbleSort(arr);//简单输出排序后的数组for(int i=0;i<arr.length;i++){System.out.println(arr[i]);}}public static void bubbleSort(int[] arr){for (int i=0;i<arr.length-1 ;i++ )//工比较length-1轮{for (int j=0;j<arr.length-1-i ;j++ )//随着轮数,每一轮比较的次数减少{if(arr[j]>arr[j+1])//满足条件则进行交换{swap(arr,j);}}}}public static void swap(int[] arr,int j)//注意:这里只有一个角标参数j{ //相邻数据进行比较 //不能传递j ,j+1arr[j]=arr[j]^arr[j+1];arr[j+1]=arr[j]^arr[j+1];arr[j]=arr[j]^arr[j+1];}}


快速排序

快速排序,排如其名实现步骤如下:

 步骤:

 1 先在待排序的一组数据中随便选一个数出来作为基数:key

 2 然后对这组数进行排序,比key小的放key的左边,比key大的放key的右边,

     当然这个按照需求来(从小到大,还是从大到小)

 3 用递归来分组,在第二步中再将这组数字,分成多个小组来排序

下面是程序示例:

public class Test{static int count = 0;      public static void main(String[] args) {   //定义一个int数组作为已知数组        int arr[] = { 5, 4, 8, 3, 7, 2, 1, 9, 0, 6 };          //调用快速排序方法        quickSort(arr, 0, (arr.length - 1));          //排序后        System.out.print("\n\n排序后的结果是:");                  for (int i = 0; i < arr.length; i++) {              System.out.printf("%d ", arr[i]);          }      }    //定义快速排序方法    public static void quickSort(int arr[], int left, int right) {          int temp = 0;        //输出排序过程,最后得到的是排序结果        System.out.printf("\n这个是第%d次排序的结果:", count);          count++;          for (int i = 0; i < arr.length; i++) {              System.out.printf("%d ", arr[i]);          }                    if (left < right) {  temp = partition(arr, left, right);    //再次调用排序 quickSort(arr, left, temp);  quickSort(arr, temp + 1, right);          }      }      public static int partition(int arr[], int left, int right) {          int i = 0, j = 0;          int key = 0, tmp = 0;            if (null == arr) {              return 0;          }          i = left;          j = right;          key = arr[left];            // 这个while循环可以实现排序的第一步:分组          while (i < j) {   while (arr[j] > key) {                  --j;   }              tmp = arr[i];              arr[i] = arr[j];              arr[j] = tmp;     while (arr[i] < key) {                  i++;   }              tmp = arr[i];              arr[i] = arr[j];              arr[j] = tmp;          }            return i;     }  }


查找

查找是数组中较为重要的操作。通过查找可以知道数组中是否存在某个数据。

最典型的查找法是折半查找法,又叫二分查找法。

普通查找方法:

通过与每个角标位置上的数据进行比较,判断是否与要查找的数相等,相等则返回角标值。

class Demo{public static void main(String[] args) {int[] arr = {12,23,12,2,34,23};int n=getIndex(arr,23);System.out.println(n);}public static int getIndex(int[] arr,int n){for (int i=0;i<arr.length ;i++ ){if(arr[i]==n)return i;}return -1;//返回-1,说明查找的元素不存在}}


这种查找方法相对速度较慢,因为需要和里面的书元素挨个进行比较。

折半查找

折半查找,顾名思义,就是把数组折两半,查找其中一半。自然的查找速度就快了。折半查找有前提,进行查找的数组必须是有序的。

对于数组,从数组的中间位置开始查找。利用指针思想。

定义三个指针:指向数组的0角标  指向数组的最大角标  指向中间位置

即,int min=0; int max=length-1; int mid=(min+max)/2;

当查找的元素大于mid角标位置的元素时,就与查找右边的(数组默认升序),反之左边

再次进行折半操作,重复进行

简单示图:



这般查找,可以实现快速查找元素的目的。

下面是这般查找的程序示例:

/*用折半查找的前提是:数组必须是有序的。arr[mid]就是循环中查找元素的 指针,若arr[mid]==查找元素;那么就找到了,不满足就找不到。重要步骤元素:1 三变量,min、mid、max2 判断条件,arr[mid]!=key 或者 min<=max; //当arr[mid]==key 时正好找到元素,即不用再折半,或者当min<=max,说明已经查找结束了,不能再折半。3 每步都执行,mid=(min+max)/2; 注:在Array类中,java机制有提供的二分法查找方法binarySearch(int[] arr,int key)可以这样用: Array.binarySearch(int[] arr,int key)*/class  Demo{public static void main(String[] args) {int[] arr={1,2,3,4,5,6,7,8};int index=binarySreach_2(arr,5);System.out.println(index);}//for循环形式: 条件 arr[mid]!=key; 和while循环一个道理,//只是把必须执行的折半动作放到了for后面的更新语句位置。public static int binarySearch(int[] arr,int key){int max=arr.length-1;int min=0;int mid=(max+min)/2;//定义三变量for( ; arr[mid]!=key; mid=(min+max)>>1)//可与while循环互换{if(key>arr[mid])min=mid+1;//查找的元素若大于原中间值,则最小值就是原中间值的后一个元素;else if(key<arr[mid])max=mid-1;//查找的元素若小于原中间值,则最大值就是原中间值的前一个元;if(max<min)//若这样,说明没有该元素;return -1;}return mid;}//while循环方式,条件:arr[mid]!=key。若不满足条件说明,//要找的元素就是arr[mid],直接返回return mid;即可。public static int binarySearch_1(int[] arr,int key){int min=0;int max=arr.length-1;int mid=(min+mid)>>1;while(arr[mid]!=key){if (key>mid){min=mid+1;}else if (key<mid){mid=min-1;}elsereturn -1;mid=(min+max)>>1;}return mid;}//条件:min<=max。满足条件,说明还可以进行折半,在此情况下,//若key既不大于arr[mid]也不小于arr[mid],说明就等于arr[mid]了,//直接返回return mid;若直到条件不满足,也没有以上情况,说明,没有该元素。public static int binarySreach_2(int[] arr,int key){int min=0;int max=arr.length-1;while(min<=max){int mid=(max+min)>>1;if(key>arr[mid])min=mid+1;else if(key<arr[mid])max=mid-1;elsereturn mid;}return -1;//如果,这里返回min,那么就是把一个元素插入到该数组中的位置。//java提供的方法返回的是-min-1;//好处:1 知道此数不存在,是负数;// 2 若是为了得到插入位置,可以直接取反再减1得到。//之所以不用-min而是-min-1:当该数不存在且插入位置应为0时如上例,//查找-5,插入位置应该是0,返回-0,即0;//那就意味着该数存在,是第一个元素,其实不存在,所以就用-min-1,-0-1就是-1,//说明该数不存在,取反再加减1得0,就知道该数应该插入到0角标位置。}}



 3   数组简单应用

数组的应用,学生只能做一些基础的笔记。这里主要介绍查表法的使用

查星期

输入一个阿拉伯数字,返回一个对应的星期几的字符串,示例:

class Test{public static void main(String[] args){String str=getWeek(2);System.out.println(str);}public static String getWeek(int num){if(num<8 && num>0){String[] week={"","星期一","星期二","星期三","星期四","星期五","星期六","星期日",};return week[num];}elsereturn "哥们,你是火星来的吧!";}}


进制转换中的应用

简单十进制转二进制  示例:

分析:

创建一个查表字符数组,只有两个元素:01

创建一个存储字符的数组,把查到的对应的二进制位存储到数组中

当数不为0时,在while循环内进行主要转换操作

|----获取数字的首个二进制位,利用数字&1运算

|----将获得的二进制位进行查表,将对应的字符存储到字符数组中

|----把数字右移1位,以便获取下一个二进制位

class Test{public static void main(String[] args) {toBinary(60);}public static void toBinary(int num){//如果是0,直接返回,不进行后面的运算if(num==0){System.out.println(0);return;}//定义字符表char[] ch={'0','1'};char[] chs=new char[16];int pos=0;while(num!=0){int temp=num&1;//获取一个二进制位chs[pos++]=ch[temp];//将对应的字符存储到数组中num=num>>>1;//右移移位,继续获取下一个二进制位}for (int i=pos-1;i>=0 ;i-- ){System.out.print(chs[i]);//输出数字转换后的二进制格式}}}


综合进制转换  示例

学生将代码进行了一些小小的优化,把二进制,8进制和16进制放在一起是实现。

通过训练,将查表法加深理解和记忆。

class Test{public static void main(String[] args) {formSearch(60,8);}//进制转换方法,num为要转的十进制数,key为转为的进制数public static void formSearch(int num,int key){//创建查表字符数组char[] chs={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};//创建一个32个字符长度的字符数组char[] ch=new char[32];int count=0;if(num==0){System.out.println(0);return;}//进制转换主要操作while(num!=0){//数字与(进制数-1)做与运算,获得首位int temp=num&(key-1);//将查表的结果存储到字符数组中ch[count++]=chs[temp];//分情况判断,2进制右移1位if (key==2)num=num>>>1;//8进制右移3位else if (key==8)num=num>>>3;//16进制右移4位else if(key==16)num=num>>>4;}}for(int i=count-1;i>=0;i--){System.out.print(ch[i]);}}}


以上是学生总结的数组简单的应用,只是对查表法进行了。


 4  数组工具类


数组工具类Arrays 是专门对数组进行操作的一个类,里面的方法全部是静态的。可以用类名直接调用,不用建立对象,使用方便。

常用方法:

排序

Arrays类中java工程师定义好了专门对数组进行排序的方法:sort(参数列表

对各种数据类型的各种排序操作,定义了多重重载方法。例如:

|----sort(byte[] a)
对指定的 byte 型数组按数字升序进行排序。

|----sort(byte[] a, int fromIndex, int toIndex)
对指定 byte 型数组的指定范围按数字升序进行排序。

把数组转成字符串表现形式

|----toString(byte[] a)
返回指定数组内容的字符串表示形式。

二分法查找 如:

|----binarySearch(byte[] a, byte key)
使用二分搜索法来搜索指定的 byte 型数组,以获得指定的值。

以上是学生的简单总结。数组现在了解学习的内容有:数组的创建、查找、排序、查表法、数组工具类应用等。在后续的虚席中还有很多地方接触到数组,数组的应用还是非常频繁的。把数组作为一个工具来使用,作为临时容器中转数据站,使用非常灵活。



   本篇博文结束!




                                                                                                   @感谢老师的辛苦批阅



原创粉丝点击