In một cây nhị phân


18

Lấy cảm hứng từ một câu hỏi gần đây về SO ...

Viết hàm để in cây nhị phân theo định dạng sau:

   3
 /   \
1     5
 \   / \
  2 4   6
  1. Đầu ra phải bao gồm một dòng các nút, theo sau là một dòng /và các \ký tự chỉ ra các mối quan hệ, theo sau là một dòng các nút, v.v.
  2. Bạn có thể giả sử tất cả các nút có thể biểu diễn dưới dạng một ký tự.
  3. Các nút liền kề ở mức thấp nhất nên được phân tách bằng ít nhất một khoảng trắng, các nút tiếp theo nên được phân tách khi thích hợp.
  4. Các nút có hai con nên được đặt chính xác ở giữa con trực tiếp của chúng.
  5. Chém mối quan hệ nên được một nửa giữa cha mẹ và đứa trẻ thích hợp (làm tròn bất cứ cách nào bạn muốn).

Đầu vào:

Đầu vào sẽ được cung cấp làm đối số cho chức năng của bạn. Tôi sẽ không chỉ định cấu trúc chính xác của cây, tuy nhiên nó phải có thể sử dụng như một cây nhị phân thực tế. Không có "cây nào được biểu diễn trong chương trình của tôi dưới dạng các chuỗi trùng khớp với sản lượng dự kiến".

Bạn có thể in ra một luồng đầu ra hoặc trả về một chuỗi chứa đầu ra, sự lựa chọn của bạn.

Điểm cho mã ngắn nhất, nhưng tôi rất thích một giải pháp dài hoàn toàn làm việc hơn là một giải pháp ngắn hoạt động 90%.


Cập nhật cho tiền thưởng:

Đối với tiền thưởng, tôi (Trình tối ưu hóa) đang thực hiện các thay đổi nhỏ:

  • Đầu vào có thể từ STDIN, ARGV hoặc đối số hàm.
  • Đầu ra cần phải ở trên STDOUT (hoặc console.logcho JS)
  • Bạn có thể giả sử rằng đầu vào ở dạng mảng, ví dụ như ex. [1,2,3]hoặc là[1 2 3]

Cập nhật 2 - Cây nhị phân thực sự phải là cây tìm kiếm nhị phân. Vì ban đầu tôi không đề cập đến điều này, tôi sẽ cho phép người dùng coi việc chuyển đổi một mảng bình thường thành một mảng cây tìm kiếm nhị phân như một chương trình riêng biệt và số byte cuối cùng sẽ chỉ dành cho chương trình lấy mảng đó làm đối số và in nó như một cây nhị phân.


Chúng ta có nên sử dụng một vài dấu gạch chéo mối quan hệ? Chúng ta phải sử dụng số lượng tối thiểu của dấu gạch chéo? Có nên phân biệt giữa việc có một con trái và một con phải không? Sẽ ổn khi có không gian hàng đầu trong mỗi dòng đầu ra?

Chúng ta phải làm gì nếu cây chưa hoàn thành (2 ^ n-1 nút cho một số n)? Một số nút (cái nào?) Chỉ có một con. Nhưng nếu chúng ta được phép có các nút chỉ có một con, thì cây thoái hóa rất dễ thực hiện (1-2-3-4-5-6 xuống và sang phải, nói).
Keith Randall

Làm thế nào bạn vẽ nó cho số lượng lớn? Ví dụ30000,1000,499999
Mohsen

Câu trả lời:


9

Fortran 77 - 1085 ký tự

      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

Cây được biểu diễn trong mảng đầu vào t theo kiểu thông thường, root ở 1, root-> left ở 2, root-> right ở 3 root-> left-> left ở 4 ...

Đầu ra phải vừa trong một thiết bị đầu cuối thông thường sâu tới 5 cấp.

Tôi sử dụng chính xác một dấu gạch chéo giữa mỗi cặp nút, trông khá ngớ ngẩn ở gần đỉnh một khi có bốn cấp trở lên. Tôi cho phép tối đa ba nút chữ số.

Chương trình đầy đủ với ý kiến ​​và một giàn giáo khởi động:

      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

Đầu ra với đầu vào tương đương với ví dụ:

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

Giúp đỡ tại sao ngôn ngữ này?
tomsmeding

9
Bởi vì nó rất kém phù hợp với việc chơi golf.
dmckee

5

CJam, 100 99 byte

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];

Đầu vào phải là một danh sách các ký tự, không có bất kỳ ký tự điều khiển ascii nào. Các nút trống được biểu thị bằng một khoảng trắng. Nó cũng phải là một cây nhị phân hoàn hảo với chính xác 2 n -1 nút.

Thí dụ:

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

Hoặc đơn giản là sử dụng chuỗi:

"63714 902 5  8 "

Đầu ra:

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

Giải trình

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. ";

Kịch bản chuyển đổi

