Re[27]: вопрос к специалистам
От: Pavel Dvorkin Россия  
Дата: 26.02.10 07:53
Оценка:
Здравствуйте, samius, Вы писали:

S>        static bool SearchAndInsert<T>(this Node<T> tree, T value)
S>        {
S>            if (tree == null)
S>                throw new ArgumentNullException("tree");

S>            var eq = Comparer<T>.Default.Compare(tree.Value, value);
S>            if (eq == 0)
S>                return true;

S>            if(eq > 0)
S>            {
S>                if(tree.Left != null)
S>                    SearchAndInsert(tree.Left, value);
S>                else
S>                    tree.Left = new Node<T>(value, null, null);
S>            }
S>            else
S>            {
S>                if (tree.Right != null)
S>                    SearchAndInsert(tree.Right, value);
S>                else
S>                    tree.Right = new Node<T>(value, null, null);
S>            }
S>            return false;
S>        }



Боже, зачем же так сложно и длинно ? Да еще ArgumentNullException, которого тут вообще не должно быть!


    class Node<T>
    {
        public Node(T value, Node<T> left, Node<T> right)
        {
            Value = value;
            Left = left;
            Right = right;
        }
        public T Value { get; set; }
        public Node<T> Left { get; set; }
        public Node<T> Right { get; set; }

// мне пришлось заменить свойства на поля, так как свойства нельзя передавать по ref
// public их делать совсем не обязательно, но лень было возиться :-)
// так что в моем коде не используются твои Left и Right, а используются мои left и right

        public Node<T> left;
        public Node<T> right;
    }

    static class Program
    {
        static Node<T> Insert<T>(this Node<T> tree, T value)
        {
            if (tree == null)
                return new Node<T>(value, null, null);
            var eq = Comparer<T>.Default.Compare(tree.Value, value);
            if (eq == 0)
                return tree;
            return eq > 0
               ? new Node<T>(tree.Value, Insert(tree.Left, value), tree.Right)
               : new Node<T>(tree.Value, tree.Left, Insert(tree.Right, value));
        }

        static bool SearchAndInsert<T>(this Node<T> tree, T value)
        {
            if (tree == null)
                throw new ArgumentNullException("tree");

            var eq = Comparer<T>.Default.Compare(tree.Value, value);
            if (eq == 0)
                return true;

            if (eq > 0)
            {
                if (tree.Left != null)
                    SearchAndInsert(tree.Left, value);
                else
                    tree.Left = new Node<T>(value, null, null);
            }
            else
            {
                if (tree.Right != null)
                    SearchAndInsert(tree.Right, value);
                else
                    tree.Right = new Node<T>(value, null, null);
            }
            return false;
        }

// а вот и моя версия - чистая калька с С++
// DPL - это я (Дворкин Павел Лазаревич :-)
// как видишь, она ничуть не сложнее твоей LinQ-овской, скорее проще :-)

        static bool DPLSearchAndInsert<T>(ref Node<T> tree, T value)
        {
            if (tree == null)
            {
                tree = new Node<T>(value, null, null);
                return false;
            }

            var eq = Comparer<T>.Default.Compare(tree.Value, value);
            if (eq == 0)
                return true;

            if (eq > 0)
                    return DPLSearchAndInsert(ref tree.left, value);
            else
                    return DPLSearchAndInsert(ref tree.right, value);
        }


        static Node<T> BuildTree<T>(IEnumerable<T> data)
        {
            return data.Aggregate(default(Node<T>), Insert);
        }

        static Node<T> BuildTreeM<T>(IEnumerable<T> data)
        {
            var iter = data.GetEnumerator();
            if (!iter.MoveNext())
            {
                throw new ArgumentException();
            }
            var result = new Node<T>(iter.Current, null, null);
            while (iter.MoveNext())
                SearchAndInsert(result, iter.Current);
            return result;
        }
// это мои построитель

        static Node<T> DPLBuildTreeM<T>(IEnumerable<T> data)
        {
            var iter = data.GetEnumerator();
            if (!iter.MoveNext())
            {
                throw new ArgumentException();
            }
// пришлось заменить var на Node<T>, так как var нельзя присвоить null
            Node<T> result = null;
            while (iter.MoveNext())
                DPLSearchAndInsert(ref result, iter.Current);
            return result;
        }
        static void Main()
        {
            var buffer = Enumerable.Range(0, 1000000).ToArray();
            var rnd = new Random();
            for (int i = 0; i < buffer.Length; i++)
            {
                int j = rnd.Next(buffer.Length);
                var tmp = buffer[i];
                buffer[i] = buffer[j];
                buffer[j] = tmp;
            }

            Test(() => BuildTree(buffer), "Immutable insert");
            Test(() => BuildTreeM(buffer), "SearchAndReplace");
            Test(() => DPLBuildTreeM(buffer), "DPLSearchAndReplace");

            Console.ReadKey();
        }

        static void Test(Action action, string name)
        {
            Console.WriteLine();
            Console.WriteLine(name);
            var sw = Stopwatch.StartNew();
            action();
            Console.WriteLine(sw.Elapsed);
        }
    }




S>При том что иммутабельное заполнение дерева в 3 и более раз короче, оно во столько же раз проигрывает по производительности императивному на миллионе вставок.



Immutable insert
00:00:09.9648256

SearchAndReplace
00:00:03.2450794

DPLSearchAndReplace
00:00:02.8752006


S>Можно сказать паритет


Нет, 2.5:0.5 в мою пользу. Я сделал эту DPLSearchAndInsert столь же простой, как твоя, и даже проще, а выигрыш по времени в 3 раза и ни одного лишнего new. Так что я выиграл и по памяти, и по времени, а вот по простоте кода — в лучшем случае паритет

P.S. А вот машина у тебя получше раза в 2. Если не секрет, какой процессор ? У меня Athlon Dual 4200+
With best regards
Pavel Dvorkin
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.