Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > IT форум > Помощь студентам
Регистрация

Восстановить пароль

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 08.06.2011, 01:20   #1
Colder M
Пользователь
 
Регистрация: 28.02.2011
Сообщений: 16
По умолчанию C++. Заполнение дерева выражения.

Здравствуйте. Поставлена задача вычисления значения явно заданной функции и ее производной в заданной точке.
Описал дерево и рекурсивные функции, работающие по уже заполненному дереву. Начинал писать на C++, потом перенес в C# поэтому функции в коде не дописаны.
Код:
class ExprTree
{
public:
	string Lexeme;
	ExprTree *Root, 
			 *Left, *Right;
	ExprTree();
	void AddLeft(string);
	void AddRight(string);
	double f(double);
	double D(double);
};
ExprTree::ExprTree()
{
	Root = Left = Right = NULL;
}
void ExprTree::AddLeft(string Lexeme)
{
	Left = new ExprTree();
	Left->Root = this;

	Left->Lexeme = Lexeme;
}
void ExprTree::AddRight(string Lexeme)
{
	Right = new ExprTree();
	Right->Root = this;

	Right->Lexeme = Lexeme;
}
double ExprTree::f(double x)
{
	if (Lexeme == "+")
		return Left->f(x) + Right->f(x);
	if (Lexeme == "-")
		return Left->f(x) - Right->f(x);
	if (Lexeme == "*")
		return Left->f(x) * Right->f(x);
	if (Lexeme == "/")
		return Left->f(x) / Right->f(x);
	if (Lexeme == "ln")
		return log(Right->f(x));
	if (Lexeme == "^")
		return pow(Left->f(x), Right->f(x));
	if (Lexeme == "x")
		return x;
	return 0;
}
double ExprTree::D(double x)
{
	if(Lexeme == "+")
		return Left->D(x) + Right->D(x);
	if(Lexeme == "-")
		return Left->D(x) - Right->D(x);
	if(Lexeme == "*")
		return Left->D(x) * Right->f(x) + Right->D(x) * Left->f(x);
	if(Lexeme == "/")
		return (Left->D(x) * Right->f(x) - Right->D(x) * Left->f(x)) /
			   (Right->f(x) * Right->f(x));
	if(Lexeme == "x")
		return 1;
	return 0;
}
Собственно, возникает вопрос, как можно, имея строку-выражение (например, "x+(ln(x)+1)^2") заполнить это дерево, используя для создания узлов AddLeft(string) и AddRight(string)?
Пытался сделать через рекурсию, вызывая функцию
void Build(string expr, string key) (её наработки удалил, извините),
которая, начиная с конца, ищет первое вхождение знаков "+" и "-" и, если находит, засовывает знак в текущий узел (зависящий от ключа), а затем вызывает саму себя для подстроки слева от знака с ключом left и аналогично справа с ключом right; если же "+"/"-" в строке не встречается, то ищет "*" или "/", и т. д.; если все знаки операций исчерпываются, то, значит, достигнут лист - число или аргумент, которое добавляется слева или справа. Но тут возникает несколько трудностей, в том числе проблема с учетом скобок.
Я думаю, что существуют уже готовые алгоритмы заполнения; поделитесь ими, пожалуйста (или подскажите, как решить проблему со скобками...).
Colder M вне форума Ответить с цитированием
Старый 08.06.2011, 07:27   #2
Colder M
Пользователь
 
Регистрация: 28.02.2011
Сообщений: 16
По умолчанию

Когда-то писал парсер для комплексного калькулятора, сейчас сделал нисходящий разбор по абсолютной аналогии с ним. Работает. Кому интересно, делюсь частично кодом на C#.
Дерево:
Код:
       private class ExprTree
        {
            public string Lexeme;
            public ExprTree Root, 
                            Left, Right;

	        public ExprTree()
            {
                Root = Left = Right = null;
            }
     
	        public double f(double x)
            {
                switch (Lexeme)
                {
                    case "+":
                        return Left.f(x) + Right.f(x);
                    case "-":
                        return Left.f(x) - Right.f(x);
                    case "*":
                        return Left.f(x) * Right.f(x);
                    case "/":
                        return Left.f(x) / Right.f(x);
                    case "ln":
                        return Math.Log(Right.f(x));
                    case "^":
                        return Math.Pow(Left.f(x), Right.f(x));
                    case "x":
                        return x;
                    default:
                        return Convert.ToDouble(Lexeme);

                }
            }
	        public double D(double x)
            {
                switch (Lexeme)
                {
                    case "+":
                        return Left.D(x) + Right.D(x);
                    case "-":
                        return Left.D(x) - Right.D(x);
                    case "*":
                        return Left.D(x) * Right.f(x) + Right.D(x) * Left.f(x);
                    case "/":
                        return (Left.D(x) * Right.f(x) - Right.D(x) * Left.f(x)) /
                               (Right.f(x) * Right.f(x));
                    case "ln":
                        return Right.D(x) / Right.f(x);
                    case "^":
                        return Left.D(x) * Right.f(x) * Math.Pow(Left.f(x), Right.f(x) - 1) + 
                               Math.Log(Left.f(x)) * Right.D(x) * Math.Pow(Left.f(x), Right.f(x));
                    case "x":
                        return 1;
                    default:
                        return 0;
	            
                }
            }
        }

Последний раз редактировалось Colder M; 08.06.2011 в 08:13.
Colder M вне форума Ответить с цитированием
Старый 08.06.2011, 07:27   #3
Colder M
Пользователь
 
Регистрация: 28.02.2011
Сообщений: 16
По умолчанию

Билдер дерева:
Код:
private static class Parser
        {
            private static string Expr;
            private static int p;

            private static ExprTree Low()
            {
                ExprTree SubTree = Medium();
                while (Expr[p] == '+' || Expr[p] == '-')
                {
                    ExprTree T = new ExprTree();
                    T.Lexeme = Convert.ToString(Expr[p]);
                    T.Left = SubTree;
                    p++;
                    T.Right = Medium();
                    SubTree = T;
                }
                return SubTree;
            }
            private static ExprTree Medium()
            {
                ExprTree SubTree = High();
                while (Expr[p] == '*' || Expr[p] == '/')
                {
                    ExprTree T = new ExprTree();
                    T.Lexeme = Convert.ToString(Expr[p]);
                    T.Left = SubTree;
                    p++;
                    T.Right = High();
                    SubTree = T;
                }
                return SubTree;
            }
            private static ExprTree High()
            {
                ExprTree SubTree = Top();
                while (Expr[p] == '^')
                {
                    ExprTree T = new ExprTree();
                    T.Lexeme = Convert.ToString(Expr[p]);
                    T.Left = SubTree;
                    p++;
                    T.Right = Top();
                    SubTree = T;
                }
                return SubTree;
            }
            private static ExprTree Top()
            {
                ExprTree SubTree = new ExprTree();
                switch (Expr[p])
                {
                    case '(':
                        p++;
                        SubTree = Low();
                        p++;
                        return SubTree;
                    case 'x':
                        p++;
                        SubTree.Lexeme = "x";
                        break;
                    case 'l':
                        p += 2;
                        SubTree.Lexeme = "ln";
                        SubTree.Right = Top();
                        SubTree.Left = null;
                        break;
                    default:
                        while (char.IsDigit(Expr[p]) || Expr[p] == ',')
                        {
                            SubTree.Lexeme += Expr[p];
                            p++;
                        }
                        break;
                }
                return SubTree;
            }

            public static ExprTree BuildExprTree(string MathExpr)
            {
                Expr = MathExpr;
                p = 0;
                return Low();
            }
        }
Предполагается, что вводимая строка синтаксически верная, поэтому проверку ошибок не реализовывал.

Последний раз редактировалось Colder M; 08.06.2011 в 07:40.
Colder M вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
сохранение дерева demonara Помощь студентам 3 03.01.2011 12:35
Заполнение дерева 29AHexNumber Общие вопросы C/C++ 0 08.06.2010 10:49
Cоздание дерева математического выражения CilCatblack Общие вопросы C/C++ 3 20.04.2009 14:22
Глубина дерева Иллидан Паскаль, Turbo Pascal, PascalABC.NET 1 29.03.2008 11:36
обход дерева ribka Помощь студентам 2 11.12.2007 20:38