Domanda

Per cominciare, la questione non è un duplicato di questo , ma si basa su di esso.

Prendendo l'albero in questa domanda come un esempio,

    1 
   / \
  2   3
 /   / \
4   5   6

Come si modificare il programma per stampare così,

1
2 3
4 5 6

, piuttosto che il generale

1 
2 
3 
4 
5 
6

Sono fondamentalmente alla ricerca di intuizioni sul modo più efficace per farlo - Ho un metodo che comporti aggiungendo il risultato a un elenco e quindi loop attraverso di essa. Un modo più efficiente potrebbe essere quella di memorizzare l'ultimo elemento in ogni livello come è spuntato, e stampare una nuova linea dopo.

idee?

È stato utile?

Soluzione

Basta costruire un livello alla volta, per esempio:.

class Node(object):
  def __init__(self, value, left=None, right=None):
    self.value = value
    self.left = left
    self.right = right

def traverse(rootnode):
  thislevel = [rootnode]
  while thislevel:
    nextlevel = list()
    for n in thislevel:
      print n.value,
      if n.left: nextlevel.append(n.left)
      if n.right: nextlevel.append(n.right)
    print
    thislevel = nextlevel

t = Node(1, Node(2, Node(4, Node(7))), Node(3, Node(5), Node(6)))

traverse(t)

Modifica : se siete interessati a ottenere un piccolo risparmio di massimo consumo di memoria "ausiliaria" (non avendo mai contemporaneamente tutto questo livello e il livello successivo in tale memoria "ausiliaria"), si può ovviamente usare collection.deque invece di list, e consumare il livello attuale, come si va (via popleft) invece di looping. L'idea di creare un livello alla volta (come si consumano iterate --o on-- quello precedente) rimane intatto - quando si ha bisogno di distinguere i livelli, è solo più diretto rispetto all'utilizzo di un unico grande deque più informazioni ausiliarie ( quali profondità, o il numero di nodi rimanenti in un dato livello).

