打印完整的递归调用栈
之前在写0-1背包问题的递归解法时,想要弄出完整的递归栈。尝试了使用debug工具手工追踪并画出调用栈,发现太麻烦了,又试了一下使用visual studio的code map功能,发现对于递归,它只会显示递归函数不断调用自己,并不会自动展开成为树的形式。所以我就使用了最简陋的办法,就是自己写了一个类,依赖C++的constructor和destructor来自动将栈输入到一个vector中,并且在main函数结束的地方添加一个语句将其内容输出到文件中。
这里使用了一些C++11的特性,我使用mingw和msvc2015编译通过了,其它的编译器就不知道了。
下面是这个类的代码,写的很不完善:
//stacktrace.h
#ifndef STACKTRACE_H
#define STACKTRACE_H
#include <iostream>
#include <string>
#include <vector>
/**
* 这个类还比较简单粗暴,没有实现字符串格式化参数的软编码(如果需要可以使用boost::format()来像sprintf()一样格式化),
* 也没有作为模板类实现以完成可变形参构造函数(注意不要使用C语言的va_arg)。
* 使用的时候需要根据需求进行修改。
*
* 使用方法:
* 在main函数中setSpaceLength(unsigned length)来控制格式,如果不做这一步,则默认spaceLength = 4
* 在需要进行stack trace的函数所在的文件中include "stacktrace.h"
* 在需要进行stack trace的函数开头加上一句 StackTrace(capacity, itemNum); capacity和itemNum是需要打印到stack trace的数据
* 在main函数的结尾加上一句writeToFile(std::ostream &os, StackTrace::outputType type = reformat);
*
* 如果需要修改这个类的显示效果,只需要修改 StackTrace(double capacity, int itemNum);
* 注意:每一行的结束需要写入一个换行符
*
*/
class StackTrace
{
private: //private data field
static int depth;
static std::vector<std::string> content;
static unsigned spaceLength;
static std::vector<unsigned> firstNotSpace;
public: //public data field
enum outputType{raw,reformat};
public: //constructor and copy control
StackTrace(double capacity, int itemNum);
virtual ~StackTrace()
{
--depth;
}
public: //public member function
static void setSpaceLength(unsigned length);
static void writeToFile(std::ostream &os, outputType type = reformat);
private: //private member function
static void clear();
static void outputResult(std::ostream &os);
static void generateFirstNotSpace();
static void textReplace();
};
#endif // RECURSIONSTACKTRACE_H
//stacktrace.cpp
#include "stacktrace.h"
#include <sstream>
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <cstdlib>
using namespace std;
int StackTrace::depth = 0;
std::vector<std::string> StackTrace::content;
unsigned StackTrace::spaceLength = 4;
std::vector<unsigned> StackTrace::firstNotSpace;
void StackTrace::clear()
{
content.clear();
firstNotSpace.clear();
}
void StackTrace::setSpaceLength(unsigned length)
{
spaceLength = length;
}
StackTrace::StackTrace(double capacity, int itemNum)
{
++depth;
ostringstream temp;
int i;
for(i = 0;i<depth-1;++i)
{
for(unsigned j= 0;j<spaceLength;++j)
temp << " ";
//cout << " ";
}
if(i<depth)
{
if(spaceLength==0)
; //null statement
else
{
temp << "└";
for(unsigned j=0; j<spaceLength-1; ++j)
temp << "-";
}
}
temp << "(" << itemNum << ", " << capacity << ")" << endl;
content.push_back(temp.str());
}
void StackTrace::writeToFile(std::ostream &os, outputType type)
{
if(type == reformat)
{
generateFirstNotSpace();
textReplace();
}
outputResult(os);
clear();
}
void StackTrace::outputResult(ostream &os)
{
for(const string &temp:content)
os << temp;
os << flush;
}
void StackTrace::generateFirstNotSpace()
{
for(size_t i= 0; i<content.size();++i)
firstNotSpace.push_back(content[i].find_first_not_of(' '));
}
void StackTrace::textReplace()
{
for(size_t i=1; i<content.size();++i)
{
size_t pos = 0;
while((pos = content[i].find("└",pos)) != string::npos)
{
for(int j = i-1;j>=0;--j)
{
if(firstNotSpace[j]==string::npos)
continue;
if(firstNotSpace[j] <= pos )
goto END2LOOP;
else
{
content[j][pos] = '|';
continue;
}
}
}
END2LOOP: ;
}
}
以下是结果范例:
└---(5, 3)
└---(4, 1)
| └---(3, 0)
| └---(3, 1)
| └---(2, 1)
| └---(1, 0)
| └---(1, 1)
| └---(0, 0.9)
| | └---(-1, 0.6)
| | └---(-1, 0.9)
| └---(0, 1)
| └---(-1, 0.7)
| └---(-1, 1)
└---(4, 3)
└---(3, 2)
| └---(2, 2)
| └---(1, 1)
| | └---(0, 0.9)
| | | └---(-1, 0.6)
| | | └---(-1, 0.9)
| | └---(0, 1)
| | └---(-1, 0.7)
| | └---(-1, 1)
| └---(1, 2)
| └---(0, 1.9)
| | └---(-1, 1.6)
| | └---(-1, 1.9)
| └---(0, 2)
| └---(-1, 1.7)
| └---(-1, 2)
└---(3, 3)
└---(2, 3)
└---(1, 2)
| └---(0, 1.9)
| | └---(-1, 1.6)
| | └---(-1, 1.9)
| └---(0, 2)
| └---(-1, 1.7)
| └---(-1, 2)
└---(1, 3)
└---(0, 2.9)
| └---(-1, 2.6)
| └---(-1, 2.9)
└---(0, 3)
└---(-1, 2.7)
└---(-1, 3)
这里有别人写的类似的类: