我怎样才能显示一种二重树拼贴猜想?

时间:2016-12-29 11:15:01

标签: c++ math console

我已经创建了一个程序,可以生成一个链接列表,其中包含了collat​​z猜想"树"如下图所示:

Collatz tree

我希望我的链表能够在终端中显示如下:

  1  
  |  
  2  
  |  
  4  
  |  
  8  
  |  
 16  
  |   \  
 32    5  
  |    |  
 64   10

但我不知道如何继续。

This是我为生成系列而创建的代码。

注意:

  • splitter是产生两个指向它的数字的数字。
  • 如果数字不是分割器,则奇数指针为NULL

2 个答案:

答案 0 :(得分:1)

在等待@RoryDaulton承诺的Python解决方案时,这是一个100%标准的C ++解决方案,用于创建基于二叉树算法的控制台树。

第1步 - 在添加ConsoleTree class之前,有必要在现有算法中添加一些元素。

  

添加全局ndigit整数以自动调整长度   树的分支。

int limit, total = 1;
int ndigit = 1; // minimum number of digit
  

添加字段layer整数以存储分支位置。

struct num {
    int n;
    int layer; // store the layer (start from 0)
    num *even;
    num *odd;
};
  

提取要显示的较大值以计算其数量   数字。

num *newnum(int x=1) {
    num *t = new num;

    t->n =x;
    ndigit = max(ndigit,x); // keep the greater value
    t->layer = 0;
    t->even=NULL;
    t->odd=NULL;
    return t;
}
  

generator()函数中添加图层值。

    //...
    en->layer = front->layer + 1; // next layer on even
    on->layer = front->layer + 1; // next layer on odd
    front -> even = en;
    front -> odd = on;
    //...
    t->layer = front->layer + 1; // next layer
    front -> even = t;
    //...

第2步 - ConsoleTree class来管理树的数字和分支。

class ConsoleTree {
private:
    int iSize;
    string *sDigitLines;
    string *sTreeLines;
protected:
    string FmtInt(int ival,int idigit,char cFill);
    string FmtTree(int idigit, bool bBranch);
    string ShiftRight(string& sLine, int ipos, int idigit);
public:
    ConsoleTree(int iLimit);
    ~ConsoleTree();
    int NbDigit(int x);
    void Make(num *pTree);
    void Print();
};

// Constructor to allocate the number of lines to be displayed
// sDigitLines array is dedicated to numbers
// sTreeLines array is dedicated to branches
ConsoleTree::ConsoleTree(int iLimit)
{
    iSize = iLimit+1;
    sDigitLines = new string[iSize];
    sTreeLines = new string[iSize];
}

// delete arrays
ConsoleTree::~ConsoleTree()
{
    delete[] sDigitLines;
    delete[] sTreeLines;
}

// format the numbers for sDigitLines
string ConsoleTree::FmtInt(int ival,int idigit,char cFill)
{
    ostringstream strStream;

    strStream << std::setfill(cFill) << std::setw(idigit) << (ival);
    return (strStream.str());
}

// format the tree & branches for sTreeLines
string ConsoleTree::FmtTree(int idigit, bool bBranch)
{
    ostringstream strStream;

    strStream << std::string(idigit-1, ' ') << "|";
    if (bBranch) strStream << std::string(idigit-2, '-') << "\\ ";
    return (strStream.str());
}

// Shift numbers & branches when adding new branches
string ConsoleTree::ShiftRight(string& sLine, int ipos, int idigit)
{
    int ilen = sLine.length();
    string sTemp;

    sTemp = sLine.substr(0,ipos);
    if ((ilen>ipos) && (sLine[ipos]=='-')) {
        sTemp += string(idigit, '-');
    }
    else {
        sTemp += string(idigit, ' ');
    }
    if (ilen>ipos) {
        sTemp += sLine.substr(ipos,ilen);
    }
    sLine = sTemp;
    return (sLine);
}

// compute the number of digit
int ConsoleTree::NbDigit(int x)
{
    ostringstream stmp;

    stmp << x;
    return (stmp.str().length()+1);
}

// recurrent function to create tree with numbers and branches
void ConsoleTree::Make(num *pn)
{
    int iLevel,iLen,iCut;
    string sTemp;

    while (pn!=NULL) {
        iLevel = pn->layer;
        sDigitLines[iLevel] += FmtInt(pn->n,ndigit,' ');
        if (pn->odd!=NULL) {
            iCut = sTreeLines[iLevel].length()+ndigit;
            sTreeLines[iLevel] += FmtTree(ndigit,true);
            for(int i=0;i<iLevel;i++) {
                sDigitLines[i] = ShiftRight(sDigitLines[i],iCut,ndigit);
                sTreeLines[i] = ShiftRight(sTreeLines[i],iCut,ndigit);
            }
            sDigitLines[iLevel] = ShiftRight(sDigitLines[iLevel],iCut,ndigit);
            Make(pn->odd);
        }
        else {
            sTreeLines[iLevel] += FmtTree(ndigit,false);
        }
        pn = pn->even;
    }
}

void ConsoleTree::Print()
{
    int iLimit = iSize -1;

    cout << "treeview" << endl;
    for(int i=0;i<iLimit;i++) {
        cout << sDigitLines[i] << endl;
        cout << sTreeLines[i] << endl;
    }
    cout << sDigitLines[iLimit] << endl;
}

第3步 - 然后修改main()功能,以便在使用generator()后显示树。

int main() {
    limit = 12; // define the height of the tree
    ndigit = 0;

    generator();

    num *pn = start; // first node of the binary-tree

    ConsoleTree myTree(limit);

    ndigit = myTree.NbDigit(ndigit);
    myTree.Make(pn);
    myTree.Print();

    cout << total << endl;

    return 0;
}

第4步 - 输出样本(限制= 12)

    1
    |
    2
    |
    4
    |
    8
    |
   16
    |-----------------------\
    5                       32
    |                        |
   10                       64
    |---\                    |---\
    3   20                  21  128
    |    |                   |    |
    6   40                  42  256
    |    |--------\          |    |--------\
   12   13        80        84   85       512
    |    |         |         |    |         |
   24   26       160       168  170      1024
    |    |         |---\     |    |         |---\
   48   52        53  320  336  340       341 2048
    |    |---\     |    |    |    |---\     |    |
   96   17  104  106  640  672  113  680  682 4096

增强功能 - 使用半图形扩展ASCII字符更改控制台树的外观

  

ConsoleTree::FmtTree()函数中,使用一组4扩展   ASCII {195,179&amp; 196,191}。

#ifdef EXTEND_ASCII
    strStream << string(idigit-1, ' ') << string(1,((bBranch)?(195):(179)));
    if (bBranch) strStream << string(idigit-1, 196) << string(1, 191);
#else
    strStream << std::string(idigit-1, ' ') << "|";
    if (bBranch) strStream << std::string(idigit-2, '-') << "\\ ";
#endif
  

ConsoleTree::ShiftRight()函数中,使用扩展ASCII   而不是'-'

#ifdef EXTEND_ASCII
    // Warning: 196 is used as unsigned char ==> cast
    if ((ilen>ipos) && ((unsigned char)sLine[ipos]==196)) {
        sTemp += string(idigit, 196);
    }
#else
    if ((ilen>ipos) && (sLine[ipos]=='-')) {
        sTemp += string(idigit, '-');
    }
#endif
  

输出样本(限制= 7)

   1
   │
   2
   │
   4
   │
   8
   │
  16
   ├───────┐
   5      32
   │       │
  10      64
   ├───┐   ├───┐
   3  20  21 128

答案 1 :(得分:1)

这是用于将Collat​​z二叉树打印到控制台的Python代码。填写Collat​​z树的第一部分是递归的。第二次打印结构不是递归的,我对该代码不满意 - 但它做了我想要的。印刷可以是&#34; kerned&#34;将一些列移近一些并且移动一些水平空间。如果您希望按照示例输出中的顺序排列列,请在例程ndiv3的大2*n部分中交换iffillthe rest()个参数。

"""Print a representation of a Collatz binary tree to the console."""

# Define each column (a list) in `columns`.
STARTROW = 0    # index of zero-based row where a column starts (int)
WIDTH = 1       # index of char width of max number in the column so far (int)
NUMBERS = 2     # index of the numbers in the column (list of ints)

def numstr(num):
    """Return a number string, properly formatted with commas"""
    return '{:,}'.format(num)

def fillnewcolumn(num, row, columns, dontuse, limit):
    """Fill a new column, starting with number `num` in row `row` of
    the partially-filled structure 'columns', not using the numbers in
    `dontuse`, up to row 'limit'."""
    dontuse.add(num)  # mark num as used
    columns.append([row, len(numstr(num)), [num]])  # top non-blank row of col
    filltherest(row, columns, dontuse, limit)  # keep going

def filloldcolumn(num, row, columns, dontuse, limit):
    """Fill the old column, starting with number `num` in row `row` of
    the partially-filled structure 'columns', not using the numbers in
    `dontuse`, up to row 'limit'."""
    dontuse.add(num)  # mark num as used
    thiscolumn = columns[-1]  # last column so far
    thiscolumn[WIDTH] = max(thiscolumn[WIDTH], len(numstr(num)))
    thiscolumn[NUMBERS].append(num)  # add num to column
    filltherest(row, columns, dontuse, limit)  # keep going

def filltherest(row, columns, dontuse, limit):
    """Fill the rest of the partially-filled structure 'columns' which
    already has used the numbers in `used`, from row 'row' in column
    `col`."""
    if limit <= 1:
        return
    thiscolumn = columns[-1]  # last column so far
    n = thiscolumn[NUMBERS][-1]  # last number in this column
    ndiv3, nmod3 = divmod(n, 3)
    if nmod3 == 1 and ndiv3 % 2 != 0 and ndiv3 not in dontuse:  # two branches
        filloldcolumn(ndiv3, row+1, columns, dontuse, limit-1)
        fillnewcolumn(2*n, row+1, columns, dontuse, limit-1)
    else:  # one branch from here
        filloldcolumn(2*n, row+1, columns, dontuse, limit-1)

limit = int(input('How many levels of Collatz to print? '))

# Fill the structure.
columns = []            # information for the overall structure to print
dontuse = {0}           # numbers to not add to the structure
fillnewcolumn(1, 0, columns, dontuse, limit)

# Print the structure to the console.
for row in range(limit):
    numline = ''
    diagline = ''
    for column in columns:
        startingrow = column[STARTROW]
        numwidth = column[WIDTH]
        if startingrow <= row:
            nstr = numstr(column[NUMBERS][row-startingrow])
            numline += nstr.rjust(numwidth) + ' '
            if startingrow == row:
                blanks = ' ' * (len(nstr) + 1)
                oldlinesize = len(numline)
                diagline = diagline.rstrip() + '\\'
                dellinesize = oldlinesize - len(diagline)
                diagline += blanks.rjust(dellinesize, '_')
            else:
                diagline += '|'.rjust(numwidth) + ' '
        else:
            numline += ''.rjust(numwidth) + ' '
            diagline += ''.rjust(numwidth) + ' '
    if row > 0:
        print(diagline.rstrip())
    print(numline.rstrip())

以下是上述代码中15行的输出。

  1
  |
  2
  |
  4
  |
  8
  |
 16
  |\___________________________________
  5                                    32
  |                                     |
 10                                    64
  |\                                    |\
  3 20                                 21 128
  |  |                                  |   |
  6 40                                 42 256
  |  |\____________                     |   |\__________________
 12 13             80                  84  85                   512
  |  |              |                   |   |                     |
 24 26            160                 168 170                 1,024
  |  |              |\____              |   |                     |\______
 48 52             53     320         336 340                   341       2,048
  |  |\___          |       |           |   |\______              |           |
 96 17    104     106     640         672 113       680         682       4,096
  |  |      |       |\      |\          |   |         |           |\          |\_
192 34    208      35 212 213 1,280 1,344 226     1,360         227 1,364 1,365  8,192
  |  |\     |\      |   |   |     |     |   |\        |\          |     |     |      |
384 11 68  69 416  70 424 426 2,560 2,688  75 452   453 2,720   454 2,728 2,730 16,384

如果切换列的顺序,这里是15行的输出。图案更规则,最终占用更少的水平空间。

     1
     |
     2
     |
     4
     |
     8
     |
    16
     |\___________________________________________
    32                                            5
     |                                            |
    64                                           10
     |\____________________________________       |\__________________________
   128                                     21    20                           3
     |                                      |     |                           |
   256                                     42    40                           6
     |\___________________                  |     |\____________              |
   512                    85               84    80             13           12
     |                     |                |     |              |            |
 1,024                   170              168   160             26           24
     |\________            |                |     |\_____        |            |
 2,048         341       340              336   320      53     52           48
     |           |         |\____           |     |       |      |\___        |
 4,096         682       680     113      672   640     106    104    17     96
     |\          |\        |       |        |     |\      |\     |     |      |
 8,192 1,365 1,364 227 1,360     226    1,344 1,280 213 212 35 208    34    192
     |     |     |   |     |\      |\       |     |   |   |  |   |\    |\     |
16,384 2,730 2,728 454 2,720 453 452 75 2,688 2,560 426 424 70 416 69 68 11 384