Tuttavia, un elenco che viene aggiunto solo per (e loop su, piuttosto che "consumato") è un po 'più efficiente di un deque (e se siete dopo soluzioni C ++, in modo simile, uno std :: vector utilizzando solo push_back per la costruzione di esso, e un ciclo per poi usarlo, è più efficiente di uno std :: deque). Poiché tutta la producendo avviene prima, poi tutte le iterazioni (o tempo), un'alternativa interessante se memoria è strettamente vincolata potrebbe essere quella di utilizzare un elenco comunque per rappresentare ogni livello, allora .reverse prima di iniziare a consumare esso (con chiamate .pop) - non ho grandi alberi intorno per controllare attraverso la misurazione, ma ho il sospetto che questo approccio sarebbe ancora più veloce (e in realtà meno memoria che consumano) rispetto deque (partendo dal presupposto che l'implementazione sottostante della lista [ [o std :: vector]] in realtà non riciclare memoria dopo un paio di telefonate al pop [[o pop_back]] - e con lo stesso presupposto per deque, naturalmente; -).

Altri suggerimenti

Questa è ricerca in ampiezza, in modo da poter utilizzare una coda e ricorsivamente fare questo in modo semplice e compatto ...

# built-in data structure we can use as a queue
from collections import deque

def print_level_order(head, queue = deque()):
    if head is None:
        return
    print head.data
    [queue.append(node) for node in [head.left, head.right] if node]
    if queue:
        print_level_order(queue.popleft(), queue)

perché non tenere sentinella in coda e controllare quando tutti i nodi di livello attuale vengono elaborati.

public void printLevel(Node n) {
    Queue<Integer> q = new ArrayBlockingQueue<Integer>();
    Node sentinal = new Node(-1);
    q.put(n);
    q.put(sentinal);
    while(q.size() > 0) {
        n = q.poll();
        System.out.println(n.value + " "); 
        if (n == sentinal && q.size() > 0) {
           q.put(sentinal); //push at the end again for next level
           System.out.println();
        }
        if (q.left != null) q.put(n.left);
        if (q.right != null) q.put(n.right);
    }
}

La mia soluzione è simile a Alex Martelli di, ma mi separano attraversamento della struttura dati dalla lavorazione della struttura dati. Ho messo la carne del codice in iterLayers per mantenere printByLayer breve e dolce.

from collections import deque

class Node:
    def __init__(self, val, lc=None, rc=None):
        self.val = val
        self.lc = lc
        self.rc = rc

    def iterLayers(self):
        q = deque()
        q.append(self)
        def layerIterator(layerSize):
            for i in xrange(layerSize):
                n = q.popleft()
                if n.lc: q.append(n.lc)
                if n.rc: q.append(n.rc)
                yield n.val
        while (q):
            yield layerIterator(len(q))

    def printByLayer(self):
        for layer in self.iterLayers():
            print ' '.join([str(v) for v in layer])

root = Node(1, Node(2, Node(4, Node(7))), Node(3, Node(5), Node(6)))
root.printByLayer()

che stampa il seguente quando eseguire:

1
2 3
4 5 6
7

Un semplice versione a base di pane prima ricerca, Questo codice è applicabile per i grafici in generale e può essere utilizzato per gli alberi binari pure.

def printBfsLevels(graph,start):
  queue=[start]
  path=[]
  currLevel=1
  levelMembers=1
  height=[(0,start)]
  childCount=0
  print queue
  while queue:
    visNode=queue.pop(0)
    if visNode not in path:
      if  levelMembers==0:
        levelMembers=childCount
        childCount=0
        currLevel=currLevel+1
      queue=queue+graph.get(visNode,[])
      if levelMembers > 0:
        levelMembers=levelMembers-1
        for node in graph.get(visNode,[]):
          childCount=childCount+1
          height.append((currLevel,node))
      path=path+[visNode]

  prevLevel=None

  for v,k in sorted(height):
        if prevLevel!=v:
          if prevLevel!=None:
            print "\n"
        prevLevel=v
        print k,
  return height

g={1: [2, 3,6], 2: [4, 5], 3: [6, 7],4:[8,9,13]}
printBfsLevels(g,1)


>>> 
[1]
1 

2 3 6 

4 5 6 7 

8 9 13
>>> 

Un'altra versione base di ricorsione, che è specifico per albero binario

class BinTree:
  "Node in a binary tree"
  def __init__(self,val,leftChild=None,rightChild=None,root=None):
    self.val=val
    self.leftChild=leftChild
    self.rightChild=rightChild
    self.root=root
    if not leftChild and not rightChild:
      self.isExternal=True

  def getChildren(self,node):
    children=[]
    if node.isExternal:
      return []
    if node.leftChild:
      children.append(node.leftChild)
    if node.rightChild:
      children.append(node.rightChild)
    return children

  @staticmethod
  def createTree(tupleList):
    "Creates a Binary tree Object from a given Tuple List"
    Nodes={}
    root=None
    for item in treeRep:
      if not root:
        root=BinTree(item[0])
        root.isExternal=False
        Nodes[item[0]]=root
        root.root=root
        root.leftChild=BinTree(item[1],root=root)
        Nodes[item[1]]=root.leftChild
        root.rightChild=BinTree(item[2],root=root)
        Nodes[item[2]]=root.rightChild
      else:
        CurrentParent=Nodes[item[0]]
        CurrentParent.isExternal=False
        CurrentParent.leftChild=BinTree(item[1],root=root)
        Nodes[item[1]]=CurrentParent.leftChild
        CurrentParent.rightChild=BinTree(item[2],root=root)
        Nodes[item[2]]=CurrentParent.rightChild
    root.nodeDict=Nodes
    return root

  def printBfsLevels(self,levels=None):
    if levels==None:
      levels=[self]
    nextLevel=[]
    for node in levels:
      print node.val,
    for node in levels:
      nextLevel.extend(node.getChildren(node))
    print '\n'
    if nextLevel:
      node.printBfsLevels(nextLevel)  


##       1
##     2     3
##   4   5  6  7
##  8

treeRep = [(1,2,3),(2,4,5),(3,6,7),(4,8,None)]
tree= BinTree.createTree(treeRep)
tree.printBfsLevels()

>>> 
1 

2 3 

4 5 6 7 

8 None 

Ecco il mio codice stampa il livello di albero per livello così come a testa in giù

int counter=0;// to count the toatl no. of elments in the tree

void tree::print_treeupsidedown_levelbylevel(int *array)
{
    int j=2;  
    int next=j;
    int temp=0;
    while(j<2*counter)
    {
        if(array[j]==0)
        break;

        while(array[j]!=-1)
        {
            j++;
        }

        for(int i=next,k=j-1 ;i<k; i++,k--)
        {
            temp=array[i];
            array[i]=array[k];
            array[k]=temp;
        }

        next=j+1;
        j++;
    }

    for(int i=2*counter-1;i>=0;i--)
    {
        if(array[i]>0)
        printf("%d ",array[i]);

        if(array[i]==-1)
        printf("\n");
    }
}

void tree::BFS()
{
    queue<node *>p;

    node *leaf=root;

    int array[2*counter];
    for(int i=0;i<2*counter;i++)
    array[i]=0;

    int count=0;

    node *newline=new node; //this node helps to print a tree level by level
    newline->val=0;
    newline->left=NULL;
    newline->right=NULL;
    newline->parent=NULL;

    p.push(leaf);
    p.push(newline);

    while(!p.empty())
    {
        leaf=p.front();
        if(leaf==newline)
        {
            printf("\n");
            p.pop();
            if(!p.empty())
            p.push(newline);
            array[count++]=-1;
        }
        else
        {
            cout<<leaf->val<<" ";
            array[count++]=leaf->val;

            if(leaf->left!=NULL)
            {
                p.push(leaf->left);
            }
            if(leaf->right!=NULL)
            {
                p.push(leaf->right);
            }
            p.pop();
        }
    }
    delete newline;

    print_treeupsidedown_levelbylevel(array);
}

Qui nel mio codice funzione BFS stampa il livello di albero per livello, che riempie anche i dati in un array int per la stampa l'albero a testa in giù. (Notare che c'è è usato un po 'di scambio durante la stampa l'albero a testa in giù che aiuta a raggiungere il nostro obiettivo). Se lo scambio non viene eseguita poi per un albero come

                    8
                   /  \
                  1    12
                  \     /
                   5   9
                 /   \
                4     7
                     /
                    6

