Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   [Алгоритмы] Как построить дерево? (http://www.flasher.ru/forum/showthread.php?t=210623)

OlmerDale 10.04.2015 20:54

Как построить дерево?
 
Вложений: 1
До этого никогда не работал с деревьями и четыре дня пытался сделать по найденным алгоритмам, но все они не отвечали тем требованиям, которые я к ним предъявлял. Но сегодня я нашел изображение, которое меня полностью устроило, но как построить подобное, я даже в уме не представляю.
По этому, если кто-то делал подобное, то объясните на словах , как рассчитать подобное дерево.
И если Вы знаете и хотите мне помочь, то у меня ещё одна к Вам просьба - помните что я до этого с деревьями не работал и что нуждаюсь в подробном объяснении.

И ещё вопрос по теме - у деревьев бывает ширина и высота и если да, то что это?

GBee 11.04.2015 00:07

Про рекурсию и обходы дерева тоже не знаете?

OlmerDale 11.04.2015 00:32

Цитата:

Про рекурсию и обходы дерева тоже не знаете?
Смотря о чем Вы. Обойти рекурсивно дерево для меня не проблема. Но я слышал о деревьях ( не знаю как они называются ) где есть ссылки право, лева, низ, верх.. Вот у меня не такое дерево, а просто ноды которые на нативный Sprite похожи.
Так вот количество детей считать - могу! Получалось пирамидками детей выстраивать при помощи рекурсии, но как уже сказал ранее, меня получившееся представление не устроило и я пошел дальше.
Так что можно с натяжкой сказать, что минимум манипуляций в рекурсии я умею.

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

Вот... Жду помощи.

Wolsh 11.04.2015 00:37

Ничего не понял из вопроса.
Что Вы имеете в виду, говоря "рассчитать дерево"?
Что такое "алгоритмы" в данном контексте? Что они делают?
Что именно представляют из себя "те требования, которые я к ним предъявлял"?

Дерево оно и есть дерево. Каждый узел имеет ссылку на parent — родительский узел, и массив ссылок на children — узлы детей, для которых он в свою очередь parent.
Вариантом может быть дополнительная классификация узла как "лист", то есть не имеющий детей, конечный узел. То есть можно создать класс Leaf, имеющий ссылку только на parent, и расширяющий его класс Node, имеющий так же массив ссылок на детей и методы для работы с ними (добавление/удаление, сортировка, подсчет количества, поиск по свойствам).

Добавлено через 1 минуту
Цитата:

я не могу подобрать алгоритм, который бы выстраивал ноды в такой последовательности.
В смысле "сортировал по алфавиту" что ли?

GBee 11.04.2015 00:40

Вправо влево это бинарное. Вверх вниз, это не слышал, какое-то двунаправленное что-ли. Ваше дерево отлично подходит, смысл в том чтобы начать рисовать его от самых листочков и потом вернуться к корню, который нарисуется в конце. Сейчас напишу алгоритм, только поем.

OlmerDale 11.04.2015 00:54

Цитата:

Что Вы имеете в виду, говоря "рассчитать дерево"?
Грамотней, наверное, сказать - построить представление на основе данных дерева, отображающее строение этого дерева.
Цитата:

Что такое "алгоритмы" в данном контексте? Что они делают?
В данном контексте я ищу повторяющиеся действия, которые помогут нарисовать данное отображение.
Я не понимаю какие данные нужно собрать чтобы построить отображение. Да и вообще не могу понять с какой стороны подойти к началу сбора данных.
Цитата:

Что именно представляют из себя "те требования, которые я к ним предъявлял"?
Только сейчас дошло, что у меня наверное просто не получалось. Ведь как отображение не крути,
а ведь все равно только так, как в данном примере и можно отобразить.

olexandr 11.04.2015 01:04

http://www.flasher.ru/forum/showthread.php?t=210591

OlmerDale 11.04.2015 01:39

Еще, только сейчас понял, что я неправильно работаю с деревьями, вообще не умею.
Чтобы найти расположение чилда, нужно знать длину его чилдов ( если они есть ) и следовательно его и его чилдов. По этому я подошел неправильно и сделал деспатч изменения длины вверх по дереву:) Но это все равно мне не помогло.
Да и нарисовать с конца тоже не могу, не могу даже представить как узнать координаты зная только.. Я даже не знаю, что нужно знать. А когда смотрю ещё и на картинку, особенно на увеличенную, то вообще не понимаю, почу в один раз нода без детей в центре между двумя с детьми, а в другой раз, если нет боковой с детьми, прижимается дефолтное расстояние..

Добавлено через 14 минут
olexandr, как я написал в той теме, я отказался от этой библиотеки из-за устаревшего демо и невозможности посмотреть исходники, так как библиотека написана на haxe, на который я сейчас смотрю, как когда-то, да и сейчас, на php с его -> вместо точки. Неделю я не могу понять как так нарисовать, зато вдоволь с рекурсией наигрался.

Добавлено через 32 минуты
И если предположить, что у библиотеки по ссылке только один режим расстановки ДО,
то он рано или поздно приведет к наложению узлов друг на друга. У меня в примере, хоть
и может показаться что идентичная расстановка, но она не такая. У меня на картинке соседние
узлы раздвигаются если у них чилды перекрывают друг друга, а у polygonal нет.

GBee 11.04.2015 03:20

Вложений: 1
Я потыркался, вроде и получается, но есть исключения и мне их уже лень думать сегодня. Если хоть как-то
приблизит вас к решению, буду рад. Справа кнопка рефреша. Комменты напишу и баги поправлю потом, если будет нужда. Общая идея - уходим до листиков, рисуем их, потом по усредненному Y рисуем их веточку, веточки дают среднюю Y для ветки их и так далее. Но гд-то явно прогибы есть, голова уже не варит, но задача прикольная.

tree2.swf   (1.9 Кб)



Код AS3:

package 
{
        import flash.display.Graphics;
        import flash.display.Sprite;
        import flash.events.MouseEvent;
        import flash.geom.Point;
 
        /**
        * ...
        * @author gbee
        */

        public class TreeTest extends Sprite
        {
                private static const VGAP:int = 15;
                private static const HGAP:int = 50;
                private var _levelsOffset:Array;
 
                private var _g:Graphics;
                public function TreeTest()
                {
                        super();
 
                        var spr:Sprite = new Sprite();
                        spr.graphics.beginFill(0, 0.4);
                        spr.graphics.drawRect(800, 0, 100, 40);
                        spr.addEventListener(MouseEvent.CLICK, refresh);
                        addChild(spr);
                        refresh();
                }
 
                private function refresh(event:MouseEvent = null):void
                {
                        _g = graphics;
                        _g.clear();
                        _g.beginFill(0x008800);
                        _g.lineStyle(1, 0x004400);
                        _levelsOffset = [0, 0, 0, 0, 0, 0, 0, 0, 0];
                        drawTree(generateTree(5, 3), 0);
                }
 
                private function generateTree(maxChilds:int, level:int):TreeNode
                {
                        var childsCount:int = int(Math.random() * maxChilds);
                        var node:TreeNode = new TreeNode();
                        if (level == 0)
                                return node;
                        for (var i:int = 0; i < childsCount; i++)
                                node.children.push(generateTree(maxChilds, level - 1));
                        node.count = childsCount;
                        return node;
                }
 
 
                private function drawTree(node:TreeNode, level:int):Number
                {
                        var levelY:Number = 0;
                        if (node.count)
                        {
                                var linesY:Array = []; //массив Y для рисования связей.
                                for each(var child:TreeNode in node.children)
                                {
                                        var cY:Number = drawTree(child, level + 1);
                                        levelY += cY;
                                        linesY.push(cY);
                                }
                                _levelsOffset[level + 1] += VGAP;
 
                                levelY = levelY / node.count;
 
                                if(levelY - _levelsOffset[level] >= VGAP)
                                        _levelsOffset[level] = levelY;
                                else
                                {
                                        _levelsOffset[level] += VGAP;
                                        levelY = _levelsOffset[level];
                                }
 
                                //Рисуем связи
                                for each(cY in linesY)
                                {
                                        _g.moveTo(HGAP * level, levelY);
                                        _g.lineTo(HGAP * (level + 1), cY);
                                }
                        }
                        else
                        {
                                levelY = _levelsOffset[level];
                                _levelsOffset[level] += VGAP;
                                //Запрещаем рисовать ноды чужих детей выше себя. Но тут надо подумать в примере не запрещено.
                                if(_levelsOffset[level + 1] < _levelsOffset[level])
                                        _levelsOffset[level + 1] = _levelsOffset[level];
                        }
 
                        //Рисуем ноду
                        _g.drawCircle(HGAP * level, levelY, 5);
                        return levelY;
                }
 
 
        }
 
}

Код AS3:

package 
{
        /**
        * ...
        * @author gbee
        */

        public class TreeNode
        {
                public var children:Array = [];
                public var count:int = 0;
                public function TreeNode()
                {
 
                }
 
        }
 
}


OlmerDale 11.04.2015 21:00

GBee спасибо боьшое! Сегодня некому было меня разбудить, по этому проснулся в четыре часа с квадратной головой. Сейчас уже переписал под себя и приступлю чуть попозже к "подгонке".

garymar 11.04.2015 22:16

Почитай про паттерн Компоновщик (Composite). Хотя я до сих пор не въеха в суть, что ты в итоге хочешь. Никакой конкретики.

ZackMercury 12.04.2015 01:06

garymar, ТС хочет увидеть дерево визуально.

Nooob 12.04.2015 04:31

для обхода дерева лучше всего подходит паттерн Visitor

garymar 12.04.2015 21:23

Цитата:

Сообщение от Nooob (Сообщение 1181218)
для обхода дерева лучше всего подходит паттерн Visitor

Посетитель сюда не совсем подойдет. Это поведенческий паттерн. В Компоновщике (структурный паттерн) никто не запрещает реализовать в каждом элементе дерева (и ветках и листьях) метод использующий технику рекурсивного обхода дерева.

OlmerDale 12.04.2015 21:40

Nooob, а можете привести минимальный пример, а то очень интересно.

garymar, да я понимаю что тут композиция нужна для нод, но сложность не в
создании нод, а в идентичном построении.

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

garymar 13.04.2015 01:55

Цитата:

Сообщение от OlmerDale (Сообщение 1181248)
garymar, да я понимаю что тут композиция нужна для нод, но сложность не в
создании нод, а в идентичном построении.

Если ты тупо хочешь повторить дерево на картинке из твоего первого сообщения (насколько я правильно понял), то тебе нужно изначально представлять дерево в каком-то формате, затем его парсить и выводить как граф. По словами "изначально представлять дерево" я хотел сказать, что тебе нужно задать исходные данные. Ну вот например JSON или XML или HTML, я хз... Если я правильно тебя понял.

Вот пример из JSON дерева на твоей картинке:

Код AS3:

{
    "root": {
        "branch_1": {
            "leaf_1": "Hello world"
        },
        "leaf_1": "Hello world",
        "leaf_2": "Hello world",
        "branch_2": {
            "leaf_1": "Hello world",
            "leaf_2": "Hello world",
            "leaf_3": "Hello world",
            "leaf_4": "Hello world",
            "leaf_5": "Hello world"
        },
        "branch_3": {
            "leaf_1": "Hello world",
            "leaf_2": "Hello world",
            "leaf_3": "Hello world",
            "leaf_4": "Hello world",
            "leaf_5": "Hello world",
            "leaf_6": "Hello world"
        },
        "leaf_3": "Hello world"
    }
}

Или вот XML:

Код AS3:

<root>
    <branch>
        <leaf/>
    </branch>
    <leaf/>
    <leaf/>
    <branch>
        <leaf/>
        <leaf/>
        <leaf/>
        <leaf/>
        <leaf/>
    </branch>
    <branch>
        <leaf/>
        <leaf/>
        <leaf/>
        <leaf/>
        <leaf/>
        <leaf/>
    </branch>
    <leaf/>
</root>

Вот тебе диаграмма классов http://prntscr.com/6t0gnr

Wolsh 14.04.2015 21:30

Алгоритмы построения поуровневого изображения деревьев

OlmerDale 15.04.2015 01:11

Wolsh спасибо за ссылку и сорри за первые комменты.
Расписано вполне доступно, а главное русским языком написано что - за один проход не получится и хватит пытаться :) Конечно есть небольшие разности, но если что, то можно и третий проход сделать..

dimarik 16.04.2015 00:02

OlmerDale, деревья очень хитрая штука. С ними нужно аккуратно, а то заведут в лес.
Вот, скажем, garymar не знает, что такое рекурсия и демонстрирует свои слабые знания в открытую:

Цитата:

Сообщение от garymar (Сообщение 1181247)
В ... Компоновщике (структурный паттерн) никто не запрещает реализовать в каждом элементе дерева (и ветках и листьях) метод использующий технику рекурсивного обхода дерева.

На дереве рекурсия немного не подпадает под определение:
Цитата:

В программировании рекурсия — вызов функции (процедуры) из неё же самой
Я сам пару лет понемногу занимаюсь деревьями. В контексте их эффективного рендеринга в Stage3D. Многое переосмыслил.

Цитата:

Сообщение от Wolsh (Сообщение 1181311)

Сходил по ссылке, сразу напрягло
Цитата:

В 1979 году C. Wetherell и A. Shannon представили алгоритм линейной сложности для рисования бинарных деревьев
И тут же на рисунках показывают небинарное дерево. Бинарное тут.
Цитата:

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

Wolsh 16.04.2015 01:00

Цитата:

И тут же на рисунках показывают небинарное дерево.
Но, если прочитать не только первое предложение, а и то, которое собственно предшествует рисунку, то получится
Цитата:

В 1990 году Walker обобщил алгоритм Рейнгольда-Тилфорда, предложив алгоритм построения поуровневого изображения упорядоченных деревьев произвольной степени.
Бинарное же дерево рассматривается в соответствующей главе.

dimarik 16.04.2015 01:28

Wolsh, нет, не надо папу путать. Указания на рисунки в контексте бинарных деревьев
Цитата:

Изоморфизм: каждая пара изоморфных поддеревьев рисуется идентично с точностью до переноса. То есть изображение каждого поддерева не зависит от расположения этого поддерева внутри всего дерева. На Рис. 4.1(а) показан пример изображения дерева с нарущением принципа изоморфизма. Поддеревья с корнем 2 и корнем 7 имеют разные изображения, хотя они и изоморфны. На Рис. 4.1(б) оба поддерева имеют идентичное изображение.
Симметричность: Изображение дерева с инвертированным порядком всех сыновей можно получить, зеркально отразив изображение исходного дерева. На Рис. 4.1(с) показано нарушение принципа симметрии, произошедшее из-за несимметричного размещения вершины 6, а на Рис. 4.1(д) изображение дерева симметрично.
идут до этой замечательной фразы, которую ты привёл.

Я знаю, что я зануда. Но автор статьи не удосужился, и я делаю вывод, что статья чуть менее, чем негодная.

garymar 16.04.2015 02:43

Цитата:

Сообщение от dimarik (Сообщение 1181349)
Вот, скажем, garymar не знает, что такое рекурсия и демонстрирует свои слабые знания в открытую:

Это твоя невнимательность, вот и все) Ты же не до конца всё просмотрел, наверняка так и было. Или я хз... Из твоих сообщений абсолютно всё - критика, и одно предложение - хвастовство... (Воспитан в TimeZero?) Ничего конструктивного не написал, так лишь бы считалось...))

Да собственно как и все сообщения на форуме как я погляжу.

gloomyBrain 16.04.2015 20:59

Цитата:

Сообщение от dimarik (Сообщение 1181349)
На дереве рекурсия немного не подпадает под определение

Я хотел написать гневный комментарий, но мне стало лень =) Ерунда это, короче. И в особенности ерунда применительно к рисованию деревьев по данным. Использование рекурсии подходит как нельзя лучше для этой задачи.
Имеем данные, представленные деревом. Все дерево можно построить из, например, вот таких объектов:
Код AS3:

public class Node
{
    // массив детей, которые могут иметь своих детей и т.д.
    // может быть пустым
    public var children:Vector.<Node>;
 
    // данные, которые мы хотим хранить в узле дерева
    // может быть null
    public var info:String;
 
    public function Node(info:String = null)
    {
        this.children = new Vector.<Node>();
        this.info = info;
    }
}

В коде можем теперь делать вот такие штуки:
Код AS3:

var parent:Node = new Node("I'm a parent!");
var child:Node = new Node("I'
m a child!");
 
parent.children.push(child);

Замечательно, теперь наша структура может стать похожей на то что было у автора поста.

Теперь попробуем рисовать что-то по этим данным. Для начала сделаем класс для отображения одного узла:
Код AS3:

public class NodeView extends Sprite
{
    private var _data:Node;
    private var _textView:TextField;
 
    public function NodeView(data:Node)
    {
        super();
 
        _data = data;
 
        this.draw();
    }
 
    // тут мы рисуем что-то, что отображает наши данные
    // так как в наши данные входит текст, то рисуем текстовое поле
    // а раз уж у нас есть еще и дети - сразу создаем отображения детей
    // "по образу и подобию" =)
    private function draw():void
    {
        _textView = new TextField();
        _textView.text = _data.info;
 
        for each (var childData:Node in _data.children)
        {
            var childView:NodeView = new NodeView(childData);
 
            // выравниваем детишек друг относительно друга
            childView.x = ...;
            childView.y = ...;
 
            // и добавляем в список отображения
            super.addChild(childView);
        }
    }
}

На выходе будем иметь экземпляр NodeView, у которого есть ширина и высота. При чем ширина и высота NodeView определяются их размеров текстового поля с информацией и размерами и положением его детей. А размеры детей определяются размерами их детей. И так далее вниз по каждой ветке дерева.

dimarik 16.04.2015 21:43

В упор не вижу рекурсии. Я только за нее и говорил. Никаких других конструктивных предложений я не желал предложить.

OlmerDale 18.04.2015 22:06

Прошла неделя а я так и не смог сделать. Это я говорю не к тому чтобы попросить помочь, а к тому,
что очень хочется назвать того кто писал эту статью - анти-ученым.
Цитата:

Рассмотрим теперь вопрос о том, как реализовать за время O(n) шаг 1. В силу требования об идентичности изображения изоморфных поддеревьев , изображение каждого поддерева не должно зависеть от его положения в объемлющем дереве. Значит, для сравнения координат вершин поддеревьев T' и T'' достаточно рассматривать только координаты вершин, принадлежащих «границе» каждого поддерева. То есть, на каждом уровне можно сравнивать только x-координату самой правой вершины левого поддерева с x-координатой самой левой вершины правого поддерева. Для реализации этой идеи, введем понятие правого и левого контура поддерева.
У меня уже отторжение статьи идет и я не понимаю что написано в первом предложении, цитируемого отрывка. Тут автор хочет реализовать O(n)? Шаг? Или Шаг 1, которого нет.. Или все же шаг, а после пишет пункт 1, когда второго пункта не существует..
И так вся статья. Её писал безумный ...

Добавлено через 3 минуты
Если бы меня за деньги попросили написать статью о том что я знаю так чтобы никто не смог понять о чем это, то у меня бы, как у автора этой статьи не получилось. Я впервые за несколько лет встречаю то, что так убого написано и впервые столкнулся с тем, что не могу так долго сделать.

Simplifier 20.04.2015 01:33

OMG, OlmerDale.

В алгоритме 2 шага:
1. Обход дерева Т в обратном порядке
2. Обход в прямом порядке

Реализация описывается не с первого шага, а со второго.
Затем, в процитированном вами фрагменте, рассматривается вопрос, как реализовать первый шаг за время O(n)

Статьи довольно краткие, сильно материал не разжевывают, поэтому явно подразумевается, что читатель уже имеет базовые знания по теории алгоритмов. И, например, знает, что такое оценка сложности: https://ru.wikipedia.org/wiki/Вычислительная_сложность
http://cybern.ru/asimtotic-oboz.html
А не начинает нападать на автора, увидев незнакомые обозначения.

OlmerDale 25.04.2015 23:53

Код AS3:

А не начинает нападать на автора, увидев незнакомые обозначения.

Это не нападок, а внутренний вопрос - почему если уж делаешь не сделать на пять с плюсом.

А как итог, прошла ещё неделя, правда по времени что я отводил на это, ушло не больше полутора дней, а итоги все те же. То есть неделя ушла на то, чтобы понять, что алгоритм данный алгоритм просто не способен сделать желаемое и что получить желаемое можно, но не менее чем тремя рекурсиями.
Надеюсь, что в начале следующей недели сделаю и покажу.

Добавлено через 1 минуту
Поймал себя на мысли, что свой многоэтажный дом я стал воспринимать как дерево :D


Часовой пояс GMT +4, время: 14:05.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.