Microsoft MVP성태의 닷넷 이야기
.NET Framework: 564. C# - DGML로 바이너리 트리 출력하는 방법 [링크 복사], [링크+제목 복사],
조회: 22252
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일

C# - DGML로 바이너리 트리 출력하는 방법

지난번 글에서 2진 트리를 화면으로 출력하는 방법에 대해 알아봤는데요.

디버깅 용도로 이진 트리의 내용을 출력하는 방법
; https://www.sysnet.pe.kr/2/0/10922

아쉬운 것이 DGML로 출력했을 때의 그래프가 별로라는 점입니다. 그러니까,,, 대충 다음과 같은 식으로 나오는데요.

dgml_bintree_1.png

다행히 DGML에 Bounds라는 속성을 통해 위치 지정을 할 수 있게 되어 있습니다. 그래서, 소스 코드를 다음과 같이 수정해 주었고,

using System;
using System.IO;
using System.Text;

class Program
{
    static void Main(string[] args)
    {
        {
            ContainerOnTree ct = new ContainerOnTree();

            ct.Add(30);
            ct.Add(20);
            ct.Add(40);
            ct.Add(10);
            ct.Add(25);
            ct.Add(23);
            ct.Add(35);
            ct.Add(32);
            ct.Add(37);
            ct.Add(50);
            ct.Add(58);
            ct.Add(5);
            ct.Add(3);
            ct.Add(7);
            ct.Add(15);
            ct.Add(28);
            ct.Add(41);

            File.WriteAllText("test.dgml", ct.ToDGML());
        }
    }
}

public class ContainerOnTree
{
    Node _root = null;
    public Node Root { get { return _root; } }

    public class Node
    {
        public Node Left;
        public Node Right;

        public int Data;
    }

    public void Add(int value)
    {
        Node newItem = new Node();
        newItem.Data = value;

        Node current = _root;
        Node parent = null;

        while (current != null)
        {
            parent = current;

            if (current.Data == value)
            {
                return; // 같은 값이면 처리하지 않음.
            }

            if (current.Data > value)
            {
                current = current.Left;
            }
            else
            {
                current = current.Right;
            }
        }

        if (parent != null)
        {
            if (parent.Data > value)
            {
                parent.Left = newItem;
            }
            else
            {
                parent.Right = newItem;
            }
        }
        else
        {
            _root = newItem;
        }
    }

    int maxHeight(Node p)
    {
        if (p == null) return 0;
        int leftHeight = maxHeight(p.Left);
        int rightHeight = maxHeight(p.Right);
        return (leftHeight > rightHeight) ? leftHeight + 1 : rightHeight + 1;
    }

    public string ToDGML()
    {
        StringBuilder sb = new StringBuilder();

        sb.AppendLine("<?xml version=\"1.0\" encoding=\"utf - 8\"?>");
        sb.AppendLine("<DirectedGraph Layout=\"TopToBottom\" Title=\"Tree\" xmlns=\"http://schemas.microsoft.com/vs/2009/dgml\">");

        int left = (int)Math.Pow(2, maxHeight(_root)) * 30 + 100;
        int top = 100;

        StringBuilder nodes = new StringBuilder();
        StringBuilder links = new StringBuilder();

        DrawNodeDGML(nodes, links, _root, top, left, left / 2);
        sb.AppendLine("<Nodes>" + Environment.NewLine + nodes.ToString() + "</Nodes>");
        sb.AppendLine("<Links>" + Environment.NewLine + links.ToString() + "</Links>");

        sb.AppendLine("<Properties>");

        sb.AppendLine("<Property Id=\"Bounds\" DataType=\"System.Windows.Rect\" />");
        sb.AppendLine("<Property Id=\"Label\" Label=\"Label\" Description=\"Displayable label of an Annotatable object\" DataType=\"System.String\" />");
        sb.AppendLine("<Property Id=\"LabelBounds\" DataType=\"System.Windows.Rect\" />");
        sb.AppendLine("<Property Id=\"Layout\" DataType=\"System.String\" />");
        sb.AppendLine("<Property Id=\"Title\" DataType=\"System.String\" />");
        sb.AppendLine("<Property Id=\"UseManualLocation\" DataType=\"System.Boolean\" />");
        sb.AppendLine("</Properties>");

        sb.AppendLine("</DirectedGraph>");
        return sb.ToString();
    }

