黑马程序员-数组问题小解

来源:互联网 发布:棋牌软件 编辑:程序博客网 时间:2024/06/07 02:00
---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------
数组问题小解
        本文适合接触JAVA5~10天的初学者。
        在初学数组时,我们面对得最多的就是int类型的数组,处理问题也主要是自然数的数学问题,由于接触ArrayList等集合的时间与初学数组的时间有一定进度上的差距,但是这并不妨碍我们可能还没学完冒泡排序就遇到了棘手的问题,下面我用基础测试中的数组去重问题为大家举例: 
例如:
原始数组是{4,2,4,6,1,2,4,7,8}
得到结果{4,2,6,1,7,8}
       这道题如果不用集合类该怎么解呢?这是否可以给你带来小学奥数的感觉?笔者在连面向对象的概念都木有的时候,书上的数组章节后就出现了一道类似的练习题(那道题要求去掉数组中的非零项)而在做基础测试时虽然已经学了集合类,但是看到它仍希望把当初的方案分享给大家。
首先咱们要初始化原始数组,题目给出的数组符合静态初始化的条件:
int oldArr[]={4,2,4,6,1,2,4,7,8};
        也许我们已经学会了怎么判断重复的数据,但是显然我们是没办法从这个数组中删除这些元素的,我们只能去新建一个数组。
       那新数组oldArr[]呢?虽然我们都知道答案时{4,2,6,1,7,8},但是我们想必不能像老数组一样去静态初始化了而此时我们除了这种静态初始化以外就只学过另一种方法:
类型 数组名[]=new 数据类型[个数];
如果这步顺利完成了的话我们就可以通过循环为新的数组中的元素:数组名[数组索引编号]来往里添加索引地址了
新的数组类型已经确认为int,那么个数如何确认呢?那就源自于我们对原始数组中不重复的元素的判断了,在这里可以告诉大家,由于数组的类型是int,所以我们可以单纯的用“==”的返回值来判断两者是否相等了,让我们首先将数组内重复的变量找出来吧:
让我们尝试一组嵌套循环
for(int i=1;i<oldArr.length;i++){//嵌套循环给与数组索引编号靠后的项数相同的项赋值为0
for(int j=0;j<i;j++){
if(oldArr[i]==oldArr[j]){

}
}
}
        嵌套循环有的时候设计起来要比直接的判断+搬挪数组元素更费一点逻辑,还好它同样是属于比较靠前的初学内容,在99乘法表的打印中就涉及到了。这个设计在构思起来实际上是比后来用集合解决这个问题要难的,后面讲类集的时候,去重只是用10分钟来作为例子讲解某个类集的特性存在了。
        已经可以找出来数组中重复的数字了,但是我们要怎么做呢?问号部分写什么代码呢?我这里填个用来定义新数组长度的计数器让它改变数值如何?比如在外面定义一个count=oldArr.length,然后在问号部分count—可好?可以说如果是去掉非零项,这里是没问题的。而恰好在这里则不行,因为数组中存在了三个4,出现了重复判断的问题,在这里我们是否可以通过改变那些重复的元素的特性来解决问题呢?比如嵌套循环结束后,我们将原数组oldArr[]变为了{4,2,0,6,1,0,0,7,8};我们再从中提取非零项就变得更容易了,但是这道题是解决了,但是这类的问题呢?如果数组中包含0了呢?这里我们就可以有很多种思路了,比如我们可以初始化一个数,然后再循环判断它是否不会存在此数组中,如果数组中出现了跟它的初始值一致的情况了,我们就在它的初值中变化一点儿,直到没有一样了的为止。这个说起来有点儿复杂,但是已数组所学还是可以实现的:
int nonexistent=0;
int a=0;
while(a<arr.length){
for(int i=0;i<arr.length;i++){
if(arr[i]==nonexistent)
nonexistent--;
}
a++;
       大家看到这里会不会感觉太麻烦了呢?这种代码编纂起来显然是比较耗费脑力的,也许我们的思路都出现了局限,我们为什么不引入第三方的数组呢?比如我们定义一个与原数组一模一样长度的数组,然后让它们的初值都一致,然后如果咱们这个数组出现了重复,将第三方数组同样的角标位置的元素数值改变不是也可以么?从头到尾的判断都带着这个临时数组,大家是否会觉得也是件有趣的事呢?其实还有很多更好的思路的,在这里就不一一赘述了,下面我们先简单的把数组中的元素改成0来进行简单的处理,看下后面的代码。
首先通过数数去找非零项的个数:
Int x=count;//初始化新数组的大小
for(int i=0;i<oldArr.length;i++){//判断原始数组变更后的0项的个数
if(oldArr[i]!=0){ //并从新数组长度的初值减去
count++;
循环结束以后新数组的大小就可以确定了下面来初始化新数组
int newArr[]=new int[count];
然后我们如何去讲原始数组满足条件加入新数组呢?
看看下面这段代码是否满足要求
for(int i=0;i<oldAr.length;i++){
if(oldArr[i]!=0){ 
newArr[i]=oldArr[i];
上面这段代码如果运行会发现一个问题,新老数组索引编号不同,无法对号入座我们看到将for(int i=0;i<oldArr.length;i++)改为for(int i=0;i<newArr.length;i++)显然也是不行的。
那么就需要加入一个新的循环变量来成为新数组的角标
int x=0;
for(int i=0;i<oldArr.length;i++){
if(oldArr[i]!=0){//将原始数组中的非零项加入新数组
newArr[y]=oldArr[i];
x++;//每被赋值一次,新数组的脚标数值+1以便下次赋值用
这样便解决了新数组的循环数值问题
这个时候再循环输出新数组newArr[]便可以得到{4,2,6,1,7,8}

        在这里笔者将上面的一部分思路封装到了一个类中,咱们一起看一下整体的代码吧:

import java.util.HashSet;/*数组去重例如:原始数组是{4,2,4,6,1,2,4,7,8}得到结果{4,2,6,1,7,8}*/class Arrays{public void fun1(int[] arr){int count=0;//初始化新的数组长度int x=0;//初始化新数组的脚标int nonexistent=0;int a=0;while(a<arr.length){for(int i=0;i<arr.length;i++){if(arr[i]==nonexistent)nonexistent--;}a++;}for(int i=1;i<arr.length;i++){//嵌套循环给与数组索引编号靠后的项数相同的项赋值为nonexistentfor(int j=0;j<i;j++){if(arr[i]==arr[j]){arr[i]=nonexistent;}}}for(int i=0;i<arr.length;i++){//判断原始数组变更后其中元素不等于nonexistent的个数if(arr[i]!=nonexistent){count++;}}int newArr[]=new int[count];//初始化新数组,类型,长度for(int i=0;i<arr.length;i++){if(arr[i]!=nonexistent){//将原始数组中的非nonexistent项加入新数组newArr[x++]=arr[i];//每被赋值一次,新数组的脚标数值+1以便下次赋值用}}for(int i=0;i<newArr.length;i++){System.out.print(newArr[i]+" ");//循环输出新数组}}public void fun2(int[] arr){int count=0;int x=0;boolean flag[] = new boolean[arr.length];for (int i = 0; i < flag.length; i++) {//遍历数组,查找重复的元素。循环结束后,重复的元素对应的标志位置都为true。            if (flag[i]) //如果这个元素对应的标志位已被置为true,则返回循环继续检查下一个元素。                            continue;            for (int j = i+1; j < flag.length; j++) {    //后边元素和此位置上的元素比较,                    if (arr[j]==arr[i]) {     //如果后边元素和前边元素相同,                            flag [j]=true;   //则此重复元素对应的标志位置为true                    }            }}for (int i = 0; i < flag.length; i++) {    //算出不重复元素的个数,记为count,if (!flag[i]) {      //标志位依然为false的对应元素即为不重复的元素count++;}}int index=0;    int [] newArr = new int [count];        //定义新数组,元素个数为count。    for (int i = 0; i < arr.length; i++) {        //将所有不重复的元素存入新数组中            if (!flag[i]) {            newArr[index++]=arr[i];            }    }for(int i=0;i<newArr.length;i++){System.out.print(newArr[i]+" ");//循环输出新数组}}public void fun3(int[] arr){int count=0;int x=0;int a=0;int[] temp=new int[arr.length];//建立于原始数组长度一致的临时数组for(int i=0;i<temp.length;i++){//将临时数组所有数值设定为1temp[i]=1;}for(int i=1;i<arr.length;i++){for(int j=0;j<i;j++){if(arr[i]==arr[j]){temp[i]=0;}}}for(int i=0;i<arr.length;i++){if(temp[i]!=0){count++;}}int newArr[]=new int[count];for(int i=0;i<arr.length;i++){if(temp[i]!=0){newArr[x++]=arr[i];}}for(int i=0;i<newArr.length;i++){System.out.print(newArr[i]+" "); }}public void fun4(int[] arr){HashSet newArr=new HashSet();for(int a:arr){newArr.add(a);}System.out.print(newArr);}}public class Test7 {public static void main(String[] args) {int oldArr[]={4,2,4,6,1,2,4,7,8,0,0,1,-1,-1};//初始化原始数组Arrays a=new Arrays();long time1=System.currentTimeMillis();a.fun1(oldArr);long time2=System.currentTimeMillis();System.out.println(time2-time1+"毫秒");a.fun2(oldArr);long time3=System.currentTimeMillis();System.out.println(time3-time2+"毫秒");a.fun3(oldArr);long time4=System.currentTimeMillis();System.out.println(time4-time3+"毫秒");a.fun4(oldArr);System.out.println(System.currentTimeMillis()-time3+"毫秒");}}

       fun2()中我借用了黑马论坛上的无此姓名兄弟的代码,来用boolead类标定为我们解决的问题,而fun4()则采用了相对先进的工具集中的方法,这里没有为fun4()做优化,主要就是为了让大家感受一下其与其它三种方法比起来,代码篇幅的巨大落差。而我又将每个方法运行了一遍,。又将他们的运行时间附到了去重后的数组后面。看不懂时间计算的朋友没关系,这些都是往后的工具集中现成的方法调用而已。现在让我们来看看运行结果:
4 2 6 1 7 8 0 -1 1毫秒
4 2 -2 6 1 7 8 0 -1 0毫秒
4 2 -2 6 1 7 8 0 -1 1毫秒
[0, 1, 2, 4, 6, 7, 8, -2, -1]3毫秒
       结果是不是很有趣?细心朋友发现结果多了一个-2,这又是为什么呢?大家还可以看到,fun4中自动为咱们的数组按一定的规律排的书顺序,而且为什么它的编写代码虽然短,运行时间反而长?这些答案大家可以在以后的集合学习中慢慢寻找答案。
      是不是感觉有些小题大做?希望能给大家带来些乐趣吧。


---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------详细请查看:www.itheima.com
0 0
原创粉丝点击