[[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<']+

Nó chấp nhận một trong hai ký tự hoặc số có một chữ số.

Ví dụ (tất cả đều giống nhau):

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

Đầu ra:

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

Đó là một công trình cây Cartesian thẳng tiến.


Bạn chỉ có thể thêm hai byte nữa và tạo đầu vào của tập lệnh chuyển đổi thành số nguyên thích hợp thay vì ký tự :)
Trình tối ưu hóa

@Optimizer Đã chỉnh sửa để hỗ trợ cả hai. Tôi nghĩ rằng các ký tự có ý nghĩa hơn vì nó chỉ hỗ trợ các tên nút với một ký tự duy nhất. Có nhiều ký tự hơn số một chữ số.
jimmy23013

2

Python 2, 411 byte

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:])

Lưu ý: Mức thụt đầu tiên là 1 khoảng trắng, thứ hai là một tab.

Gọi fvới một danh sách các chuỗi một ký tự hoặc None's, ví dụ.f(['1',None,'3']). Danh sách không thể để trống.

Điều này nên tuân theo các quy tắc cho tiền thưởng.

Tập lệnh chuyển đổi:

Chuyển đổi và mảng thành định dạng được sử dụng bởi máy in cây nhị phân. Thí dụ:

$ 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

Ví dụ:

Để chạy chúng, bạn nên đặt tên tệp chính bt.pyvà tệp chuyển đổi có tên 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

Bạn không thực sự tạo cây nhị phân. Chỉ cần in mảng như một cây nhị phân. Đầu ra của ['1','2','3','4','5','6','7','8','9']mảng không phải là những gì bạn đã cho thấy. Nó nên có 3một đứa trẻ đúng 2là một đứa trẻ đúng 1là một phần tử gốc.
Tối ưu hóa

@Optimizer Từ câu hỏi: "Đầu vào sẽ được cung cấp làm đối số cho chức năng của bạn. Tôi sẽ không chỉ định cấu trúc chính xác của cây, tuy nhiên nó phải có thể sử dụng như một cây nhị phân thực tế." Tôi không thấy một định nghĩa cụ thể của định dạng mảng được sử dụng.
Tyilo

Câu hỏi ban đầu là về việc in một cây nhị phân . Đầu ra của bạn không phải là cây nhị phân. Định dạng của mảng không có gì để làm với nó.
Tối ưu hóa

@Optimizer làm sao chúng không phải là cây nhị phân? Từ Wikipedia: cây nhị phân là cấu trúc dữ liệu cây trong đó mỗi nút có nhiều nhất hai con. Có ai trong số các nút có nhiều hơn hai con?
Tyilo

Ừm Tôi thấy bây giờ Tôi nghĩ rằng có một sự hiểu lầm hạn ở đây. Ngay cả trong các ví dụ ban đầu, đầu ra có định dạng của cây tìm kiếm nhị phân . Và tiền thưởng của tôi cũng chỉ dành cho một cây tìm kiếm nhị phân. Xin lỗi vì sự nhầm lẫn ở đó.
Trình tối ưu hóa

1

APL, 125 ký tự

{⍵{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(×,*)≡⍵}

Thí dụ:

{⍵{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' ()())())))

Đã thử nghiệm ở đây.


Đây có phải là kịch bản chuyển đổi quá không?
Tối ưu hóa

@Optimizer Nó có định dạng đầu vào mảng lồng nhau, có thể được sử dụng làm cây tìm kiếm nhị phân (nhưng tôi không chắc về độ phức tạp). Nếu tôi phải sử dụng một số định dạng thông thường hơn ... có thể tôi sẽ thực hiện sau.
jimmy23013

@Optimizer Bây giờ đọc lại câu hỏi, "mảng cây tìm kiếm nhị phân" có nghĩa là mảng của cây nhị phân hoàn chỉnh theo thứ tự chiều sâu (hoặc cái gì khác) không? Tôi không nghĩ đó là bất cứ điều gì cụ thể. Và tìm kiếm thuật ngữ này đã không cung cấp bất cứ điều gì hữu ích.
jimmy23013


@Optimizer Vâng, đó chỉ là những gì tôi muốn nói. Nhưng tôi không nghĩ nó thường được gọi là "mảng cây tìm kiếm nhị phân", mà chỉ là "một loại lưu trữ mảng của cây nhị phân". Có lẽ nó cần được làm rõ ... Và có lẽ tôi sẽ sửa câu trả lời này vài ngày sau đó, có thể bằng một ngôn ngữ khác ...
jimmy23013

0

Ruby, 265 byte

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

Phiên bản @proudhaskeller, 269 byte

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

Giải thích

Phiên bản dài dòng:

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

Thí dụ

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
])

cho:

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

(Tôi chưa viết kịch bản chuyển đổi.)


dấu gạch chéo của bạn không chính xác ở giữa
tự hào

@proudhaskeller "tròn bất cứ cách nào bạn muốn", tôi nghĩ rằng nó trông mát mẻ hơn theo cách này. Bạn có thể thay thế s / 2 bằng (s + 1) / 2 nếu muốn.
AlexRath

Không, các dấu gạch chéo ở hàng đầu tiên không chính xác ở giữa, trong hàng này không phải là vấn đề làm tròn
tự hào

@proudhaskeller Nếu bạn thay s / 2 bằng (s + 1) / 2 thì chúng chính xác ở giữa, nhưng tôi vẫn thích cách này vì nó làm cho các nhánh ngoài cùng và bên phải trông tròn.
AlexRath

nó chống lại thông số kỹ thuật ...
tự hào
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.