检索列表大小时发生 ConcurrentModificationException

2023-11-30

对于我的数据结构课程中的一个项目,我的任务是创建一个 3 维范围树,其中每个维度都是 BST。我读这个问题,但这是一个Android问题,而且我们问题的原因似乎不同,唯一的答案是不被接受。

代码墙即将推出。对不起。

涉及班级:

  • Point3D<T>:包含点坐标的通用类。T extends Comparable<T>, and Point3D也扩展它
  • RangeTree<T>:包含整个树的根以及构建和搜索树的方法的通用类

有比这两个更多的类,但它们似乎与我收到 ConcurrentModificationException 的原因无关(链接到芝商所)。 这是我运行驱动程序时得到的结果:

Read in 10 points //Number of points read in driver, this is okay
5//first median, 10 / 2
2//second median 5 / 2
first[0.082  0.791  0.832  , 0.366  0.136  0.009  ]//correct
second[0.138  0.968  0.391  , 0.414  0.785  0.883  , 0.546  0.044  0.133  ]//correct
merged[0.082  0.791  0.832  , 0.366  0.136  0.009  ]//not correct
first[0.082  0.791  0.832  , 0.366  0.136  0.009  ]//printed again. why?
2//secondHalf being sorted
first[0.415  0.64  0.099  , 0.513  0.612  0.466  ]//correct
second[0.091  0.719  0.772  , 0.199  0.999  0.086  , 0.896  0.835  0.86  ]//correct
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$SubList.checkForComodification(ArrayList.java:1231)
at java.util.ArrayList$SubList.size(ArrayList.java:1040)
at RangeTree.mergeList(RangeTree.java:189)
at RangeTree.sortAscending(RangeTree.java:175)
at RangeTree.sortAscending(RangeTree.java:173)
at RangeTree.build3DTree(RangeTree.java:126)
at RangeTree.build(RangeTree.java:11)
at Main.main(Main.java:35)

When RangeTree.build被称为(Main.java:35),它需要一个List<Point3D<T>>并将其传递给RangeTree.build3DTree(RangeTree.java:11) 它还需要剩余 # 个维度来构建,以及一个指示是否List已经排序了。该方法中的 RangeTree.java:126 是我调用的行sortAscending in build3DTree.

sortAscending(它是递归的)通过比较某个维度上的点来完成听起来的样子,从x(x = 0, y = 1, z = 2),如果它们相等,它会检查下一个维度等。基于上述,它显然工作得很好,除了那个奇怪的故障Line 172以某种方式打印两次。下面是sortAscending代码(所有打印行纯粹用于调试):

private List<Point3D<T>> sortAscending(List<Point3D<T>> pointArr){

    if(pointArr.size() <= 3){//minimum sublist size is 3
        int median = findMedian(pointArr);
        Point3D<T> medianElement = pointArr.get(median);//retrieves coordinate to sort on
        int compareLeft = medianElement.compareTo(pointArr.get(median - 1));
        if(compareLeft < 0){//determine if median is less than element to its left. There will always be an element to the left
            pointArr.add(0, pointArr.remove(median));
            medianElement = pointArr.get(median);
        }
        try{//check median against element to its right. May not be valid if sublist is size 2
            int compareRight = medianElement.compareTo(pointArr.get(median + 1));
            if(compareRight > 0){
                Point3D<T> rightEnd = pointArr.get(median + 1);
                Point3D<T> leftEnd = pointArr.get(median - 1);
                if(rightEnd.compareTo(leftEnd) < 0)
                    pointArr.add(0, pointArr.remove(median + 1));
                else
                    pointArr.add(median, pointArr.remove(median + 1));
            }
        } catch (IndexOutOfBoundsException e){

        }
        return pointArr;
    }
    int median = findMedian(pointArr);//returns pointArr.size() / 2
    System.out.println(median);//for debugging
    List<Point3D<T>> firstHalf = sortAscending(pointArr.subList(0, median));
    System.out.println("first" + firstHalf); //prints twice, once when it should, and again after Line 176 prints
    List<Point3D<T>> secondHalf = sortAscending(pointArr.subList(median, pointArr.size()));//Line 173
    System.out.println("second" + secondHalf);//debugging
    List<Point3D<T>> merged = mergeList(firstHalf, secondHalf);//Line 175
    System.out.println("merged" + merged);//debugging
    return merged;//mergeList(firstHalf, secondHalf);
}

