Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/367.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java数据结构,具有高效的添加、删除和随机_Java_Search_Data Structures_Random - Fatal编程技术网

Java数据结构,具有高效的添加、删除和随机

Java数据结构,具有高效的添加、删除和随机,java,search,data-structures,random,Java,Search,Data Structures,Random,我需要一个可以有效地添加、删除和访问随机对象的Java数据结构 这是不起作用的: ArrayList具有高效的add(常量时间)和随机访问(仅使用随机整数“get”),但删除可能需要线性时间,因为它可能需要搜索整个列表才能找到它 TreeSet或HashSet具有高效的添加和删除功能,但我不知道如何获取随机对象 有什么想法吗 理论上,如果我可以用随机的左键或右键遍历树,那么B树就可以工作,但我认为标准Java类没有给我这种能力 如果标准Java类中的任何东西都不起作用,我愿意使用第三方库 我不需

我需要一个可以有效地添加、删除和访问随机对象的Java数据结构

这是不起作用的:

ArrayList具有高效的add(常量时间)和随机访问(仅使用随机整数“get”),但删除可能需要线性时间,因为它可能需要搜索整个列表才能找到它

TreeSet或HashSet具有高效的添加和删除功能,但我不知道如何获取随机对象

有什么想法吗

理论上,如果我可以用随机的左键或右键遍历树,那么B树就可以工作,但我认为标准Java类没有给我这种能力

如果标准Java类中的任何东西都不起作用,我愿意使用第三方库


我不需要支持重复或空,也不需要是线程安全的


谢谢。

我建议您使用带有整数键的映射。这样,您就可以为删除生成一个随机数


留给读者的问题是:在后续删除(或任何操作)时,都会有间隙。

如果将列表删除设置为无序,则可以使用ArrayList/HashMap对(映射将在其中存储列表中对象的索引)来获得间隙。移除时,您只需移动最后一个元素以填充移除项的空间,而不是将列表中所有后续元素下移一个位置。在拆卸过程中,最多需要接触两种不同的元件。一个简单的例子(我还没有测试过,希望我没有搞错):

class SpecialSet扩展了AbstractSet实现集{
私有最终列表=新的ArrayList();
私有最终映射indexMap=newhashmap();
@凌驾
公共布尔加法(E){
如果(包含(e))返回false;
indexMap.put(e,list.size());
列表.添加(e);
返回true;
}
@凌驾
公共布尔删除(对象o){
整数indexbox=indexMap.remove(o);
if(indexbox==null)返回false;
int索引=索引框;
int last=list.size()-1;
E元素=列表。删除(最后一个);
如果(索引!=最后一个){
indexMap.put(元素、索引);
list.set(索引、元素);
}
返回true;
}
公共电子商务{
E element=list.get((int)(Math.random()*size());
移除(元素);
返回元素;
}
@凌驾
公共布尔包含(对象o){
返回索引map.containsKey(o);
}
@凌驾
公共迭代器迭代器(){
return list.iterator();
}
@凌驾
公共整数大小(){
返回list.size();
}
}

根据您想要的对象相等性测试行为,您可能可以将HashMap替换为IdentityHashMap,以获得更快的速度。

请注意,如果您预先分配到所需的最大大小,一个简单数组就可以完成这项工作。保留一个“top”索引值,并通过递增“top”并存储到该数组元素中来插入。删除时,将“top”值向下复制到已删除的元素中,并减小“top”


如果您不知道自己的最大大小,您仍然可以分配一个数组数组并使用相同的基本算法,只需在访问元素之前首先计算主数组索引值和次数组索引值。

ArrayList.remove(int index)
以摊销的固定时间运行。据我所知,这意味着单个调用是线性时间,但一系列调用的平均时间接近常数时间。感谢Aarowaim,但我不知道要删除的对象的索引。我想我可以将这些信息单独存储在HashMap或其他什么东西中,但是一旦我从ArrayList中删除了一个对象,列表中的其他对象就会改变索引,这意味着HashMap中的一些值可能是错误的,修复它们需要线性时间。@您需要允许重复元素吗?我不需要支持重复或null,也不需要是线程安全的。您在说多少个元素?几百?几千?数以百万计的?它们是简单的数字、字符串还是更复杂的对象?但如果不知道某个值的键,如何删除该值?你仍然需要进行低效的线性搜索才能找到它。哇,谢谢你的代码!我只是把它投入到我的项目中。(我只是将“RemoveAndom”改为“getRandom”,并取出了删除它的行)。它工作得很好!我一直在使用一个ArrayList进行低效的删除,但当我改为这段代码时,处理时间从1900毫秒下降到628毫秒。哇,哇,哇!谢谢,谢谢,谢谢!!我看不出HashMap在这里的重要性。这里最重要的技巧是:移除不是直接移除元素,而是移除最后一个元素,并将最后一个元素放置在需要移除的位置。在这种情况下,只需一个
ArrayList
作为内部结构即可help@AdrianShum您必须先找到一个元素,然后才能删除它;这就是HashMap快速生成的部分。@Boann Oops,你是对的,我忽略了delete部分(我想OP要求按索引删除)
class SpecialSet<E> extends AbstractSet<E> implements Set<E> {
    private final List<E> list = new ArrayList<>();
    private final Map<E,Integer> indexMap = new HashMap<>();

    @Override
    public boolean add(E e) {
        if (contains(e)) return false;
        indexMap.put(e, list.size());
        list.add(e);
        return true;
    }

    @Override
    public boolean remove(Object o) {
        Integer indexBoxed = indexMap.remove(o);
        if (indexBoxed == null) return false;
        int index = indexBoxed;
        int last = list.size() - 1;
        E element = list.remove(last);
        if (index != last) {
            indexMap.put(element, index);
            list.set(index, element);
        }
        return true;
    }

    public E removeRandom() {
        E element = list.get((int)(Math.random() * size()));
        remove(element);
        return element;
    }

    @Override
    public boolean contains(Object o) {
        return indexMap.containsKey(o);
    }

    @Override
    public Iterator<E> iterator() {
        return list.iterator();
    }

    @Override
    public int size() {
        return list.size();
    }
}