Распечатать массив кучи в формате дерева

0

Поэтому я пытался реализовать алгоритм вывода массива кучи в формате дерева. Например, если у меня есть массив вроде A [10,6,8,2,4,3,6,0,1,3,2,2,1,0,2], я бы хотел, чтобы результат был следующим:

10-----6-----2-----0
    |     |     |--1
    |     |--4-----3
    |           |--2   
    |--8-----3-----2
          |     |--1
          |--6-----0
                |--2

Обновление: решил мой вопрос, я сделал ответ с кодом для тех, кого это интересует.

  • 0
    Я бы использовал символьную матрицу для хранения вывода, поэтому у вас есть произвольный доступ на запись в выходной буфер. Тогда у вас может быть такая функция, как int render(rootNode, x, y) которая рисует поддерево в точке (x,y) и возвращает «высоту» вывода. Вы можете использовать это рекурсивно, чтобы построить дерево.
  • 0
    Хм, это может на самом деле сделать свое дело. Работа с матрицей, безусловно, облегчит работу, учитывая, что строки / столбцы и родительские позиции могут быть известны из размера массива. Это потенциально слишком дорого, хотя память.
Показать ещё 1 комментарий
Теги:

3 ответа

0
Лучший ответ

Вот окончательная реализация. Форматирование весов с длиной номера.

#include <string>
#include <vector>
#include <iostream>
#include <algorithm>

std::string do_padding (unsigned index, unsigned mlength){
  std::string padding;
  if (int((index-1)/2) != 0){
    return (int((index-1)/2) % 2 == 0) ?
    (do_padding(int((index-1)/2),mlength) + std::string(mlength+4,' ') + " ")  :
    (do_padding(int((index-1)/2),mlength) + std::string(mlength+3,' ') + " |") ;
  }
  return padding;
}


void printer (std::vector<int> const & tree, unsigned index, unsigned mlength){
  auto last = tree.size() - 1 ;
  auto  left = 2 * index + 1 ;
  auto  right = 2 * index + 2 ;
  std::cout << " " << tree[index] << " ";
  if (left <= last){
    auto llength = std::to_string(tree[left]).size();
    std::cout << "---" << std::string(mlength - llength,'-');
    printer(tree,left,mlength);
    if (right <= last) {
      auto rlength = std::to_string(tree[right]).size();
      std::cout << "\n" << do_padding(right,mlength) << std::string(mlength+ 3,' ') << " | ";
      std::cout << "\n" << do_padding(right,mlength) << std::string(mlength+ 3,' ') << " └" <<
      std::string(mlength - rlength,'-');
      printer(tree,right,mlength);
    }
  }
}


void print_tree (std::vector<int> & tree){
  unsigned mlength = 0;
  for (int & element : tree){
    auto clength = std::to_string(element).size();
    if (clength > mlength) {
      mlength = std::to_string(element).size();
    }
  }
  std::cout <<  std::string(mlength- std::to_string(tree[0]).size(),' ');
  printer(tree,0,mlength);
}

int main() {
  std::vector<int> test;
  for(auto i =0; i<50; ++i){
    test.push_back(rand() % 1000 + 1);
  }
  std::make_heap(test.begin(),test.end());
  std::cout << "\n";
  print_tree(test);
}
2

Возможное решение состоит в том, чтобы вставить заполнители в массив и, таким образом, сформировать матрицу MxN, если она. Затем вы можете просто контактировать с ним, вставить фид строки после каждой строки и ящиков с отступом, имеющих местозаполнитель.

  • 0
    Это интересный подход. Я постараюсь обернуть голову вокруг этого.
1

Эта программа С++ 11 выводит кучу в немного другом формате:

//              10              
//      ||--------------||      
//       6               8      
//  ||------||      ||------||  
//   2       4       3       6  
//||--||  ||--||  ||--||  ||--||
// 0   1   3   2   2   1   0   2

#include<iostream>
#include<vector>
#include<sstream>
#include<string>
#include<cmath>
#include<iomanip>

// http://stackoverflow.com/questions/994593/how-to-do-an-integer-log2-in-c
// will be used to compute height of the heap
size_t IntegerLogarithm2(size_t arg) {
  size_t logarithm = 0;
  while (arg >>= 1) ++logarithm;
  return logarithm;
}   

// will be used to compute number of elements at the level i
size_t IntegerPower2(size_t arg) {
  if(arg)
    return (size_t)2 << (arg-1);
  else
    return 1;
}   

// returns total line length for the level
size_t LineLength(size_t level, size_t item_width, size_t spaces_between) {
  return IntegerPower2(level) * (item_width + spaces_between) - spaces_between;
}   

int main()
{
  // The input heap array
  std::vector<int> A = {10, 6, 8, 2, 4, 3, 6, 0, 1, 3, 2, 2, 1, 0, 2};
  // The heap array split by levels
  std::vector<std::vector<int> > levels;

  // Height of the heap
  size_t levels_number = IntegerLogarithm2(A.size() + 1);
  levels.resize(levels_number);

  // Now fill the levels
  for (size_t i = 0; i < levels.size(); ++i) {
    size_t elements_number = IntegerPower2(i);
    levels[i].resize(elements_number);
    for (size_t j = elements_number - 1, p = 0; p < elements_number; ++j, ++p)
      levels[i][p] = A[j];
  }   

  if (levels_number < 1) return 0;

  int magnitude = (abs(A[0]) <= 1 ? 1 : abs(A[0]));
  size_t tab_width = (size_t)floor(log(double(magnitude)) / log(10.0)) + 1;
  // size_t longest_line = LineLength(levels_number - 1, tab_width, tab_width);
  std::vector<std::string> text;
  text.reserve(levels_number * 2 - 1); 

  // Do the aligned output to the strings array
  for (size_t i = 0; i < levels_number; ++i) {
    size_t outer_space_width = IntegerPower2(levels_number - 1 - i) - 1;
    size_t inner_space_width = outer_space_width * 2 + 1;
    std::string outer_space(outer_space_width * tab_width, ' ');
    std::string inner_space(inner_space_width * tab_width, ' ');

    std::ostringstream line;
    line << outer_space;

    if (i > 0) {
      std::ostringstream branchline;
      std::string joint(tab_width, '|');
      std::string branch(inner_space_width * tab_width, '-');

      branchline << outer_space;

      if (levels[i].size() > 0) {
        branchline << joint;
      }

      bool isline = true;
      for (size_t j = 1; j < levels[i].size(); ++j, isline = !isline) {
        if(isline)
          branchline << branch << joint;
        else
          branchline << inner_space << std::setfill(' ') <<
              std::setw(tab_width) << joint;
      }

      branchline << outer_space;
      text.push_back(branchline.str());
    }

    if (levels[i].size() > 0) {
      line << std::setfill(' ') << std::setw(tab_width) << levels[i][0];
    }

    for (size_t j = 1; j < levels[i].size(); ++j) {
      line << inner_space << std::setfill(' ') <<
          std::setw(tab_width) << levels[i][j];
    }

    line << outer_space;
    text.push_back(line.str());
  }

  // Output the text
  for (auto& i : text)
    std::cout << i << std::endl;

  return 0;
}

Яп, сложнее, чем казалось изначально. Эффективно делает то, что предложил Себастьян Дресслер.

  • 0
    Как видите, реализовать алгоритм с хорошим форматом на самом деле сложнее, чем кажется.
  • 0
    Это работает, только если последний ряд детей достаточно велик, чтобы заполнить его. Лучший ответ. Вы действительно приложили некоторые усилия, и я благодарен за это.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню