郑海波 2013-07-08

问题:

有List<String> list1和List<String> list2,两个集合各有上万个元素,怎样查找两个集合中不同的元素呢?

问题分析:

由于每个list中都有上万个元素,如果用简单的遍历查找算法,那么至少需要10000*10000次判断比较。显然,这样做的效率极低。那么有没有比较好的方案呢?经过我的思考,想出了2个办法。请大家评判。

方法一:遍历算法的改进算法

思路:对每一个list1中的元素,都在list2中查找一下,是否重复,如果不重复,则将该元素放到listDiff中。如果重复,则将该元素从list2中剔除。这样,能够减少遍历算法的时间复杂度,而且重复元素越多,该改进算法的运行时间就越短。当然,如果两个list的重复元素个数远远小于list的长度,则该算法的时间复杂度和遍历算法近似相同,会变的很慢而不切实际。

方法二:利用Map中无重复元素的特性

思路:将list1中元素首先复制到map<String,Integer>中,并将其Integer的值设置为1.然后再对list2中的元素,与map中元素比较。如果map中已经存在该String,那么map中对应String的Integer加1(表示字符串出现的次数),如果map中不存在,那么就将其复制到map中,并设置其Integer为1.那么,map中Integer值为1的元素所对应的String,就是两个list中不同的元素。

以下代码是在Java中实现,也可以用C++ STL进行测试。

  1. import java.util.ArrayList;
  2. import java.util.HashMap;
  3. import java.util.List;
  4. import java.util.Map;
  5. /*
  6. *@author: ZhengHaibo
  7. *2013-07-08  Nanjing,Conris,China
  8. */
  9. public class TestMian {
  10. private static final int ListLen = 10000;// 设置list的长度
  11. private static final Integer flagUnique = 1;//无重复字符串的键值
  12. public List<String> list1 = new ArrayList<String>();
  13. public List<String> list2 = new ArrayList<String>();
  14. public static void main(String[] args) {
  15. // TODO Auto-generated method stub
  16. TestMian mTest=new TestMian();
  17. mTest.initList();
  18. List<String> listDiff1=mTest.getDiffElementUseEach(mTest.list1,mTest.list2);//获得不同元素
  19. mTest.initList();
  20. List<String> listDiff2=mTest.getDiffElementUseMap(mTest.list1,mTest.list2);//获得不同元素
  21. System.out.println("The number of diff element is: "+listDiff1.size());
  22. System.out.println("The number of diff element is: "+listDiff2.size());
  23. //mTest.printList(listDiff1);
  24. //mTest.printList(listDiff2);
  25. }
  26. // 初始化list中的元素,并保证有相同的元素
  27. public void initList() {
  28. list1.clear();
  29. list2.clear();
  30. for (int i = 0; i < ListLen; i++) {
  31. list1.add("conris_list_of" + i + "test");
  32. list2.add("conris_list_of" + 3 * i + "test");
  33. }
  34. }
  35. //获得连个list中的不同元素,查找删除法
  36. public List<String> getDiffElementUseEach(List<String> list1,List<String> list2) {
  37. System.out.println("-----------------------方法1----------------------");
  38. long runtime = System.nanoTime();// 开始计时
  39. List<String> diffList = new ArrayList<String>();// 用于保存两个list中不同的元素
  40. for (String string:list1) {//消除list1本身的重复元素
  41. int index=list2.indexOf(string);
  42. if (index==-1) {//说明list2中不存在此元素
  43. diffList.add(string);
  44. }else{//list2存在此元素,那么删除此元素
  45. list2.remove(index);
  46. }
  47. }
  48. for(String string:list2){//此时,liat2中的重复元素已经删除了,只需要复制到diffList中即可
  49. diffList.add(string);
  50. }
  51. System.out.println("getDiffElementUseRemove run time:"
  52. + (System.nanoTime() - runtime));
  53. return diffList;
  54. }
  55. //获得两个list中的不同元素,map方法
  56. public List<String> getDiffElementUseMap(List<String> list1,List<String> list2){
  57. System.out.println("-----------------------方法2----------------------");
  58. long runtime = System.nanoTime();//开始计时
  59. //利用map中不能有重复元素的特点
  60. Map<String, Integer> map = new HashMap<String,Integer>(list1.size()+ list2.size());
  61. List<String> diffList = new ArrayList<String>();//用于保存两个list中不同的元素
  62. for (String string : list1) {
  63. map.put(string,flagUnique);//先将list1中元素复制到map中保存
  64. }
  65. for (String string : list2) {
  66. Integer key = map.get(string);// 获得键值
  67. if (key != null) {//如果map中已经存在该元素,说明list1中存在该元素,那么将其key加1
  68. map.put(string, ++key);
  69. continue;
  70. }else{//如果不存在,则放入map中
  71. map.put(string,flagUnique);
  72. }
  73. }
  74. for (Map.Entry<String, Integer> entry : map.entrySet()){
  75. if (entry.getValue() == flagUnique)//在map中,键值为flagUnique的元素即为无重复的元素
  76. {
  77. diffList.add(entry.getKey());
  78. }
  79. }
  80. System.out.println("getDiffElementUseMap run time:"
  81. + (System.nanoTime() - runtime));
  82. return diffList;
  83. }
  84. public void printList(List<String> list){
  85. for(int i=0;i<list.size();i++){
  86. System.out.println(list.get(i));
  87. }
  88. }
  89. }

实验结果:

当ListLen设置为10000时:

结果1:

  1. -----------------------方法1----------------------
  2. getDiffElementUseRemove run time:2015792051
  3. -----------------------方法2----------------------
  4. getDiffElementUseMap run time:37966034
  5. The number of diff element is: 13332
  6. The number of diff element is: 13332

当ListLen设置为100000时:等了半天方法1没有运行出来结果,方法2的运行结果如下:

  1. -----------------------方法2----------------------
  2. getDiffElementUseMap run time:471017640
  3. The number of diff element is: 133332

可见当数据量达到100000时(增大10倍),方法二仍然可以工作,而且时间也随着数据量增大线性增加。

而方法1很久也没有运行出来结果…

由此可见,利用HashMap的方法速度更快,能够满足基本要求。不知道大家还有哪些想法可以交流交流。希望对大家有帮助。

PS:如果用C++ STL实现的话,运行速度将更快!没事的时候再试试~~

有关《查找两个List中的不同元素》的问题解答与编程实践的更多相关文章

  1. Java - Collection 高效的找出两个List中的不同元素

    如题:有List<String> list1和List<String> list2,两个集合各有上万个元素,怎样取出两个集合中不同的元素? 方法1:遍历两个集合 public ...

  2. php获取两个数组相同的元素(交集)以及比较两个数组中不同的元素(差集)

    (一)php获取两个数组相同元素 array  array_intersect(array  $array1, array $array2, [, array $...]) array  array_ ...

  3. Java Collection - 003 高效的找出两个List中的不同元素

    如题:有List<String> list1和List<String> list2,两个集合各有上万个元素,怎样取出两个集合中不同的元素? 方法1:遍历两个集合 public ...

  4. HashMap通过hashcode对其内容进行快速查找,而 TreeMap中所有的元素都保持着某种固定的顺序

    HashMap通过hashcode对其内容进行快速查找,而 TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用TreeMap(HashMap中元素的排列顺序是不 ...

  5. C语言:返回两个数组中第一个元素的指针,并输出这个值

    // //  main.c //  Pointer_search // //  Created by ma c on 15/8/2. //  Copyright (c) 2015年. All righ ...

  6. 寻找两个数组中的公共元素Java程序代码

    package lianxi; import java.util.*; public class UnionSearch { public static void main(String[] args ...

  7. 获取两个List中的不同元素,4种方法,逐步优化,学习使用

    完全复制https://www.cnblogs.com/czpblog/archive/2012/08/06/2625794.html 先上测试结果 代码 package com.syl.test; ...

  8. 遍历查找集合或者数组中的某个元素的值 java代码 详解 Android开发

    import java.util.Scanner; public class Test21 { public static void main(String[] args) { //定义并初始化数组 ...

  9. 高效的找出两个List中的不同元素

    /* * TestList.java * Version 1.0.0 * Created on 2017年12月15日 * Copyright ReYo.Cn */ package reyo.sdk. ...

随机推荐

  1. express 应用创建及app.js详解

    #1 express 应用创建 1.安装node.js (自行百度) 2.npm install express -g 3.全局安装express生成器 express-generator npm i ...

  2. python浅谈编程规范和软件开发目录规范的重要性

    前言 我们这些初学者,目前要做的就是遵守代码规范,这是最基本的,而且每个团队的规范可能还不一样,以后工作了,尽可能和团队保持一致,目前初学者就按照官方的要求即可 新人进入一个企业,不会接触到核心的架构 ...

  3. kafka2x-Elasticsearch 数据同步工具demo

    Bboss is a good elasticsearch Java rest client. It operates and accesses elasticsearch in a way simi ...

  4. 改写画质、突破性能, Unity 全面升级!

    技术变革,时代更迭.从<神庙逃亡>.<暗影之枪>等主流手游到独立联网的大型游戏,从绚丽多彩的影视动画到具备极致体验的运输建筑制造行业,从传统的2D 到立体3D 乃至沉浸式的VR ...

  5. 将UIImage转换成圆形图片image

    建议写成UIImage分类,如下: .h //变成圆形图片 - (UIImage *)circleImage; .m //变成圆形图片 - (UIImage *)circleImage { // NO ...

  6. Android开发:界面设计之六大layouts介绍

    1.帧布局 FrameLayout: FrameLayout是最简单的布局对象.在它里面的的所有显示对象都将固定在屏幕的左上角,不能指定位置,后一个会直接覆盖在前一个之上显示 因为上面的一段话这个是在 ...

  7. C++ 知识零碎搭建

    全局变量 局部变量 函数不能嵌套定义 C/C++ 变量在将要被使用时定义即可, 不必一开始就声明所有变量 函数的定义与声明的区别 C++常规类型自动类型转换规则 C语言中十六进制和八进制的格式: 二进 ...

  8. node.js的C++入门

    最近的任务是把计划库的API用JavaScript语言调用起来,需要用Node.js的C++扩展,本文简单归总一下node.js addons官方文档https://nodejs.org/api/ad ...

  9. 配置VSCode开发Vue项目

    一.安装VSCode.NodeJS VSCode:https://code.visualstudio.com/ NodeJS:https://nodejs.org/en/ 二.打开VSCode,安装常 ...

  10. mmap 与 munmap

    功能描述 mmap(memory map) 将一个文件或其他对象映射进内存. 文件被映射到多个page上, 若文件的大小不是所有page的大小之和, 最后一个page不被使用的空间将会被清零. mum ...