Мое решение теперь выглядит так:
MATCH (start:LABEL)
WHERE id(start)= {}
MATCH (end:LABEL)
WHERE id(end) = {}
MATCH path=shortestPath((start)<-[:PATH*]-(end))
RETURN DISTINCT start
Это немного быстрее для меня.
Известная кавычка приходит на ум:
"Мы должны забыть о маленькой эффективности, сказать приблизительно 97% времени: преждевременная оптимизация является корнем всего зла". (Knuth, Donald. Структурное программирование с движением к Операторам, Журнал ACM, Вычисляя Обзоры, Vol 6, № 4, декабрь 1974. p.268.)
Но возможно Вы не должны передавать большие структуры данных значением так или иначе... :-)
Править: И, возможно, также избегайте O (N^2) или более сложные алгоритмы...
Я соглашаюсь с советом относительно преждевременной оптимизации. Однако существует несколько инструкций, за которыми мне нравится следовать во время дизайна, потому что их может быть трудно оптимизировать позже:
new
в течение времени выполнения.Безотносительно действия Вы берете, чтобы сохранить несколько циклов, помнить это: не пытайтесь быть более умными, чем компилятор - мера для проверки усиления.
"преждевременная оптимизация является корнем всего зла" (Knuth, Donald)
Это действительно зависит от типа кода, который Вы пишете, и это - типичное использование.
не решая точную проблему, некоторый совет:
всегда кодируйте для интерфейсов (когда дело доходит до алгоритмов) так, чтобы можно было гладко заменить их эффективным один (любыми средствами req).
Из одной из книг C++ я относился (Эффективные Методы производительности C++ Bulka и Mayhew), который явно говорил об аспектах производительности C++. Один из них был;
при определении конструкторов.. инициализируйте других конструкторов также; некоторая вещь как;
class x {
x::x(char *str):m_x(str) {} // and not as x::x(char *str) { m_str(str); }
private:
std::string m_x;
};
Вышеупомянутое является некоторой вещью, которая привлекла мое внимание и помогла мне улучшить свой стиль кодирования... эта книга имеет больше для совместного использования по этой интересной теме производительности.
В основном Ваше самое большое увеличение производительности должно иметься алгоритмическими улучшениями. Это означает использовать самые эффективные алгоритмы и, в свою очередь, самые эффективные контейнеры для элементов данных.
Иногда трудно знать, каковы лучшие компромиссы, но к счастью у разработчиков STL был точно этот вариант использования в памяти, и следовательно контейнеры STL достаточно обычно гибки, чтобы позволить контейнерам быть смешанными и подобранными в соответствии с требованиями приложения.
Чтобы полностью понять преимущество однако, необходимо удостовериться, чтобы Вы не выставляли внутреннее проектное решение как часть интерфейса Вашего class/module/whatever. Ни один из Ваших клиентов не должен зависеть от Вашего использования a std::vector
. По крайней мере обеспечьте определение типа, которое они (и Вы) могут использовать, который должен позволить вектору быть измененным на список (или безотносительно) в зависимости от Ваших потребностей.
Так же удостоверьтесь, что у Вас есть самый широкий выбор отлаженных алгоритмов и контейнеров в Вашем распоряжении. Повышение и/или TR1 являются prettymuch предметами первой необходимости в эти дни.
Не используйте чрезвычайно неэффективные алгоритмы, включайте оптимизацию в Вашем компиляторе, ничего не оптимизируйте, если профилировщик не показывает его, чтобы быть узким местом, и когда Вы пытаетесь улучшить вещи тест, чтобы видеть, делали ли Вы хорошее или плохо. Помните также, что библиотечные функции обычно оптимизировались людьми лучше в нем, чем Вы.
В значительной степени все остальное незначительно, по сравнению с ними.
одно простое предложение состоит в том, чтобы выработать привычку выполнения ++ я, а не я ++. я ++ делаю копию, и это может быть дорого.
Вот некоторые:
Эффективно Встраивание рычагов (в зависимости от Вашей платформы).
Избегайте использования временных файлов как можно больше (и знайте то, что они),
x = y + z;
Был бы лучше оптимизирован, если записано как:
x=y;
x + = z;
Кроме того, избегайте виртуальных функций и только создайте объекты, когда необходимо будет использовать их.
Если Вы находитесь в настроении, проверяете Эффективный C++. У меня есть копия дома от спины, когда я был в школе.
Две из лучших подсказок для C++:
Купите эффективный C++ Scott Meyers.
Затем купите Более эффективный C++ Scott Meyers.
Всегда пытайтесь думать о том, как Ваша память смотрит - например, массив является последовательной строкой памяти размера numOfObjects X sizeof(object)
. двумерная матрица является n X m X sizeof(object)
и каждый объект находится в индексе n + m X n и так
for(int i = 0 ; i < n ; i++){
for(int j = 0 ; j < m ; j++){
arr[i,j] = f();
намного лучше затем (на единственном процессе):
for(int i = 0 ; i < n ; i++){
for(int j = 0 ; j < m ; j++){
arr[j,i] = f();
Поскольку массив принесен в кэш в последовательных блоках, 1-й отрывок работает на всех ячейках, которые находятся в кэше прежде, чем выбрать остальных, в то время как 2-й отрывок должен был бы выбрать новые элементы массива в ячейки много раз
Когда Ваше приложение начинает замедлять сравнительный тест выполнения использования для нахождения точного узкого места даже простым GetTickCount
вызовы могут использоваться для определения времени, которое это берет компоненты для выполнения. На большем использовании проектов надлежащий профилировщик, прежде чем Вы начнете оптимизировать так Вас, потратит большую часть усилия по оптимизации, где оно имеет значение.
Викиучебник имеет некоторые вещи.
Хорошая вещь сделать, знают эффективность того, что Вы используете. Как быстрое дополнение к умножению, как быстро вектор сравнивается с нормальным массивом или к более высоким масштабам, как определенные алгоритмы выдерживают сравнение. Это позволяет Вам выбирать самый эффективный инструмент для задачи
Сохраните свой код максимально чистым. Компиляторы ЧУДЕСНЫ в наше время. Затем если у Вас действительно есть проблема перфекта, профиль.
Все это после имеет выбранный лучшие алгоритмы, доступные для Вашей проблемы.
Другая точка: самый быстрый код является кодом, который не существует. Что означает, чем более устойчив и полная функция Ваш проект должен быть, тем медленнее это будет. Нижняя строка: Пропустите пух, когда это возможно, при проверке, что Вы все еще отвечаете требованиям.
Лучшая вещь, которую можно сделать до движений производительности, состоит в том, чтобы запуститься с надежной архитектуры и модели потоков. Все остальное будет основано на этом, поэтому если Ваша основа будет вшивой, то Ваше готовое изделие только будет так хорошо. Профилирование происходит немного позже, и еще позже, чем тот прибывшая микрооптимизация (в целом, они незначительны, и усложняют код больше, чем что-нибудь.)
Мораль истории: Запустите с эффективной основы, создайте к тому же осведомленный о не выполнении чего-то совершенно глупого и медленного, и необходимо быть в порядке.
Используйте существующий, рассмотренный код, это использовалось и снова использовалось. (Пример: STL, повысьте по сравнению с прокруткой Ваших собственных контейнеров и алгоритмов),
Обновление из-за комментариев: ПРАВИЛЬНО используйте существующий, рассмотренный код, это использовалось и снова использовалось.
Не потрудитесь оптимизировать, пока это не будет необходимо. Узнать, необходимо ли это, профиль. Не угадывайте; имейте доказательство.
Кроме того, алгоритмическая оптимизация обычно оказывает большее влияние, чем микро. Используя A-звезду вместо новаторской грубой силы будет быстрее, точно так же, как как круги Bresenham лучше, чем использование sin/cos. Существуют исключения к ним, конечно, но они очень (очень) редки (<0,1%). Если у Вас есть хороший дизайн, изменение алгоритма изменяет только один модуль в Вашем коде. Легкий.
if
или switch
вместо вызовов через указатели функции. Разъяснение: void doit(int m) { switch(m) { case 1: f1(); break; case 2: f2(); break; } }
вместо void doit(void(*m)()) { m(); }
может встроить вызовы.++t
вместо t++
const
рано, часто. Самый важный для улучшения удобочитаемости.new
к минимуму. Всегда предпочитайте автоматические переменные (на стеке), если это возможно,T t[N] = { };
если Вы хотите нули.operator()
перегруженный). Они встраивают лучше, чем вызовы через указатели функции.std::vector
или std::string
если у Вас есть фиксированное размерное количество, не растущее. Использовать boost::array<T, Size>
или явный массив и использование это правильно.И действительно, я почти забыл это:
Преждевременная оптимизация является корнем всего зла
Кто-то упомянул указатели функции (и почему необходимо скорее использовать if
). Ну, еще лучше: используйте функторы вместо этого, они встраиваются, и обычно имейте нуль наверху. Функтор является структурой (или класс, но обычно первый) тот оператор перегрузок ()
и экземпляры которого могут использоваться точно так же, как обычная функция:
template <typename T>
struct add {
operator T ()(T const& a, T const& b) const { return a + b; }
};
int result = add<int>()(1, 2);
Они могут использоваться почти в каждом контексте, где обычная функция или указатель функции могли использоваться. Они обычно происходят из также std::unary_function
или std::binary_function
но это часто не необходимо (и на самом деле только сделанный для наследования некоторых полезных typedef
s).
ОТРЕДАКТИРУЙТЕ явное <int>
квалификация типа необходима в вышеупомянутом коде. Вывод типа только работает на вызовы функции, не, например, создание. Однако это может часто опускаться путем использования a make
функция помощника. Это сделано в STL для pair
s:
template <typename T1, typename T2>
pair<T1, T2> make_pair(T1 const& first, T2 const& second) {
return pair<T1, T2>(first, second);
}
// Implied types:
pair<int, float> pif = make_pair(1, 1.0f);
Кто-то упомянул в комментариях, что функторы иногда называют “functionoids”. Yesish – но не совсем. На самом деле “функтор” является (несколько странным) сокращением для “функционального объекта”. functionoid концептуально подобен, но понят путем использования виртуальных функций (хотя они иногда используются синонимично). Например, functionoid мог быть похожим на это (наряду с его необходимым интерфейсным определением):
template <typename T, typename R>
struct UnaryFunctionoid {
virtual R invoke(T const& value) const = 0;
};
struct IsEvenFunction : UnaryFunctionoid<int, bool> {
bool invoke(int const& value) const { return value % 2 == 0; }
};
// call it, somewhat clumsily:
UnaryFunctionoid const& f = IsEvenFunction();
f.invoke(4); // true
Конечно, это теряет любое преимущество производительности, которое функтор имеет из-за его вызова виртуальной функции. Это поэтому используется в другом контексте, который на самом деле требует полиморфной функции времени выполнения (с сохранением информации).
FAQ C++ имеет больше для высказывания относительно этого предмета.
Подсказка по производительности числа № 1 должна представить Ваш код рано и часто. Существует много общих, "не делают этого" подсказки, но действительно трудно гарантировать, что это повлияет на производительность Вашего приложения. Почему? Каждое приложение отличается. Легко сказать, что передача вектора значением плоха, если у Вас есть много элементов, но Ваша программа даже использует вектор (Вы, вероятно, должны, но...)?
Профилирование является единственным способом понять производительность Вашего приложения. Я был в слишком многих ситуациях, где люди "оптимизировали" код, но никогда не представляли. "Оптимизация", оказалось, представляла много ошибок и даже не была горячей точкой в пути выполнения кода. Пустая трата everyones времени.
Править:
Несколько человек прокомментировали "раннюю" часть моего ответа. Я не думаю, что необходимо быть профильными со дня 1. Однако Вы не должны также ожидать до 1 месяца от поставки также.
Я обычно первый профиль, после того как у меня есть несколько категоричные вплотную сценарии, или в большем проекте, главным образом функциональном компоненте. Я занимаю день или два (обычно работающий с QA), чтобы собраться некоторые большие сценарии и бросить его в код. Это - проверка отличного места для нахождения очевидных проблем производительности рано. Фиксация их в этой точке немного легче.
На типичном проекте я нахожу, что у меня есть код, встречающий это criterias 30%-40% пути через проект (100%, находящихся в клиентских руках). Я свободно классифицирую на этот раз как рано.
Используя универсальные алгоритмы большая подсказка по оптимизации - не с точки зрения времени выполнения, а кодирования времени. Знание, что можно отсортировать (запускаются, конец) и ожидает диапазон - быть им, два указателя или итераторы к базе данных - будут отсортированы (и кроме того, используемый алгоритм будет временем выполнения, эффективным также). Универсальное программирование - то, что делает C++ уникальным и мощным, и необходимо всегда иметь в виду его. Вам не придется записать много алгоритмов, потому что версии уже существуют (и вероятны как быстро или быстрее, чем что-нибудь, что Вы записали бы). Если у Вас есть другие соображения, то можно специализировать алгоритмы.
Select best performing algorithms, use less memory, use less branching, use fast operations, use small number of iterations.