所以,CME 的最终来源似乎是在mergeList,并且直到调用后半部分数据才中断。mergeList(迭代)需要两个List<Point3D<T>>并将它们合并成一个按升序排序的列表,然后返回。也就是说,它采用第一个参数并将其修改为合并列表并返回它。代码:

private List<Point3D<T>> mergeList(List<Point3D<T>> firstList, List<Point3D<T>> secList){
    int sListSize = secList.size();
    int fListSize = firstList.size();//Line 188
    Point3D<T> firstListElement = firstList.get(fListSize - 1);
    Point3D<T> secListElement = secList.get(0);

    if(secListElement.compareTo(firstListElement) >= 0){//check to see if secList can be appended to end of firstList e.g. firstList = {1, 2} secList = {3, 4, 5}
        firstList.addAll(secList);
        return firstList;
    }

    secListElement = secList.get(secList.size() - 1);
    firstListElement = firstList.get(0);

    if(secListElement.compareTo(firstListElement) <= 0){//check to see if firstList can be appended to the end of secList e.g. secList = {1, 2} firstList = {3,4,5}
        secList.addAll(firstList);
        return secList;
    }

    for(int a = 0; a < secList.size(); a++){//take an element from secList and insert it into firstList
        secListElement = secList.get(a);
        int minIdx, maxIdx, median = findMedian(firstList);
        int mComp = secListElement.compareTo(firstList.get(median));//compare to the median of firstList to choose side to start from
        if(mComp < 0){
            minIdx = 0;
            maxIdx = median;
        }
        else if(mComp > 0){
            minIdx = median;
            maxIdx = firstList.size();
        }
        else{//if mComp is 0, insert it at median index
            firstList.add(median, secList.get(a));
            continue;
        }

        for(; minIdx < maxIdx; minIdx++){
            firstListElement = firstList.get(minIdx);
            int compare = secListElement.compareTo(firstListElement);
            if(compare <= 0){
                firstList.add(minIdx, secList.get(a));
                break;
            }
        }
    }
    return firstList;
}

因此,由于某种原因,当我尝试访问的大小时,CME 出现了firstList。我不知道为什么会发生这种情况。我已经使用数据集(下面发布)手动跟踪了我的代码,完成了每个步骤,但我看不到 CME 来自哪里。数据:

10
0.366   0.136   0.009
0.082   0.791   0.832//beautiful 3D points
0.138   0.968   0.391
0.414   0.785   0.883
0.546   0.044   0.133
0.513   0.612   0.466
0.415   0.640   0.099
0.199   0.999   0.086
0.896   0.835   0.860
0.091   0.719   0.772
0.25 0.75 0.25 0.75 0.25 0.75//range queries. Code fails before we get to this
0.75 0.25 0.8 0.1 0.9 0.1
0.95 1.75 0.1 0.01 0.1 0.2
exit//no more queries

问题是这个函数List#subList不会返回允许您修改的列表的副本。您需要制作这些列表的可变副本。不完全确定为什么并发检查只在size()但看看子列表抛出 ConcurrentModificationException进行讨论

编辑:检查仅发生的可能原因size():您可以进行不会扰乱子列表结构的更改,例如与Collections.swap。他们只能将支票放入size()允许这些“结构保留”操作的实施而不会立即崩溃,因此您的调用add()可能已经被单独留下了。

编辑2:解决这个问题的一种方法可能是始终按原样传递原始列表,并使用索引来定义递归的子列表范围

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

