gpt4 book ai didi

java - Java 中集合的 size() 的时间复杂度是多少?

转载 作者:塔克拉玛干 更新时间:2023-11-01 21:40:10 25 4
gpt4 key购买 nike

我知道,这似乎是一个愚蠢的问题,你会期望 size() 在任何集合上的时间复杂度都是 O(1) - 但我发现我的代码中的“优化”需要调用 size() 实际上会减慢速度。

那么,Java 中 Set 的 size() 的时间复杂度是多少?

我的代码是一个递归算法的实现,用于查找图中的最大团(不重要)。基本上,优化只是检查两个 Set 的大小是否相等(这些 Set 以任何一种方式构建),如果它们的大小相等,则只允许再进行一次递归调用(之后停止递归)。

这是我的代码的(简化)版本:

        private static void recursivelyFindMaximalCliques(Set<Integer> subGraph, Set<Integer> candidates, Set<Integer> notCandidates) {
boolean noFurtherCliques = false;

Iterator<Integer> candidateIterator = candidates.iterator();
while (candidateIterator.hasNext()) {
int nextCandidate = candidateIterator.next();
candidateIterator.remove();
subGraph.add(nextCandidate);

Set<Integer> neighbors = getNeighbors(nextCandidate);
Set<Integer> newCandidates = calculateIntersection(candidates, neighbors);
Set<Integer> newNotCandidates = calculateIntersection(notCandidates, neighbors);

//if (newCandidates.size() == candidates.size())
// noFurtherCliques = true;
recursivelyFindMaximalCliques(subGraph, newCandidates, newNotCandidates);
//if (noFurtherCliques)
// return;

subGraph.set.remove(nextCandidate);
notCandidates.set.add(nextCandidate);
}
}

我注释掉的行是有问题的行 - 你可以看到他们检查集合 newCandidates 和 candidates 是否相同大小,如果是,递归只允许更深一层。

当取消注释这些行时,代码运行速度会慢大约 10% - 无论使用的集合是 HashSet、TreeSet 还是 LinkedHashSet,都是如此。这是没有意义的,因为这些行确保递归调用更少。

我唯一可以假设的是在集合上调用 size() 需要很长时间。在 Java 中对 Sets 调用 size() 花费的时间是否比 O(1) 长?

编辑

既然有人问了,这里就是calculateIntersection():

private static IntegerSet calculateIntersection(Set<Integer> setA, Set<Integer> setB) {
if (setA.size() == 0 || setB.size() == 0)
return new Set<Integer>();

Set<Integer> intersection = new Set<Integer>(); //Replace this with TreeSet, HashSet, or LinkedHashSet, whichever is being used
intersection.addAll(setA);
intersection.retainAll(setB);
return intersection;
}

第二次编辑如果您愿意,这是完整的代码。我犹豫要不要发布它,因为它又长又讨厌,但有人问了,所以在这里:

