debugging 如何在C++中处理大输入时提高代码的性能?

ijxebb2r  于 2023-01-05  发布在  其他
关注(0)|答案(2)|浏览(162)

怎样才能使这个代码在C++中运行得更快呢?这个代码需要很多时间来运行。目的是确定需要多少个登机口来处理一个规定的到达和离开时间表。

#include <vector>

struct Airplane {
    int arrival_time_seconds;
    int departure_time_seconds;
};

class Schedule {
private:
    const std::vector<Airplane> airplanes_;

public:
    Schedule(const std::vector<Airplane>& airplanes) :
        airplanes_(airplanes) {}

    int MaximumNumberOfPlanes() const {
        int rv = 0;
        for (const Airplane& airplane : airplanes_) {
            int num_planes = NumberOfPlanes(airplane.arrival_time_seconds);
            if (num_planes > rv) {
                rv = num_planes;
            }
        }
        return rv;
    }

private:
    int NumberOfPlanes(int time_seconds) const {
        int rv = 0;
        for (const Airplane& airplane : airplanes_) {
            if (airplane.arrival_time_seconds < time_seconds &&
                    time_seconds <= airplane.departure_time_seconds) {
                rv++;
            }
        }
        return rv;
    }
};
mznpcxlj

mznpcxlj1#

该算法被写成一个O()问题,但它可以很容易地被改写成一个O(N)问题。
首先你需要按到达时间对飞机向量排序,这样向量就是一个排序序列,每次你添加一架新飞机,你都必须按顺序插入它,你甚至可以考虑用std::map作为容器。
然后你在“当前”飞机上向前走,同时保持指针指向第一架飞机,两者的差值就是你当前停靠的飞机数量。
一旦你增加了你的索引,你就检查“最后一架”飞机的起飞时间是否小于新的当前时间,如果是,你就增加。
那应该是非常快的。
或者,如果你不想保留一个有序数组,你可以建立一个单独的向量,只包含时间。

int MaximumNumberOfPlanes() const {
        std::vector< std::pair<int,int> > delta; 
        delta.reserve( 2*airplanes_.size() );
        for (const Airplane& x : airplanes_) {
            delta.push_back( {x.arrival_time_seconds,1} );
            delta.push_back( {x.departure_time_seconds,-1} );
        }
        std::sort( delta.begin(), delta.end() );
        int rv = 0;
        int np = 0;
        for ( const auto p : delta ) {
            np += p.second;
            rv = std::max(rv, np);
        }
        return rv;
    }

Godbolt链接:https://godbolt.org/z/5de9corEM

4si2a6ki

4si2a6ki2#

很多人都说这是O(N),在某种程度上是可能的,至少我能把它变成O(max(N,86400)),这比你的版本在 N〉294时要好,比O(NlogN)在 N〉6788时要好。
我假设如果一架飞机第二天起飞,它有一个departure_time_seconds = 86400(一天中的秒数),而所有arrival_time_seconds都小于86400。
你可以用O(N)编译一个飞机数量变化的向量,然后用它来计算机场中每秒钟的飞机数量,时间为O(86400):

int MaximumNumberOfPlanes2() const {
        int delta[24 * 60 * 60 + 1] = { 0 };
        for (const Airplane& x : airplanes_) {
            delta[x.arrival_time_seconds]++;
            delta[x.departure_time_seconds]--;
        }
        int rv = 0;
        int np = 0;
        for (int i = 0; i < 24 * 60 * 60; ++i) {
            np += delta[i];
            rv = std::max(rv, np);
        }
        return rv;
    }

具有一定定时的测试程序:

#include <vector>
#include <iostream>
#include <fstream>
#include <random>
#include <chrono>
#include <queue>

int main()
{
    using namespace std;
    using namespace std::chrono;

    default_random_engine eng;
    uniform_int_distribution<int> arr_dist(0, 24*60*60);
    gamma_distribution<double> dep_dist(5, 3);

    std::vector<Airplane> a;
    for (int i = 0; i < 100000; ++i) {
        int arrival = arr_dist(eng);
        int departure = arrival + (20 + lround(dep_dist(eng))) * 60;
        departure = min(departure, 24*60*60);
        a.push_back({ arrival, departure });
    }

    Schedule s(a);
    {
        const auto& start = steady_clock::now();
        int mnp = s.MaximumNumberOfPlanes();
        const auto& stop = steady_clock::now();
        duration<double> elapsed = stop - start;
        std::cout << "MaximumNumberOfPlanes : " << mnp << " - Elapsed: " << elapsed.count() << " s\n";
    }
    {
        const auto& start = steady_clock::now();
        int mnp = s.MaximumNumberOfPlanes2();
        const auto& stop = steady_clock::now();
        duration<double> elapsed = stop - start;
        std::cout << "MaximumNumberOfPlanes2: " << mnp << " - Elapsed: " << elapsed.count() << " s\n";
    }
    return 0;
}

这给出(在我的笔记本电脑上):

MaximumNumberOfPlanes : 2572 - Elapsed: 48.8979 s
MaximumNumberOfPlanes2: 2572 - Elapsed: 0.0010778 s

相关问题