O / P sarà

  6
  7 4
  9 5
  12 1
  8

ma l'O / P deve essere

  6
  4 7
  5 9
  1 12
  8

questo il motivo per cui è stato necessario parte scambiando in tale matrice.

class TNode:
  def __init__(self, data, left=None, right=None):
    self.data = data
    self.left = left
    self.right = right

class BST:
  def __init__(self, root):
    self._root = root

  def bfs(self):
    list = [self._root]
    while len(list) > 0:
        print [e.data for e in list]
        list = [e.left for e in list if e.left] + \
               [e.right for e in list if e.right]
bst = BST(TNode(1, TNode(2, TNode(4), TNode(5)), TNode(3, TNode(6), TNode(7))))
bst.bfs()

Questo è principalmente lo stesso codice fornito da Alex Martelli tranne questo viene modificato per Python 3.

class Node(object):
  def __init__(self, value, left=None, right=None):
    self.value = value
    self.left = left
    self.right = right

def traverse(rootnode):
  thislevel = [rootnode]
  while thislevel:
    nextlevel = list()
    for n in thislevel:
      print (n.value,' ', end=''),
      if n.left: nextlevel.append(n.left)
      if n.right: nextlevel.append(n.right)
    print(" ")
    thislevel = nextlevel

t = Node(1, Node(2, Node(4, Node(7))), Node(3, Node(5), Node(6)))

traverse(t)

Il codice seguente stamperà ogni livello di albero binario nella nuova linea:

public void printbylevel(node root){
    int counter = 0, level = 0;
    Queue<node> qu = new LinkedList<node>();

    qu.add(root);
    level = 1;
    if(root.child1 != null)counter++;
    if(root.child2 != null)counter++;

     while(!qu.isEmpty()){
         node temp = qu.remove();
         level--;
         System.out.print(temp.val);
         if(level == 0 ){
             System.out.println();

             level = counter;
             counter = 0;
         }
        if(temp.child1 != null){
            qu.add(temp.child1);
            counter++;
        }
        if(temp.child2 != null){
            qu.add(temp.child2);
            counter++;
        }
     }
}

Credo che ciò che si aspetta è quello di stampare i nodi ad ogni livello sia separato da uno spazio o una virgola e livelli separati da una nuova linea. Questo è come vorrei codificare fino dell'algoritmo. Sappiamo che quando facciamo una ricerca in ampiezza su un grafico o un albero e inserire i nodi in una coda, tutti i nodi nella coda in uscita saranno sia allo stesso livello di quello precedente o un nuovo livello che è livello padre + 1 e niente altro.

