性能问题:Java与C ++

我一直听说C ++比Java更高效(因此大多数游戏都是用C ++开发的)。

我使用完全相同的算法编写了一个小算法来解决Java和C ++中的“八皇后难题”,然后开始提高数量或平方。 当达到20 * 20或甚至22 * 22的检查板时,看起来Java更有效(C ++为3秒vs 66秒)。

我不知道为什么,但我很早就开始使用C ++,因此我可能犯了一些巨大的性能错误,所以我会很乐意接受任何有助于我理解正在发生的事情的信息。

以下是我在Java中使用的代码:

import java.awt.Point;
import java.util.ArrayList;
import java.util.List;

public class HuitDames {

    /**
     * La liste des coordnnées des dames.
     */
    private static List<Point> positions = new ArrayList<>();

    /**
     * Largeur de la grille.
     */
    private static final int LARGEUR_GRILLE = 22;


    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        int i = 1;
        placerDame(i);
        for (Point point : positions) {
            System.out.println("(" + point.x + "; " + point.y + ")");
        }
    }

    /**
     * Place une dame et return true si la position est bonne.
     * @param i le numéro de la dame.
     * @return si la position est bonne.
     */
    private static boolean placerDame(int i) {

        boolean bonnePosition = false;
        for (int j = 1; j <= LARGEUR_GRILLE && bonnePosition == false; j++) {
            Point emplacement = new Point(i, j);
            positions.add(emplacement);
            if (verifierPrise(emplacement) && (i == LARGEUR_GRILLE || placerDame(i + 1))) {
                bonnePosition = true;
            }
            else {
                positions.remove(i - 1);
            }
        }

        return bonnePosition;
    }

    /**
     * Vérifie que la nouvelle position n'est pas en prise avec une position déjà présente.
     * @param position la position de la nouvelle dame.
     * @return Si la position convient par rapport aux positions des autres dames.
     */
    private static boolean verifierPrise(Point position) {
        boolean nonPrise = true;
        for (Point point : positions) {
            if (!point.equals(position)) {
                // Cas où sur la même colonne.
                if (position.y == point.y) {
                    nonPrise = false;
                }
                // Cas où sur même diagonale.
                if (Math.abs(position.y - point.y) == Math.abs(position.x - point.x)) {
                    nonPrise = false;
                }
            }
        }

        return nonPrise;
    }
}

以下是C ++中的代码:

#include <iostream>
#include <list>
#include <math.h>
#include <stdlib.h>

using namespace std;


// Class to represent points.
class Point {

    private:
        double xval, yval;

    public:
        // Constructor uses default arguments to allow calling with zero, one,
        // or two values.
        Point(double x = 0.0, double y = 0.0) {
                xval = x;
                yval = y;
        }

        // Extractors.
        double x() { return xval; }
        double y() { return yval; }
};

#define LARGEUR_GRILLE 22
list<Point> positions;


bool verifierNonPrise(Point emplacement) {
    bool nonPrise = true;
    for (list<Point>::iterator it = positions.begin(); it!= positions.end(); it++) {
        if (it->x() != emplacement.x()) {
            if (it->y() == emplacement.y()) {
                nonPrise = false;
            }
            if (abs(it->y() - emplacement.y()) == abs(it->x() - emplacement.x())) {
                nonPrise = false;
            }
        }
    }

    return nonPrise;
}

bool placerDame(int i) {
    bool bonnePosition = false;
    for (int j = 1; j <= LARGEUR_GRILLE && !bonnePosition; j++) {
        Point emplacement(i,j);
        positions.push_back(emplacement);
        if (verifierNonPrise(emplacement) && (i == LARGEUR_GRILLE || placerDame(i + 1))) {
            bonnePosition = true;
        }
        else {
            positions.pop_back();
        }
    }

    return bonnePosition;
}

int main()
{
    int i = 1;
    placerDame(i);
    for (list<Point>::iterator it = positions.begin(); it!= positions.end(); it++) {
        cout << "(" << it->x() << "; " << it->y() << ")" << endl;
    }
    return 0;
}

C ++中的std::list是一个链表,而java.util.ArrayList是一个数组。 尝试用std::list std::vector替换std::list 。 此外,一定要打开优化进行编译。


更新:

对C ++的更改

  • 正如所写:
    编译失败
  • 替换math.h => cmath
    27610毫秒
  • 添加-O3标志
    4416毫秒
  • 用std :: vector替换std :: list
    2294毫秒
  • 用std :: pair替换点
    2384毫秒
  • 使verifierNonPrise常量正确
    2351毫秒
  • 使用std::find_if替换verifierNonPrise中的循环
    929毫秒
  • 用int替换double(使其等同于Java)
    549毫秒
  • 对Java的改变

  • 正如书面
    3459毫秒
  • 更改verifierNonPrise提前返回
    368毫秒
  • Java与C ++

    > javac HuitDames.java
    > time java HuitDames
    real    0m0.368s
    user    0m0.436s
    sys     0m0.042s    
    > g++ -O3 -std=c++11 HuitDames.cpp
    > time ./a.out
    real    0m0.541s
    user    0m0.539s
    sys     0m0.002s
    

    最终代码:

    #include <iostream>
    #include <vector>
    #include <cmath>
    #include <stdlib.h>
    #include <chrono>
    #include <algorithm>
    
    using namespace std;
    
    typedef std::pair<int, int>   Point;
    
    #define LARGEUR_GRILLE 22
    vector<Point> positions;
    
    
    bool verifierNonPrise(Point const& emplacement) {
        return std::find_if(positions.begin(), positions.end(), [&emplacement](Point const& val){
            if (val.first != emplacement.first) {
                if ((val.second == emplacement.second) || (abs(val.second - emplacement.second) == abs(val.first - emplacement.first))) {
                    return true;
                }
            }
            return false;
        }) == positions.end();
    }
    
    bool placerDame(int i) {
        bool bonnePosition = false;
    
        for (int j = 1; j <= LARGEUR_GRILLE && !bonnePosition; j++) {
            Point emplacement(i,j);
            positions.push_back(emplacement);
            if (verifierNonPrise(emplacement) && (i == LARGEUR_GRILLE || placerDame(i + 1))) {
                bonnePosition = true;
            }
            else {
                positions.pop_back();
            }
        }
    
        return bonnePosition;
    }
    
    
    int main()
    {
        using std::chrono::system_clock;
    
        system_clock::time_point begin_time = system_clock::now();
    
        int i = 1;
        placerDame(i);
        for (vector<Point>::iterator it = positions.begin(); it!= positions.end(); it++) {
            cout << "(" << it->first << "; " << it->second << ")" << endl;
        }
    
        system_clock::time_point end_time = system_clock::now();
    
        long long elapsed_milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - begin_time).count();
        cout << "Duration (milliseconds): "
             << elapsed_milliseconds
             << std::endl;    
    }
    

    测试此版本,使用C ++ 11功能进行更新。 使用-std=c++11测试GCC 4.9.0。 测试赛扬1.6 GHz,512 MB RAM。

    在我的电脑中的时代:
    原文: 持续时间(毫秒):12658
    第一版: 持续时间(毫秒):3616
    优化版本: 持续时间(毫秒):1745

    变化是:

  • 使用vector而不是list Benchmark和Stroustrup的单词。
  • 如果知道值不变,编译器可以使用const进行更多的优化。
  • 使用std :: pair而不是Point。
  • 对常量迭代器使用新的for-loop。
  • 资源:

    #include <iostream>
    #include <vector>
    #include <chrono>
    #include <iomanip>
    
    using namespace std;
    
    typedef std::pair<int, int> Point;
    
    #define LARGEUR_GRILLE 22
    vector<Point> positions;
    
    bool verifierNonPrise(const Point& emplacement) {
        bool nonPrise = true;
        for (const auto& p : positions) {
            if (p.first != emplacement.first) {
                if (p.second == emplacement.second) {
                    nonPrise = false;
                }
                if (abs(p.second - emplacement.second) ==
                    abs(p.first - emplacement.first)) {
                    nonPrise = false;
                }
            }
        }
    
        return nonPrise;
    }
    
    bool placerDame(int i) {
        bool bonnePosition = false;
        for (int j = 1; j <= LARGEUR_GRILLE && !bonnePosition; j++) {
            Point emplacement(i, j);
            positions.emplace_back(emplacement);
            if (verifierNonPrise(emplacement) &&
                (i == LARGEUR_GRILLE || placerDame(i + 1))) {
                bonnePosition = true;
            } else {
                positions.pop_back();
            }
        }
    
        return bonnePosition;
    }
    
    int main(int argc, char* argv[]) {
        std::chrono::system_clock::time_point begin_time =
            std::chrono::system_clock::now();
    
        positions.reserve(LARGEUR_GRILLE);
    
        placerDame(1);
        for (const auto& p : positions) {
            cout << "(" << p.first << "; " << p.second << ")" << endl;
        }
    
        std::chrono::system_clock::time_point end_time =
            std::chrono::system_clock::now();
        long long elapsed_milliseconds =
            std::chrono::duration_cast<std::chrono::milliseconds>(
                end_time - begin_time).count();
        std::cout << "Duration (milliseconds): " << elapsed_milliseconds
                  << std::endl;
    
        return 0;
    }
    

    一些更深的变化。

    变化包括:

  • 尽早回归。 一旦女王不能被放置。
  • 返回到一个更简单的Point类。
  • 使用find_if算法搜索皇后位置。
  • 来源(更新了一些建议):

    #include <algorithm>
    #include <iostream>
    #include <vector>
    #include <chrono>
    #include <iomanip>
    
    using namespace std;
    
    struct Point {
        int x, y;
    };
    
    #define LARGEUR_GRILLE 22
    vector<Point> positions;
    
    bool verifierNonPrise(const Point& emplacement) {
        return find_if(positions.cbegin(), positions.cend(), [&emplacement](const Point& p) {
                   return (p.x != emplacement.x &&
                           (p.y == emplacement.y ||
                            abs(p.y - emplacement.y) == abs(p.x - emplacement.x)));
               }) == positions.cend();
    }
    
    bool placerDame(int i) {
        for (int j = 1; j <= LARGEUR_GRILLE; j++) {
            Point emplacement{i, j};
            positions.push_back(emplacement);
            if (verifierNonPrise(emplacement) &&
                (i == LARGEUR_GRILLE || placerDame(i + 1))) {
                return true;
            } else {
                positions.pop_back();
            }
        }
        return false;
    }
    
    int main(int argc, char* argv[]) {
        std::chrono::system_clock::time_point begin_time =
            std::chrono::system_clock::now();
    
        positions.reserve(LARGEUR_GRILLE);
    
        placerDame(1);
        for (const auto& p : positions) {
            cout << "(" << p.x << "; " << p.y << ")" << endl;
        }
    
        std::chrono::system_clock::time_point end_time =
            std::chrono::system_clock::now();
        long long elapsed_milliseconds =
            std::chrono::duration_cast<std::chrono::milliseconds>(
                end_time - begin_time).count();
        std::cout << "Duration (milliseconds): " << elapsed_milliseconds
                  << std::endl;
    
        return 0;
    }
    
    链接地址: http://www.djcxy.com/p/86757.html

    上一篇: Performance issue: Java vs C++

    下一篇: One could use a profiler, but why not just halt the program?