    void DrawNodeDGML(StringBuilder nodes, StringBuilder links, Node node, int top, int left, int offset)
    {
        int drawLeft = left + offset;

        nodes.AppendLine(string.Format("<Node UseManualLocation=\"True\" Id=\"{0}\" Bounds=\"{3}, {2}, 50, 26\" Label=\"{1}\" />", node.Data, node.Data,
            top, drawLeft));

        if (node.Left != null)
        {
            links.AppendLine(string.Format("<Link Source=\"{0}\" Label=\"Left\" Target=\"{1}\" />", node.Data, node.Left.Data));
            DrawNodeDGML(nodes, links, node.Left, top + 40, drawLeft, -(Math.Abs(offset) / 2));
        }

        if (node.Right != null)
        {
            links.AppendLine(string.Format("<Link Source=\"{0}\" Label=\"Right\" Target=\"{1}\" />", node.Data, node.Right.Data));
            DrawNodeDGML(nodes, links, node.Right, top + 40, drawLeft, +(Math.Abs(offset) / 2));
        }
    }
}

실행해 보면, 제법 그럴 듯하게 나옵니다. ^^

dgml_bintree_2.png

(첨부한 파일은 이 글의 테스트 코드를 포함합니다.)




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 6/27/2021]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2016-10-06 01시10분
Microsoft/automatic-graph-layout
; https://github.com/Microsoft/automatic-graph-layout
정성태

... 31  32  33  34  35  36  37  38  39  40  41  42  [43]  44  45  ...
NoWriterDateCnt.TitleFile(s)
12867정성태12/7/202114940개발 환경 구성: 612. 파이썬 - PyPI 패키지 만들기 (3) entry_points 옵션
12866정성태12/7/202121855오류 유형: 769. "docker build ..." 시 "failed to solve with frontend dockerfile.v0: failed to read dockerfile ..." 오류
12865정성태12/6/202115197개발 환경 구성: 611. 파이썬 - PyPI 패키지 만들기 (2) long_description, cmdclass 옵션
12864정성태12/6/202112880Linux: 46. WSL 환경에서 find 명령을 사용해 파일을 찾는 방법
12863정성태12/4/202114984개발 환경 구성: 610. 파이썬 - PyPI 패키지 만들기
12862정성태12/3/202112878오류 유형: 768. Golang - 빌드 시 "cmd/go: unsupported GOOS/GOARCH pair linux /amd64" 오류
12861정성태12/3/202116743개발 환경 구성: 609. 파이썬 - "Windows embeddable package"로 개발 환경 구성하는 방법 [1]
12860정성태12/1/202113244오류 유형: 767. SQL Server - 127.0.0.1로 접속하는 경우 "Access is denied"가 발생한다면?
12859정성태12/1/202121010개발 환경 구성: 608. Hyper-V 가상 머신에 Console 모드로 로그인하는 방법
12858정성태11/30/202118300개발 환경 구성: 607. 로컬의 USB 장치를 원격 머신에 제공하는 방법 - usbip-win
12857정성태11/24/202115151개발 환경 구성: 606. WSL Ubuntu 20.04에서 파이썬을 위한 uwsgi 설치 방법
12856정성태11/23/202117762.NET Framework: 1121. C# - 동일한 IP:Port로 바인딩 가능한 서버 소켓 [2]
12855정성태11/13/202113549개발 환경 구성: 605. Azure App Service - Kudu SSH 환경에서 FTP를 이용한 파일 전송
12854정성태11/13/202115732개발 환경 구성: 604. Azure - 윈도우 VM에서 FTP 여는 방법
12853정성태11/10/202113959오류 유형: 766. Azure App Service - JBoss 호스팅 생성 시 "This region has quota of 0 PremiumV3 instances for your subscription. Try selecting different region or SKU."
12851정성태11/1/202115487스크립트: 34. 파이썬 - MySQLdb 기본 예제 코드
12850정성태10/27/202117115오류 유형: 765. 우분투에서 pip install mysqlclient 실행 시 "OSError: mysql_config not found" 오류
12849정성태10/17/202116587스크립트: 33. JavaScript와 C#의 시간 변환 [1]
12848정성태10/17/202116381스크립트: 32. 파이썬 - sqlite3 기본 예제 코드 [1]
12847정성태10/14/202116587스크립트: 31. 파이썬 gunicorn - WORKER TIMEOUT 오류 발생
12846정성태10/7/202117577스크립트: 30. 파이썬 __debug__ 플래그 변수에 따른 코드 실행 제어
12845정성태10/6/202116052.NET Framework: 1120. C# - BufferBlock<T> 사용 예제 [5]파일 다운로드1
12844정성태10/3/202113706오류 유형: 764. MSI 설치 시 "... is accessible and not read-only." 오류 메시지
12843정성태10/3/202114193스크립트: 29. 파이썬 - fork 시 기존 클라이언트 소켓 및 스레드의 동작파일 다운로드1
12842정성태10/1/202134016오류 유형: 763. 파이썬 오류 - AttributeError: type object '...' has no attribute '...'
12841정성태10/1/202116608스크립트: 28. 모든 파이썬 프로세스에 올라오는 특별한 파일 - sitecustomize.py
... 31  32  33  34  35  36  37  38  39  40  41  42  [43]  44  45  ...