public class CliqueFindingAlgorithm {

private static class IntegerSet {
public Set<Integer> set = new TreeSet<Integer>(); //Or whatever Set is being used
}


private static ArrayList<IntegerSet> findMaximalCliques(UndirectedGraph graph) {
ArrayList<IntegerSet> cliques = new ArrayList<IntegerSet>();
IntegerSet subGraph = new IntegerSet();
IntegerSet candidates = new IntegerSet();
IntegerSet notCandidates = new IntegerSet();

for (int vertex = 0; vertex < graph.getNumVertices(); vertex++) {
candidates.set.add(vertex);
}

recursivelyFindMaximalCliques(cliques, graph, subGraph, candidates, notCandidates);
return cliques;
}


private static void recursivelyFindMaximalCliques(ArrayList<IntegerSet> cliques, UndirectedGraph graph,
IntegerSet subGraph, IntegerSet candidates, IntegerSet notCandidates) {
boolean noFurtherCliques = false;

Iterator<Integer> candidateIterator = candidates.set.iterator();
while (candidateIterator.hasNext()) {
int nextCandidate = candidateIterator.next();
candidateIterator.remove();
subGraph.set.add(nextCandidate);

IntegerSet neighbors = new IntegerSet();
neighbors.set = graph.getNeighbors(nextCandidate);
IntegerSet newCandidates = calculateIntersection(candidates, neighbors);
IntegerSet newNotCandidates = calculateIntersection(notCandidates, neighbors);

if (newCandidates.set.size() == candidates.set.size())
noFurtherCliques = true;
recursivelyFindMaximalCliques(cliques, graph, subGraph, newCandidates, newNotCandidates);
if (noFurtherCliques)
return;

subGraph.set.remove(nextCandidate);
notCandidates.set.add(nextCandidate);
}

if (notCandidates.set.isEmpty()) {
IntegerSet clique = new IntegerSet();
clique.set.addAll(subGraph.set);
cliques.add(clique);
}
}


private static IntegerSet calculateIntersection(IntegerSet setA, IntegerSet setB) {
if (setA.set.size() == 0 || setB.set.size() == 0)
return new IntegerSet();

IntegerSet intersection = new IntegerSet();
intersection.set.addAll(setA.set);
intersection.set.retainAll(setB.set);
return intersection;
}

public class UndirectedGraph {

// ------------------------------ PRIVATE VARIABLES ------------------------------

private ArrayList<TreeMap<Integer, Double>> neighborLists;
private int numEdges;


// ------------------------------ CONSTANTS ------------------------------

// ------------------------------ CONSTRUCTORS ------------------------------

public UndirectedGraph(int numVertices) {
this.neighborLists = new ArrayList<TreeMap<Integer, Double>>(numVertices);
this.numEdges = 0;
for (int i = 0; i < numVertices; i++) {
this.neighborLists.add(new TreeMap<Integer, Double>());
}
}


// ------------------------------ PUBLIC METHODS ------------------------------


public void addEdge(int vertexA, int vertexB, double edgeWeight) {
TreeMap<Integer, Double> vertexANeighbors = this.neighborLists.get(vertexA);
TreeMap<Integer, Double> vertexBNeighbors = this.neighborLists.get(vertexB);

vertexANeighbors.put(vertexB, edgeWeight);
vertexBNeighbors.put(vertexA, edgeWeight);
this.numEdges++;
}


public List<Integer> computeCommonNeighbors(int vertexA, int vertexB) {
List<Integer> commonNeighbors = new ArrayList<Integer>();
Iterator<Integer> iteratorA = this.getNeighbors(vertexA).iterator();
Iterator<Integer> iteratorB = this.getNeighbors(vertexB).iterator();

if (iteratorA.hasNext() && iteratorB.hasNext()) {
int nextNeighborA = iteratorA.next();
int nextNeighborB = iteratorB.next();
while(true) {

if (nextNeighborA == nextNeighborB) {
commonNeighbors.add(nextNeighborA);
if (iteratorA.hasNext() && iteratorB.hasNext()) {
nextNeighborA = iteratorA.next();
nextNeighborB = iteratorB.next();
}
else
break;
}

else if (nextNeighborA < nextNeighborB) {
if (iteratorA.hasNext())
nextNeighborA = iteratorA.next();
else
break;
}

else if (nextNeighborB < nextNeighborA) {
if (iteratorB.hasNext())
nextNeighborB = iteratorB.next();
else
break;
}
}
}

return commonNeighbors;
}

// ------------------------------ PRIVATE METHODS ------------------------------

private class EdgeIterator implements Iterator<int[]> {

private int vertex;
private int[] nextPair;
private Iterator<Integer> neighborIterator;

public EdgeIterator() {
this.vertex = 0;
this.neighborIterator = neighborLists.get(0).keySet().iterator();
this.getNextPair();
}

public boolean hasNext() {
return this.nextPair != null;
}

public int[] next() {
if (this.nextPair == null)
throw new NoSuchElementException();
int[] temp = this.nextPair;
this.getNextPair();
return temp;
}

public void remove() {
throw new UnsupportedOperationException();
}

private void getNextPair() {
this.nextPair = null;

while (this.nextPair == null && this.neighborIterator != null) {
while (this.neighborIterator.hasNext()) {
int neighbor = this.neighborIterator.next();

if (this.vertex <= neighbor) {
this.nextPair = new int[] {vertex, neighbor};
return;
}
}

this.vertex++;
if (this.vertex < getNumVertices())
this.neighborIterator = neighborLists.get(this.vertex).keySet().iterator();
else
this.neighborIterator = null;
}
}
}

// ------------------------------ GETTERS & SETTERS ------------------------------

public int getNumEdges() {
return this.numEdges;
}


public int getNumVertices() {
return this.neighborLists.size();
}


public Double getEdgeWeight(int vertexA, int vertexB) {
return this.neighborLists.get(vertexA).get(vertexB);
}


public Set<Integer> getNeighbors(int vertex) {
return Collections.unmodifiableSet(this.neighborLists.get(vertex).keySet());
}


public Iterator<int[]> getEdgeIterator() {
return new EdgeIterator();
}

最佳答案

这取决于实现;例如 HashSet.size() 只是在其内部 hashMap 上调用 size() 返回一个变量;

//HashSet
public int size() {
return map.size();
}

//Hashmap
public int size() {
return size;
}

关于java - Java 中集合的 size() 的时间复杂度是多少?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16682831/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com