Как сохранить многочлен?

целые числа могут использоваться для хранения отдельных чисел, но не математических выражений. Например, скажем, у меня есть выражение:

6x^2 + 5x + 3

Как я буду хранить многочлен? Я мог бы создать свой собственный объект, но я не вижу, как я могу представить полином через данные-члены. Я не хочу создавать функцию для оценки переданного аргумента, потому что мне нужно не только оценить его, но и манипулировать выражение.

является ли вектор моим единственным вариантом или есть более подходящее решение?

8 ответов


простой, но неэффективный способ-сохранить его в виде списка коэффициентов. Например, полином в вопросе будет выглядеть так:

[6, 5, 3]

если терм отсутствует, поместите ноль на его место. Например, многочлен 2x^3 - 4x + 7 будет представлено следующим образом:

[2, 0, -4, 7]

степень многочлена задается длиной списка минус один. Это представление имеет один серьезный недостаток: для разреженных многочленов список будет содержать много нулей.

более разумным представлением списка членов разреженного многочлена является список ненулевых членов, где каждый член представляет собой список, содержащий порядок члена и коэффициент для этого порядка; степень многочлена задается порядком первого члена. Например, многочлен x^100+2x^2+1 будет представлен этим списком:

[[100, 1], [2, 2], [0, 1]]

в качестве примера того, насколько полезно это представление, книга SICP строит простой, но очень эффективный система символической алгебры используя второе представление для полиномов, описанные выше.


список не единственный вариант.

вы можете использовать карту (словарь), сопоставляющую показатель с соответствующим коэффициентом.

используя карту, ваш пример будет

{2: 6, 1: 5, 0: 3}

список пар (коэффициент, показатель) вполне стандартный. Если вы знаете, что ваш многочлен плотный, то есть все позиции экспоненты являются малыми целыми числами в диапазоне от 0 до некоторого малого максимального показателя, вы можете использовать массив, как я вижу, Оскар Лопес только что опубликовал. :)


выражения можно представлять в виде деревьев выражений. См., например,деревья выражений .NET.

Это позволяет использовать гораздо более сложные выражения, чем простые многочлены, и эти выражения также могут использовать несколько переменных.

в .NET вы можете управлять деревом выражений как деревом и оценивать его как функцию.

        Expression<Func<double,double>> polynomial = x => (x * x + 2 * x - 1);
        double result = polynomial.Compile()(23.0);

объектно-ориентированный подход мог бы сказать, что многочлен-это набор Мономов, и Одночлены инкапсулирует коэффициент и Экспонента вместе.

этот подход работает, когда у вас есть полином такой:

y(x) = x^1000 + 1

подход, который связал структуру данных с полиномиальным порядком, был бы ужасно расточительным для этого патологического случая.


вам нужно запомнить две вещи:

  1. степень вашего полинома (например, "3")
  2. список, содержащий каждый коэффициент (например,"{3, 0, 2}")

в стандартном C++ "std::vector" и "std:: list" могут делать и то, и другое.


вектор / массив-очевидный выбор. В зависимости от типа выражений вы можете рассмотреть какой-то разреженный векторный тип (изготовленный на заказ, т. е. основанный на словаре или даже связанном списке, если у вас есть 2-3 ненулевых коэффициента 5x^100+x ).

в любом случае выставление через пользовательский класс/интерфейс было бы полезно, поскольку вы можете заменить реализацию позже. Вероятно, вы захотите предоставить стандартные операции ( + , -,*, equals), если планируете написать много выражений код манипуляции.


просто сохраните коэффициенты в массиве или векторе. Например, в C++, если вы используете только целочисленные коэффициенты, вы можете использовать std::vector<int>, или для действительных чисел,std::vector<double>. Затем вы просто нажимаете коэффициенты по порядку и получаете к ним доступ по переменной экспоненте.

например (снова на C++), для хранения 5*x^3 + 9*x - 2 Вы можете сделать:

   std::vector<int> poly;
   poly.push_back(-2); // x^0, acceesed with poly[0]
   poly.push_back(9);  // x^1, accessed with poly[1]
   poly.push_back(0);  // x^2, etc
   poly.push_back(5);  // x^3, etc

Если у вас есть большие, разреженные многочлены, то, возможно, вы захотите использовать карту вместо вектора. Если вы исправили размер длины, тогда вы, возможно, используете массив фиксированной длины вместо вектора.

я использовал C++ для примеров, но эта же схема может использоваться на любом языке.


вы также можете преобразовать его в обратная польская нотация:

6x^2 + 5x + 3 - > x 2 ^ 6 * x 5 * + 3 +

здесь x и числа "выталкиваются" в стек, а операции ( ^ ,*,+) берут два самых верхних значения из стека и заменяют их результатом операции. В итоге вы получаете результат в стек.

в этой форме легко вычислить произвольно сложный выражения.

это представление также близко к древовидному представлению выражений, где не-листовые узлы дерева представляют операции и функции, а листовые узлы-константы и переменные.

что хорошо в деревьях, так это то, что вы также можете легко оценивать выражения, и вы также можете делать такие вещи, как символическая дифференциация на них. Оба имеют рекурсивный характер.