检索列表大小时发生 ConcurrentModificationException 的相关文章

  • 带有 Android 支持库 v7 的 Maven Android 插件

    我使用 maven android plugin 构建我的 android 应用程序 它依赖于 android 支持库 v4 和 v7 由于我没有找到如何从developer android com下载整个sdk 因此我无法使用maven
  • 使用 WebDriver 单击新打开的选项卡中的链接

    有人可以在这种情况下帮助我吗 场景是 有一个网页 我仅在新选项卡中打开所有指定的链接 现在我尝试单击新打开的选项卡中的任何一个链接 在下面尝试过 但它仅单击主 第一个选项卡中的一个链接 而不是在新选项卡中 new Actions drive
  • 当路径的点超出视野时,Android Canvas 不会绘制路径

    我在绘制路径时遇到了 Android Canvas 的一些问题 我的情况是 我有一个相对布局工作 如地图视图 不使用 google api 或类似的东西 我必须在该视图上绘制一条路径 canvas drawPath polyPath bor
  • Base36 编码字符串?

    我一直在网上查找 但找不到解决此问题的方法 在 Python Ruby 或 Java 中 如何对以下字符串进行 Base 36 编码 nOrG9Eh0uyeilM8Nnu5pTywj3935kW 5 Ruby 以 36 为基数 s unpa
  • (Java) App Engine 中的静态文件无法访问

    The 示例文档 http code google com appengine docs java gettingstarted staticfiles html表示您只需将文件放在 war 或子目录 中 并且应该可以从主机访问它们 只要它
  • 文本在指定长度后分割,但不要使用 grails 打断单词

    我有一个长字符串 需要将其解析为长度不超过 50 个字符的字符串数组 对我来说 棘手的部分是确保正则表达式找到 50 个字符之前的最后一个空格 以便在字符串之间进行彻底的分隔 因为我不希望单词被切断 public List
  • 为自定义驱动程序创建 GraphicsDevice

    我正在开发一个在嵌入式系统中使用 Java 的项目 我有用于屏幕和触摸输入的驱动程序 以及用于文本输入的虚拟键盘 我的屏幕驱动程序有一个Graphics2D您可以绘制的对象和repaint Rectangle 更新方法 类似地 触摸驱动器能
  • 在 MongoDB 和 Apache Solr 之间同步数据的简单方法

    我最近开始使用 MongoDB 和 Apache Solr 我使用 MongoDB 作为数据存储 并且希望 Apache Solr 为我的数据创建索引 以实现应用程序中的搜索功能 经过一些研究 我发现 基本上有两种方法可以在 MongoDB
  • Java:从集合中获取第一项

    如果我有一个集合 例如Collection
  • 如何通过注解用try-catch包装方法?

    如果应该在方法调用中忽略异常 则可以编写以下内容 public void addEntryIfPresent String key Dto dto try Map
  • 在 Java 中通过 XSLT 分解 XML

    我需要转换具有嵌套 分层 表单结构的大型 XML 文件
  • 如何删除日期对象的亚秒部分

    当 SQL 数据类型为时间戳时 java util Date 存储为 2010 09 03 15 33 22 246 如何在存储记录之前将亚秒设置为零 例如 在本例中为 246 最简单的方法是这样的 long time date getTi
  • Prolog 中的隔离列表

    我很难理解如何让我的代码显示由偶数和奇数组成的隔离列表 我什至不确定我的理解缺乏什么 显然我对这门语言很陌生 必须在学校使用它 我的命令式和功能性思维不会让我知道这到底是怎么回事 哈哈 现在 不 我不是要求你做我的作业 我只是请你帮我看看我
  • Java:如何确定文件所在的驱动器类型?

    Java 是否有一种独立于平台的方法来检测文件所在的驱动器类型 基本上我有兴趣区分 硬盘 可移动驱动器 如 USB 记忆棒 和网络共享 JNI JNA 解决方案不会有帮助 可以假设 Java 7 您可以使用 Java 执行 cmd fsut
  • 我们如何测试包私有类?

    我正在看书Effective Java in Item 13 Minimize the accessibility of classes and members 它提到 为了方便测试 您可能想让类 接口或成员更易于访问 这在某种程度上是好的
  • Play.application() 的替代方案是什么

    我是 Play 框架的新手 我想读取conf文件夹中的一个文件 所以我用了Play application classloader getResources Data json nextElement getFile 但我知道 play P
  • 如何在Java中对对象数组进行字段级别排序以进行等级比较?

    In Java Class StudentProgress String Name String Grade CTOR goes here main class main method StudentProgress arrayofObje
  • 如何处理 StaleElementReferenceException

    我正在为鼠标悬停工作 我想通过使用 for 循环单击每个链接来测试所有链接的工作条件 在我的程序中 迭代进行一次 而对于下一次迭代 它不起作用并显示 StaleElementReferenceException 如果需要 请修改代码 pub
  • ECDH使用Android KeyStore生成私钥

    我正在尝试使用 Android KeyStore Provider 生成的私有文件在 Android 中实现 ECDH public byte ecdh PublicKey otherPubKey throws Exception try
  • 将对象从手机共享到 Android Wear

    我创建了一个应用程序 在此应用程序中 您拥有包含 2 个字符串 姓名和年龄 和一个位图 头像 的对象 所有内容都保存到 sqlite 数据库中 现在我希望可以在我的智能手表上访问这些对象 所以我想实现的是你可以去启动 启动应用程序并向左和向

随机推荐