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


--------------------- 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+1
		arr[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、max
2 判断条件,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;
			}
			else
			return -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;
		else
			return 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];
		}
		else
		return "哥们,你是火星来的吧!";
	}
}


进制转换中的应用

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

分析:

创建一个查表字符数组,只有两个元素: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 型数组,以获得指定的值。

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



   本篇博文结束!




                                                                                                   @感谢老师的辛苦批阅



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值