Quindi, quando si è ad un livello di continuare a stampare i valori dei nodi e, non appena si scopre che il livello del nodo aumenta di 1, quindi si inserisce una nuova riga prima di iniziare a stampare tutti i nodi a quel livello.

Questo è il mio codice è necessario che non usa molta memoria e solo la coda per tutto.

Supponendo che inizia albero dalla radice.

queue = [(root, 0)]  # Store the node along with its level. 
prev = 0
while queue:
  node, level = queue.pop(0)
  if level == prev:
    print(node.val, end = "")
  else:
    print()
    print(node.val, end = "")
  if node.left:
    queue.append((node.left, level + 1))
  if node.right:
    queue.append((node.right, level + 1))
  prev = level

Alla fine tutto ciò che serve è la coda per tutta l'elaborazione.

Per coloro che sono semplicemente interessati a visualizzare alberi binari (e non tanto nella teoria che sta dietro di ricerca in ampiezza), c'è una funzione show nel pacchetto BinaryTree. Applicato all'esempio indicato nella domanda,

from binarytree import Node, show

root = Node(1)
root.left = Node(2)
root.right = Node(3)
root.left.left = Node(4)
root.right.left = Node(5)
root.right.right = Node(6)

show(root)

che stampa

    1    
   / \   
  2   3  
 /   / \ 
4   5   6

Ecco un succo Python che stampa l'albero per livello. L'idea è di utilizzare BFS e mantenere un intero indicatore di livello che indica la fine dell'ultimo nodo del livello. Questo è simile al metodo sentinella di Naresh, ma senza la necessità di inserire una sentinella all'interno della coda, dal momento che questo si ottiene l'indicatore di livello.

Questo algoritmo ha una complessità spaziale di O (2 tree_height )

# Print tree by levels - using BFS
# Time complexity of O(n)
# Space complexity: O(2^tree_height)

from collections import deque

class Node:
    def __init__(self, data, left=None, right=None):
        self.data = data
        self.left = left
        self.right = right

def print_levels_tree(root: Node):
    q = deque()
    q.append(root)
    level, level_marker = 0, 1
    while q:
        if (level_marker == 0):
            level, level_marker = level + 1, len(q)
            print("", end = '\n')
        level_marker -= 1

        node = q.popleft()

        if (node is None):
            continue

        print(node.data, " ", end = '')

        q.append(node.left)
        q.append(node.right)


# Some examples
tree = Node(19, Node(7, Node(3), Node(11)), Node(19)) 
print_levels_tree(tree)

left = Node(7, Node(3, Node(2), Node(5)), Node(11, None, Node(17, Node(13))))
tree = Node(19, left, Node(43))
print_levels_tree(tree)

left = Node(7, Node(3, Node(2), Node(5)), Node(11, None, Node(17, Node(13))))
right = Node(43, Node(23, None, Node(37, Node(29, None, Node(31)), Node(41))), Node(47, None, Node(53)) )
tree = Node(19, left, right)
print_levels_tree(tree)

che consente di stampare qualcosa del tipo:

19  
7  43  
3  11  23  47  
2  5  17  37  53  

Se si desidera utilizzare un separatore \t, sarebbe simile:

19  
7   43  
3   11  23  47  
2   5   17  37  53  

Questa sostanza è disponibile all'indirizzo https://gist.github.com/lopespm/993f0af88cf30b7f8c9e17982518b71b

Una versione che non richiede capacità di archiviazione:

std::deque<Node> bfs;
bfs.push_back(start);
int nodesInThisLayer = 1;
int nodesInNextLayer = 0;
while (!bfs.empty()) {
    Node front = bfs.front();
    bfs.pop_front();
    for (/*iterate over front's children*/) {
        ++nodesInNextLayer;
        nodes.push_back(child);
    }
    std::cout << node.value;
    if (0 == --nodesInThisLayer) {
        std::cout << std::endl;
        nodesInThisLayer = nodesInNextLayer; 
        nodesInNextLayer = 0;
    } else {
        std::cout << " ";
    }
}

P.S. dispiace per il codice C ++, io non sono molto fluente in Python ancora.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top