İkili Ağaç Yazdır


18

SO hakkında son bir soru esinlenerek ...

İkili ağacı aşağıdaki biçimde yazdırmak için bir işlev yazın:

   3
 /   \
1     5
 \   / \
  2 4   6
  1. Çıktı, bir düğüm çizgisini, ardından bir çizgiyi /ve \ilişkileri gösteren karakterleri, ardından bir düğüm çizgisini, vb. İçermelidir.
  2. Tüm düğümlerin tek bir karakter olarak temsil edilebildiğini varsayabilirsiniz.
  3. En düşük seviyedeki bitişik düğümler en az bir boşlukla ayrılmalı, daha sonraki düğümler uygun şekilde ayrılmalıdır.
  4. İki çocuklu düğümler tam olarak doğrudan çocuklarının ortasına yerleştirilmelidir.
  5. İlişki eğik çizgileri, ebeveyn ile uygun çocuk arasında (istediğiniz şekilde yuvarlak) olmalıdır.

Giriş:

Giriş, işlevinize bir argüman olarak sağlanacaktır. Ağacın tam yapısını belirtmeyeceğim, ancak gerçek bir ikili ağaç olarak kullanılabilir olmalıdır. Hayır "programımda ağaçlar, beklenen çıktıya rastlantısal olarak dizeler olarak gösterilmiyor".

Bir çıktı akışına yazdırabilir veya çıktıyı içeren bir dizeyi geri döndürebilirsiniz.

En kısa kod için puan, ama ben çok% 90 çalışan kısa bir çözüm yerine tamamen çalışan uzun bir çözüm tercih ediyorum.


Ödül için güncelleme:

Ödül için, ben (Doktor) küçük değişiklikler yapıyorum:

  • Giriş STDIN, ARGV veya işlev bağımsız değişkeninden olabilir.
  • Çıktının STDOUT'ta (veya console.logJS için) olması gerekir
  • Örneğin, girişin bir dizi biçiminde olduğunu varsayabilirsiniz. [1,2,3]veya[1 2 3]

Güncelleme 2 - İkili ağaç aslında bir ikili arama ağacı olmalıdır. Başlangıçta bundan bahsetmediğim için, kullanıcıların normal bir diziyi ikili bir arama ağacı dizisine ayrı bir program olarak dönüştürmesine izin vereceğim ve son bayt sayısı sadece programın diziyi argüman olarak alması ve yazdırması için olacak ikili ağaç gibi.


Birkaç ilişki eğik çizgi kullanmalıyız uygun muydu? Minimum sayıda eğik çizgi kullanmalı mıyız? Tek bir sol çocuğu ile tek bir sağ çocuğu arasında bir ayrım olmalı mı? Her çıktı hattında önde gelen boşlukların olması iyi olur mu?

Ağaç tam değilse (bazı n için 2 ^ n-1 düğümü) ne yaparız? Bazı düğümlerin (hangileri?) Sadece bir çocuğu vardır. Ancak tek bir çocukla düğümler almamıza izin verilirse, dejenere ağacın yapılması kolaydır (1-2-3-4-5-6 aşağı ve sağa, diyelim).
Keith Randall

Büyük sayılar için nasıl çizersiniz? Örneğin30000,1000,499999
Mohsen

Yanıtlar:


9

Fortran 77-1085 karakter

      subroutine q(u,t)
      implicit integer(i-z)
      character*33 f,g
      dimension t(u)
      m=ceiling(log(real(u))/log(2.))
      v=2**(m+1)-1
      do l=1,m
         n=2**(l-1)
         k=2**(m-l+2)-3
         w=(3+k)*2**(l-1)-k
         p=1+(v-w)/2
         if(l.ne.1)then
            write(f,'(A,I3,A)')'(A',p,',$)'
            print f,' '
            write(f,'(A5,I3,A3)')'(A3,A',k,',$)'
            do j=2**(l-1),2**l-1
               if(t(j/2).lt.0.or.t(j).lt.0)then
                  print f,'   ',' '
               elseif(mod(j,2).eq.0)then
                  print f,'  /',' '
               else
                  print f,' \ ',' '
               endif
            enddo
            print*
         endif
         write(f,'(A,I3,A)')'(A',p,',$)'
         print f,' '
         write(f,'(A5,I3,A3)')'(I3,A',k,',$)'
         write(g,'(A2,I3,A3)')'(A',k+3,',$)'
         do j=2**(l-1),2**l-1
            if(t(j).ge.0)then
               print f,t(j),' '
            else 
               print g,' '
            endif
         enddo
         print*
      enddo
      end

Ağaç giriş dizisinde ther zamanki gibi temsil edilir , kök 1'de, kök-> 2'de sol, kök-> sağda 3 kök-> sol-> 4'te sol ...

Çıkış, 5 seviyeye kadar konvansiyonel bir terminale sığmalıdır.

Dört veya daha fazla seviye olduğunda, her bir düğüm çifti arasında tam olarak bir eğik çizgi kullanıyorum. En fazla üç basamaklı düğüme izin verdim.

Yorumları ve fırlatma iskelesini içeren tam program:

      program tree

      parameter (l=8)          ! How many nodes to support
      dimension i(l)

c     Initialize the array to all empty nodes
      do j=1,l
         i(j)=-1
      end do
c     Fill in some values
      i(1)=3
      i(2)=1
      i(3)=5
      i(5)=2
      i(6)=4
      i(7)=7
c      i(14)=6
c      i(15)=8
c     Call the printing routine
      call q(l,i)

      stop
      end

c     Print an ASCII representation of the tree
c
c     u the length of the array containing the tree
c     t an integer array representing the tree.
c
c     The array contains only non-negative values, and empty nodes are
c     represented in the array with -1.
c
c     The printed representation uses three characters for every node,
c     and places the (back) slash equally between the two node-centers.
      subroutine q(u,t)
      implicit integer(i-z)
      character*33 f,g
      dimension t(u)
      m=ceiling(log(real(u))/log(2.)) ! maximum depth of the tree
      v=2**(m+1)-1              ! width needed for printing the whole tree
                                ! Optimized from 3*2**m + 1*((2**m)-1) at
                                ! the bottom level
      do l=1,m
         n=2**(l-1)             ! number of nodes on this level
         k=2**(m-l+2)-3         ! internode spacing
         w=(3+k)*2**(l-1)-k     ! width needed for printing this row
                                ! Optimized from 3*2**l + k*((2**l)-1) at
                                ! the bottom level
         p=1+(v-w)/2            ! padding for this row
c     Print the connecting lines associated with the previous level
         if(l.ne.1)then         ! Write the connecting lines
            write(f,'(A,I3,A)')'(A',p,',$)'
            print f,' '
            write(f,'(A5,I3,A3)')'(A3,A',k,',$)'
            do j=2**(l-1),2**l-1
               if(t(j/2).lt.0.or.t(j).lt.0)then
                  print f,'   ',' '
               elseif(mod(j,2).eq.0)then
                  print f,'  /',' '
               else
                  print f,' \ ',' '
               endif
            enddo
            print*
         endif
c     Print the nodes on this level
         write(f,'(A,I3,A)')'(A',p,',$)'
         print f,' '
         write(f,'(A5,I3,A3)')'(I3,A',k,',$)'
         write(g,'(A2,I3,A3)')'(A',k+3,',$)'
         do j=2**(l-1),2**l-1
            if(t(j).ge.0)then
               print f,t(j),' '
            else 
               print g,' '
            endif
         enddo
         print*
      enddo
      end

Örneğe eşdeğer girişli çıkış:

$ ./a.out 
         3             
     /      \      
     1       5     
      \    /  \  
       2   4   7 

YARDIM neden bu dil?
Aralık'ta

9
Çünkü golf oynamak için çok uygun değil.
dmckee

5

CJam, 100 99 bayt

q~_,2b,)2\#:Q1@{_2$<Q(S*:T*TQ2/:Q@ts[N+_0@{@1$' >{2$St2$_Q3*&2/^_4$>"\/"=t}*@)}/;U*o]o1:U$>\2*\}h];

Giriş, herhangi bir ascii kontrol karakteri olmadan bir karakter listesi olmalıdır. Boş düğümler boşlukla gösterilir. Ayrıca tam olarak 2 n -1 düğümü olan mükemmel bir ikili ağaç olmalıdır .

Misal:

['6 '3 '7 '1 '4 '  '9 '0 '2 '  '5 '  '  '8 ' ]

Veya sadece dizeleri kullanın:

"63714 902 5  8 "

Çıktı:

                6              
            /       \          
        3               7      
      /   \               \    
    1       4               9  
   / \       \             /   
  0   2       5           8    

açıklama

q~                        " Read input. ";
_,2b,                     " Get tree height. ";
)2\#:Q                    " Get (displayed) tree width and save it in Q. ";
1@                        " Push X=1 and rotate the input to top. ";
{                         " Do: ";
    _2$<                  " Get first X characters from the input. ";
    Q(S*:T                " T = (Q-1) spaces. ";
    *                     " Separate the X characters by T. ";
    TQ2/:Q@t              " Put the string in the middle of T, and divide Q by 2. ";
    s                     " Concatenate everything into a string.
                            This is the line of node labels. ";
    [
        N+                " Append a newline. ";
        _                 " Duplicate. ";
        0@                " Push a 0 and rotate the original string to top. ";
        {                 " For each character: ";
            @             " Rotate the duplicate to top. ";
            1$' >         " Test if the current character is greater than a space. ";
            {             " If true: ";
                2$St      " Set the current character in the duplicate to space. ";
                2$        " Copy the current position I (the number initialized with 0). ";
                _Q3*&2/^  " Calculate I ^ ((I & (3*Q))>>1),
                            the position of the relationship character. ";
                _4$>      " Test if it is greater than the current position. ";
                "\/"=     " Select the relationship character. ";
                t         " Change the character in the duplicate. ";
            }*
            @)            " Increment the current position. ";
        }/
                          " The last two items are the line of relationship characters
                            and the tree width. ";
        ;                 " Discard the tree width. ";
        U*                " If it is the first line, empty the line of
                            relationship characters. ";
        o                 " Output. ";
    ]o                    " Output the line of node labels. ";
    1:U                   " Mark it not the first line. ";
    $>                    " Remove the first X characters from the input. ";
    \2*\                  " Multiply X by 2. ";
}h                        " ...while the input is not empty. ";
];                        " Discard everything in the stack. ";

Dönüşüm komut dosyası

[[0LL]W]
[q~{_a_:i={'0+}*}%La2*f+
_,,]z$
1$a+
{
    {
        1$1=1$1=>:T
        {
            ~@0=2 3$1=t
            @1@ta\+
        }*
        T
    }g
}*
0=1=a
{
    {
        (M\+:M;
        La[' LL]aer~
    }%
    _[' LL]a-
}g
];
M0+`-3<']+

Karakterleri veya tek haneli sayıları kabul eder.

Örnekler (hepsi aynı):

['6 '7 '9 '3 '1 '2 '8 '4 '0 '5]
[6 7 9 3 1 2 8 4 0 5]
"6793128405"

Çıktı:

['6 '3 '7 '1 '4 ' '9 '0 '2 ' '5 ' ' '8 ' ]

Bu düz bir Kartezyen ağacı yapısı.


Sadece iki bayt daha ekleyebilir ve dönüşüm komut dosyasının girdisini karakter yerine doğru tamsayı olarak yapabilirsiniz :)
Optimizer

@Optimizer Her ikisini de destekleyecek şekilde düzenlendi. Bence karakterler sadece mantıklı düğüm isimlerini desteklediğinden daha mantıklı. Tek haneli rakamlardan çok daha fazla karakter var.
jimmy23013

2

Python 2,411 bayt

import math
def g(a,o,d,l,b):
 if l<0:
    return
 c=2*b+1
 k=2*l+1
 o[k]=' '*b
 n=d-l
 p=1 if n==0 else 3*2**n-1
 o[k-1]=p/2*' '
 i=0
 for v in a[2**l-1:2**l*2-1]:
    v=' ' if v==None else v
    o[k]+=v+' '*c
    m=' ' if v==' ' else '/' if i%2==0 else '\\'
    o[k-1]+=m+max(1,b)*' ' if i%2==0 else m+p*' '
    i+=1

 g(a,o,d,l-1,c)
def f(a):
 d=int(math.log(len(a),2))
 o=['']*(d*2+2)
 g(a,o,d,d,0)
 print '\n'.join(o[1:])

Not: İlk girinti seviyesi 1 boşluk, ikincisi bir sekmedir.

fTek karakterli dizelerin veya None' slerinin listesiyle arayın , ör. f(['1',None,'3']). Liste boş olamaz.

Bu ödülün kurallarına uymalıdır.

Dönüştürücü komut dosyası:

Diziyi ikili ağaç yazıcısı tarafından kullanılan formata dönüştürür. Misal:

$ python conv.py [3,5,4,6,1,2]
['3', '1', '5', None, '2', '4', '6']

-

import sys

def insert(bt, i):
    if i < bt[0]:
        j = 0
    else:
        j = 1

    n = bt[1][j]
    if n == [None]:
        bt[1][j] = [i, [[None], [None]]]
    else:
        insert(bt[1][j], i)

def insert_empty(bt, i):
    if i == 0:
        return
    if bt == [None]:
        bt += [[[None], [None]]]

    insert_empty(bt[1][0], i - 1)
    insert_empty(bt[1][1], i - 1)

def get(l, level):
    if level == 0:
        if type(l) == list:
            return ([], l)
        else:
            return ([l], [])
    elif type(l) != list:
        return ([], [])

    res = []
    left = []

    for r, l in  [get(i, level - 1) for i in l]:
        res += r
        left += l

    return (res, left)

if __name__ == '__main__':
    l = eval(sys.argv[1])
    bt = [l[0], [[None], [None]]]
    map(lambda x: insert(bt, x), l[1:])

    depth = lambda l: 0 if type(l) != list else max(map(depth, l)) + 1
    d = (depth(bt) + 1) / 2

    insert_empty(bt, d - 1)

    flat = []
    left = bt
    i = 0
    while len(left) > 0:
        f, left = get(left, 1)
        flat += f

        i += 1

    for i in range(len(flat) - 1, -1, -1):
        if flat[i] == None:
            flat.pop()
        else:
            break

    flat = map(lambda x: None if x == None else str(x), flat)

    print flat

Örnekler:

Bunları çalıştırmak için ana dosyaya bt.pyve dönüştürücü dosyaya sahip olmalısınız conv.py.

$ python conv.py [3,5,4,6,1,2] | python -c 'import bt; bt.f(input())'
   3
  / \
 1   5
  \ / \
  2 4 6
$ python conv.py [5,4,3,7,9] | python -c 'import bt; bt.f(input())'
   5
  / \
 4   7
/     \
3     9
$ python conv.py [1,2,3,4,5,6] | python -c 'import bt; bt.f(input())'
                               1
                                       \
                                               2
                                                   \
                                                       3
                                                         \
                                                           4
                                                            \
                                                             5
                                                              \
                                                              6
$ python conv.py [6,5,4,3,2,1] | python -c 'import bt; bt.f(input())'
                                   6
                       /
               5
           /
       4
     /
   3
  /
 2
/
1

Aslında ikili ağacı oluşturmuyorsunuz. Diziyi ikili ağaç olarak yazdırmak yeterlidir. Dizinin çıktısı ['1','2','3','4','5','6','7','8','9']gösterdiğiniz gibi değil. Bu olması gereken 3bir hak çocuğun itibariyle 2hangi bir sağ çocuğu 1bir kök öğesi olan.
Optimizer

@Optimizer Şu sorudan: "Giriş, işlevinize bir argüman olarak sağlanacaktır. Ağacın tam yapısını belirtmeyeceğim, ancak gerçek bir ikili ağaç olarak kullanılabilir olmalıdır." Kullanılan dizi biçiminin belirli bir tanımını görmüyorum.
Tyilo

Asıl soru, ikili bir ağacın basılmasıyla ilgilidir . Çıktılarınız ikili ağaçlar değil. Dizinin formatının onunla hiçbir ilgisi yoktur.
Doktor

@Optimizer nasıl ikili ağaçlar değildir? Wikipedia'dan: ikili ağaç, her düğümün en fazla iki çocuğu olduğu bir ağaç veri yapısıdır. Düğümlerden herhangi birinde ikiden fazla çocuk var mı?
Tyilo

Ughh. Şimdi görüyorum. Bence burada yanlış anlaşılma var. İlk örneklerde bile, çıktı ikili arama ağacı biçimindedir . Ödülüm de sadece ikili bir arama ağacı içindir. Oradaki karışıklık için özür dilerim.
Optimizer

1

APL, 125 karakter

{⍵{x←⍵[0;d←⌈2÷⍨1⌷⍴⍵]←↑⍺
2 1∇{x[2↓⍳↑⍴x;(⍳d)+d×⍺-1]←⍵(⍺⍺⍣t←0≠⍴⍵)2↓x[;⍳d]
x[1;d+(⌈d÷4)ׯ1*⍺]←' /\'[t×⍺]}¨⍺[2 1]
x}' '⍴⍨2(×,*)≡⍵}

Misal:

{⍵{x←⍵[0;d←⌈2÷⍨1⌷⍴⍵]←↑⍺
2 1∇{x[2↓⍳↑⍴x;(⍳d)+d×⍺-1]←⍵(⍺⍺⍣t←0≠⍴⍵)2↓x[;⍳d]
x[1;d+(⌈d÷4)ׯ1*⍺]←' /\'[t×⍺]}¨⍺[2 1]
x}' '⍴⍨2(×,*)≡⍵}('1' ('2' ('3' ('4' ()()) ('5' ()())) ('6' ()('7' ()())))('8' ()('9' ('0' ()())())))

Burada test edildi.


Bu da dönüşüm komut dosyası mı?
Optimize Edici

@Optimizer Muhtemelen ikili arama ağacı olarak kullanılabilecek iç içe dizi giriş formatını alır (ancak karmaşıklıktan emin değilim). Daha alışılmış biçimleri kullanmam gerekirse ... belki daha sonra yaparım.
jimmy23013

@Optimizer Şimdi soruyu tekrar okurken, "ikili arama ağacı dizisi" tam bir ikili ağacın derinlik sırasına göre dizisi (veya başka bir şey) anlamına mı geliyor? Belirli bir şey olduğunu düşünmemiştim. Ve bu terimi aramak yararlı bir şey vermedi.
jimmy23013


@Optimizer Eh, demek istediğim buydu. Ama genellikle "ikili arama ağacı dizisi", sadece "ikili ağaçların bir dizi depolama" denir sanmıyorum. Muhtemelen biraz açıklığa ihtiyacı var ... Ve muhtemelen bu cevabı günler sonra düzeltebilirim, belki başka bir dilde ...
jimmy23013

0

Yakut, 265 bayt

def p(t);h=Math.log(t.length,2).to_i;i=-1;j=[];0.upto(h){|d|s=2**(h-d)-1;c=2**d;if d>0;m=' '*(s+s/2)+'I'+' '*(s-s/2);1.upto(d){m+=' '+m.reverse};w=i;puts m.gsub(/I/){|o|t[w+=1]?(w%2==0?'\\':'/'):' '};end;puts (0...c).map{' '*s+(t[i += 1]or' ').to_s+' '*s}*' ';};end

@Proudhaskeller sürümü, 269 bayt

def p(t);h=Math.log(t.length,2).to_i;i=-1;j=[];0.upto(h){|d|s=(z=2**(h-d))-1;c=2**d;if d>0;m=' '*(s+z/2)+'I'+' '*(s-z/2);1.upto(d){m+=' '+m.reverse};w=i;puts m.gsub(/I/){|o|t[w+=1]?(w%2==0?'\\':'/'):' '};end;puts (0...c).map{' '*s+(t[i += 1]or' ').to_s+' '*s}*' ';};end

Açıklama

Ayrıntılı sürüm:

def p(t)
  depth = Math.log(t.length, 2).floor
  i = -1
  j = []
  (0..depth).each do |d|
    s = 2 ** (depth-d)-1
    c = 2 ** d

    if d > 0
      m = ' '*(s+s/2) + '|' + ' '*(s-s/2)
      w = i
      1.upto(d) { m += ' ' + m.reverse }
      puts m.gsub(/\|/) { |o| t[w+=1] ? (w%2==0 ? '\\' : '/') : ' ' }
    end

    puts (0...c).map{' '*s+(t[i += 1]or' ').to_s+' '*s}*' '
  end
end

Misal

n = nil
p([
  1, 2, 3, 4, 5,
  n, 7, 8, 9, 0,
  1, n, n, 4, 5,
  6, 7, 8, 9, 0,
  1, 2, 3, n, n,
  n, n, 8, 9, n,
  n
])

verir:

               1               
          /         \          
       2               3       
    /     \               \    
   4       5               7   
 /   \   /   \           /   \ 
 8   9   0   1           4   5 
/ \ / \ / \ / \         / \    
6 7 8 9 0 1 2 3         8 9   

(Henüz dönüşüm komut dosyasını yazmadım.)


eğik çizgiler tam ortasında değil
gururlu haskeller

@proudhaskeller "istediğiniz şekilde yuvarlak", ben bu şekilde daha havalı göründüğünü düşündüm. İsterseniz s / 2'yi (s + 1) / 2 ile değiştirebilirsiniz.
AlexRath

Hayır, ilk sıradaki eğik çizgiler tam ortada değil, bu sırada bu bir yuvarlama meselesi değil
gururlu Haskeller

@proudhaskeller Eğer s / 2'yi (s + 1) / 2 ile değiştirirseniz tam olarak ortadalar, ama yine de bu yolu tercih ediyorum çünkü en soldaki ve en sağdaki dalların yuvarlak görünmesini sağlıyor.
AlexRath

bu spec karşı ...
gurur haskeller
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.