面试必问的集合-1.2:集合常见操作

1:集合遍历,要删除其中一个元素

要想在集合遍历的过程中删除指定元素,就务必使用迭代器自身的remove方法;

可以使用 Iterator 本身的方法 remove() 来删除对象

这种方式可以正常的循环及删除。但要注意的是,使用iterator的remove方法。

2:ArrayList排序

java中实现对list的自定义排序主要通过两种方式

1)让需要进行排序的对象的类实现Comparable接口,重写compareTo(T o)方法,在其中定义排序规则,那么就可以直接调用Collections.sort()来排序对象数组

2)实现比较器接口Comparator,重写compare方法,直接当做参数传进sort中

我们通常使用Collections.sort()方法来对一个简单的数据列表排序。

但是当ArrayList是由自定义对象组成的,就需要使用comparable或者comparator接口了。

倒序:
//            Collections.sort(list, new Comparator<CoterieTag>(){  
//                /*  
//                 * int compare(CoterieTag o1, CoterieTag o2) 返回一个基本类型的整型,  
//                 * 返回负数表示:o1 小于o2,  
//                 * 返回0 表示:o1和o2相等,  
//                 * 返回正数表示:o1大于o2。  
//                 */  
//                public int compare(CoterieTag o1, CoterieTag o2) {  
//                    //按照命中次数进行升序排列  
//                    if(o1.getHitNumber() > o2.getHitNumber()){  
//                        return 1;  
//                    }  
//                    if(o1.getHitNumber() == o2.getHitNumber()){  
//                        return 0;  
//                    }  
//                    return -1;  
//                }  
//            });   


 正序:
            Collections.sort(list, new Comparator<CoterieTag>(){  
                /*  
                 * int compare(CoterieTag o1, CoterieTag o2) 返回一个基本类型的整型,  
                 * 返回负数表示:o1 小于o2,  
                 * 返回0 表示:o1和o2相等,  
                 * 返回正数表示:o1大于o2。  
                 */  
                public int compare(CoterieTag o1, CoterieTag o2) {  
                    //按照命中次数进行升序排列  
                    if(o1.getHitNumber() > o2.getHitNumber()){  
                        return -1;  
                    }  
                    if(o1.getHitNumber() == o2.getHitNumber()){  
                        return 0;  
                    }  
                    return 1;  
                }  
            });   
        }

public class Test {  
  
    public static void main(String[] args) {  
          
        List<Student> list = new ArrayList<Student>();  
          
        //创建3个学生对象,年龄分别是20、19、21,并将他们依次放入List中  
        Student s1 = new Student();  
        s1.setAge(20);  
        Student s2 = new Student();  
        s2.setAge(19);  
        Student s3 = new Student();  
        s3.setAge(21);  
        list.add(s1);  
        list.add(s2);  
        list.add(s3);  
          
        System.out.println("排序前:"+list);  
          
        Collections.sort(list, new Comparator<Student>(){  
  
            /*  
             * int compare(Student o1, Student o2) 返回一个基本类型的整型,  
             * 返回负数表示:o1 小于o2,  
             * 返回0 表示:o1和o2相等,  
             * 返回正数表示:o1大于o2。  
             */  
            public int compare(Student o1, Student o2) {  
              
                //按照学生的年龄进行升序排列  
                if(o1.getAge() > o2.getAge()){  
                    return 1;  
                }  
                if(o1.getAge() == o2.getAge()){  
                    return 0;  
                }  
                return -1;  
            }  
        });   
        System.out.println("排序后:"+list);  
    }  
}  
class Student{  
      
    private int age;  
  
    public int getAge() {  
        return age;  
    }  
  
    public void setAge(int age) {  
        this.age = age;  
    }  
    @Override  
    public String toString() {  
        return getAge()+"";  
    }  
}  


执行结果:
[html] view plain copy
排序前:[20, 19, 21]  
排序后:[19, 20, 21]  

当然对象的属性可以多个,比如按年龄升序,按成绩降序等

3:Arraylist 去重,实现思路

首先说明一下ArrayList和HashSet的区别:

ArrayList是List(列表),数据是有序的,可以有重复元素。

HashSet是Set(集合),数据没有顺序,没有重复元素,元素搜索速度快。

之后我们利用ArrayList->HashSet->ArrayList后即可实现对List的去重工作,实现代码如下:

其实这个还要看集合中存的是什么,

两个例子:

1.ArrayList存储字符去重

2.ArrayList存储自定义对象去重

一 .   ArrayList存储字符串去重。

思路:

a、重新new一个新的List集合。

b、然后遍历旧集合,然后获取旧集合中的每一个元素。

c、判断新集合中是否有 当前遍历到的元素。

      有:就不添加。

     没有:就添加。

二 .   ArrayList存储存储自定义对象去重

这个和第一种情况思路大同小异,不同之处是集合内存储的是对象,代码上有些不同,这里我们写一个Student类来演示

需要注意的是,还要重写toString()方法和equals()方法,

重写hashCode方法,如果你是用hashCode来判断两个对象是否相等。

4:为什么数组查询比链表要快?而插入删除比链表效率低

一般来说数组的查询速度快于链表,原理是什么?

电脑中存在多种不同的存储器,如下表

  • CPU 寄存器 – immediate access (0-1个CPU时钟周期)
  • CPU L1 缓存  – fast access (3个CPU时钟周期)
  • CPU L2 缓存 – slightly slower access (10个CPU时钟周期)
  • 内存 (RAM)   – slow access (100个CPU时钟周期)
  • 硬盘 (file system) – very slow (10,000,000个CPU时钟周期)

各级别的存储器速度差异非常大,CPU寄存器速度是内存速度的100倍!

这就是为什么CPU产商发明了CPU缓存。

而这个CPU缓存,就是数组和链表的区别的关键所在。

 

CPU缓存会把一片连续的内存空间读入, 因为数组结构是连续的内存地址

所以数组全部或者部分元素被连续存在CPU缓存里面, 平均读取每个元素的时间只要3个CPU时钟周期。   

而链表的节点是分散在堆空间里面的,这时候CPU缓存帮不上忙,只能是去读取内存,平均读取时间需要100个CPU时钟周期。

这样算下来,数组访问的速度比链表快33倍! (这里只是介绍概念,具体的数字因CPU而异)

 

其实这里还有一个概念就是操作系统的局部性原理

1、数据存储结构分为顺序存储、链接存储、索引存储、散列存储。

2、数组属于顺序存储,用一段连续的内存位置来存储。

3、链表属于链接存储,用一组任意的存储单元来存储,不要求物理上相邻

总结:

因为CPU缓存会读入一段连续的内存,顺序存储符合连续的内存,所以顺序存储可以被缓存处理,而链接存储并不是连续的,分散在堆中,所以只能内存去处理。

所以数组查询比链表要快。

 

而数组大小固定,插入和删除都需要移动元素,链表可以动态扩充,插入删除不需要移动元素,只需要更改元素中的指针。所以链表的插入删除比数组效率高。

 

多说一句:查询比数组快,删除插入效率又高的方式就是散列存储,散列是什么?散列的英文:hash

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值