简体   繁体   English

效率未知的java /数组效率低下

[英]Inefficient java / arrays of unknown length

I am making a few methods that are used for finding the prime factors of a certain number. 我正在制作一些用于查找某个数的素因子的方法。 This is broken down into two functions which both use arrays. 这被分解为两个使用数组的函数。 However, in both functions the code is very inefficient. 但是,在这两个函数中,代码效率非常低。 First I have to count the length of the array, make a new array of that length and then use almost the exact same code to populate the array. 首先,我必须计算数组的长度,创建一个具有该长度的新数组,然后使用几乎完全相同的代码来填充数组。

Is there a way I can make the array unknown width and push integers to the end of the array as I find them? 有没有一种方法可以使数组未知宽度并将整数推送到数组的末尾,因为我找到它们?

Here is my code: 这是我的代码:

public class JavaApplication7{
    public static void main(String[] args) {
        System.out.println(Arrays.toString(primeFactors(85251)));
    }
    public static int[] primeFactors(int num){
        int[] factors = primesUpTo(num);
        int originalNum = num;
        int i = 0;
        int count = 0;
        while(num != 1){
            if(num % factors[i] == 0){
                num /= factors[i];
                i = 0;
                count++;
            }else{
                i++;
            }
        }
        int[] primeFactors = new int[count];
        i = 0;
        count = 0;
        while(originalNum != 1){
            if(originalNum % factors[i] == 0){
                originalNum /= factors[i];
                primeFactors[count] = factors[i];
                i = 0;
                count++;
            }else{
                i++;
            }
        }
        return primeFactors;
    }
    public static int[] primesUpTo(int upTo){
        int count = 0;
        int num = 2;
        while(num <= upTo){
            boolean isPrime = true;
            for(int div = 2; div <= num / 2; div++){
                isPrime = num % div == 0 ? false : isPrime;
            }
            count += isPrime ? 1 : 0;
            num++;
        }
        int i = 0;
        num = 2;
        int[] primes = new int[count];
        while(num <= upTo){
            boolean isPrime = true;
            for(int div = 2; div <= num / 2; div++){
                isPrime = num % div == 0 ? false : isPrime;
            }
            if(isPrime){
                primes[i] = num;
                i++;
            }
            num++;
        }
        return primes;
    }    
} 

您可以使用创建为空且没有特定大小的ArrayList ,您可以随时添加( - > add(Object o)或remove( - > remove(int index) )。

You can use an 你可以使用

ArrayList<Integer>

but this requires substantial memory overhead due to auto-boxing. 但由于自动装箱,这需要大量的内存开销。

Or you can use the excellent GNU Trove3 libraries. 或者您可以使用优秀的GNU Trove3库。 These contain an TIntArrayList , which takes care of the resizing for you; 它们包含一个TIntArrayList ,它负责为您调整大小; and is essentially an int[] + a length field. 并且本质上是一个int[] +一个长度字段。 The logic for appending to then is roughly: 追加到那时的逻辑大致是:

double[] array = new double[10]; // Allocated space
int size = 0; // Used space

void add(int v) {
    if (size == array.length) {
        array = Arrays.copyOf(array, array.length * 2);
    }
    array[size++] = v;
}

You could use Arraylists that are more dynamic than Arrays. 你可以使用比Arrays更动态的Arraylists

However in both functions the code is very inefficient as first i have to count the length of the array, make a new array of that length and then use almost the exact same code to populate the array 但是在这两个函数中,代码效率非常低,因为首先我必须计算数组的长度,创建一个长度的新数组,然后使用几乎完全相同的代码来填充数组

However, you will find that Arraylists do seem dynamic but underneath they do a similar thing. 然而,你会发现Arraylists确实看起来很动态,但在它们下面却做了类似的事情。 They start with a size and make a copy of the underlying Array to a bigger one etc. 它们以一个大小开始,并将基础Array的副本复制到更大的Array等。

Another thing you can do if you know some upper bounds to how many numbers you will have to store is to implement you own container class. 如果你知道要存储多少个数字的上限,你可以做的另一件事就是实现你自己的容器类。 It can have a big array to hold the numbers and a length variable, for looping through the elements. 它可以有一个大数组来保存数字和一个长度变量,用于循环遍历元素。

For example: 例如:

public class NumberContainer(){

    private int[] elements;
    private int numOfElements;

    public NumberContainer(int size){
        elements = new int[size];
        numOfElements = 0;
    }

    //add a number

    public void add(int x){
        elements[numOfElements] = x;
        numOfElements++;
    }

    //get length
    public int length(){
        return numOfElements;
    }

}

....and so on. ....等等。

This way you don't have to copy an Array to a new large one, allways assuming that you instantiate the NumberContainer with a large enough size. 这样,您不必将Array复制到新的大Array ,总而言之,假设您实例化具有足够大的NumberContainer

Hope this helps 希望这可以帮助

Use an ArrayList if you still need fast retrieval by Index. 如果仍需要Index快速检索,请使用ArrayList Otherwise consider a LinkedList, as add = O(1). 否则考虑一个LinkedList,如add = O(1)。

For LinkedList 对于LinkedList

get(int index) is O(n)
add(E element) is O(1)
add(int index, E element) is O(n)
remove(int index) is O(n)
Iterator.remove() is O(1) <--- main benefit of LinkedList<E>
ListIterator.add(E element) is O(1) <--- main benefit of LinkedList<E>

For ArrayList 对于ArrayList

get(int index) is O(1) <--- main benefit of ArrayList<E>
add(E element) is O(1) amortized, but O(n) worst-case since the array must be resized and copied
add(int index, E element) is O(n - index) amortized, but O(n) worst-case (as above)
remove(int index) is O(n - index) (i.e. removing last is O(1))
Iterator.remove() is O(n - index)
ListIterator.add(E element) is O(n - index)

When to use LinkedList over ArrayList? 何时使用LinkedList而不是ArrayList?

I did 我做到了

        boolean isPrime = true;
        for (int div = 2; div <= num / 2; div++) {
            if (num % div == 0) {
                isPrime = false;
                break;
            }
            // Instead isPrime = num % div == 0 ? false : isPrime;
        }

and the time needed went from 13 to 1 second. 所需时间从13秒到1秒。

Actually I wanted to try 其实我想试试

public static int guessedPrimeCount(int upTo) {
    if (upTo < 10) {
        return 10;
    }
    return (int) (upTo / Math.log10(upTo - 1));
}

public int[] addToPrimes(int[] primes, int count, int p) {
    if (count >= primes.length) {
        primes = Arrays.copyOf(primes, count + 10);
    }
    primes[count] = p;
    return primes;
}

primes = addToPrimes(primes, count, num);
++count;

The guessedPrimeCount is documented, x/log x, or x/log(x-1). 记录了guessedPrimeCount ,x / log x或x / log(x-1)。 On adding a new prime p at [count], one in the worst case has to copy the entire array. 在[count]处添加新的素数p时,最糟糕的情况是必须复制整个数组。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM