我已经创建了一个程序,可以生成一个链接列表,其中包含了collatz猜想"树"如下图所示:
我希望我的链表能够在终端中显示如下:
1
|
2
|
4
|
8
|
16
| \
32 5
| |
64 10
但我不知道如何继续。
This是我为生成系列而创建的代码。
注意:
答案 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)
这是用于将Collatz二叉树打印到控制台的Python代码。填写Collatz树的第一部分是递归的。第二次打印结构不是递归的,我对该代码不满意 - 但它做了我想要的。印刷可以是&#34; kerned&#34;将一些列移近一些并且移动一些水平空间。如果您希望按照示例输出中的顺序排列列,请在例程ndiv3
的大2*n
部分中交换if
和fillthe 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