打印完整的递归调用栈

之前在写0-1背包问题的递归解法时,想要弄出完整的递归栈。尝试了使用debug工具手工追踪并画出调用栈,发现太麻烦了,又试了一下使用visual studio的code map功能,发现对于递归,它只会显示递归函数不断调用自己,并不会自动展开成为树的形式。所以我就使用了最简陋的办法,就是自己写了一个类,依赖C++的constructor和destructor来自动将栈输入到一个vector中,并且在main函数结束的地方添加一个语句将其内容输出到文件中。

这里使用了一些C++11的特性,我使用mingw和msvc2015编译通过了,其它的编译器就不知道了。

下面是这个类的代码,写的很不完善:

//stacktrace.h
  1. #ifndef STACKTRACE_H
  2. #define STACKTRACE_H
  3. #include <iostream>
  4. #include <string>
  5. #include <vector>
  6. /**
  7. * 这个类还比较简单粗暴,没有实现字符串格式化参数的软编码(如果需要可以使用boost::format()来像sprintf()一样格式化),
  8. * 也没有作为模板类实现以完成可变形参构造函数(注意不要使用C语言的va_arg)。
  9. * 使用的时候需要根据需求进行修改。
  10. *
  11. * 使用方法:
  12. * 在main函数中setSpaceLength(unsigned length)来控制格式,如果不做这一步,则默认spaceLength = 4
  13. * 在需要进行stack trace的函数所在的文件中include "stacktrace.h"
  14. * 在需要进行stack trace的函数开头加上一句 StackTrace(capacity, itemNum); capacity和itemNum是需要打印到stack trace的数据
  15. * 在main函数的结尾加上一句writeToFile(std::ostream &os, StackTrace::outputType type = reformat);
  16. *
  17. * 如果需要修改这个类的显示效果,只需要修改 StackTrace(double capacity, int itemNum);
  18. * 注意:每一行的结束需要写入一个换行符
  19. *
  20. */
  21. class StackTrace
  22. {
  23. private: //private data field
  24. static int depth;
  25. static std::vector<std::string> content;
  26. static unsigned spaceLength;
  27. static std::vector<unsigned> firstNotSpace;
  28. public: //public data field
  29. enum outputType{raw,reformat};
  30. public: //constructor and copy control
  31. StackTrace(double capacity, int itemNum);
  32. virtual ~StackTrace()
  33. {
  34. --depth;
  35. }
  36. public: //public member function
  37. static void setSpaceLength(unsigned length);
  38. static void writeToFile(std::ostream &os, outputType type = reformat);
  39. private: //private member function
  40. static void clear();
  41. static void outputResult(std::ostream &os);
  42. static void generateFirstNotSpace();
  43. static void textReplace();
  44. };
  45. #endif // RECURSIONSTACKTRACE_H

//stacktrace.cpp
  1. #include "stacktrace.h"
  2. #include <sstream>
  3. #include <iostream>
  4. #include <vector>
  5. #include <string>
  6. #include <fstream>
  7. #include <cstdlib>
  8. using namespace std;
  9. int StackTrace::depth = 0;
  10. std::vector<std::string> StackTrace::content;
  11. unsigned StackTrace::spaceLength = 4;
  12. std::vector<unsigned> StackTrace::firstNotSpace;
  13. void StackTrace::clear()
  14. {
  15. content.clear();
  16. firstNotSpace.clear();
  17. }
  18. void StackTrace::setSpaceLength(unsigned length)
  19. {
  20. spaceLength = length;
  21. }
  22. StackTrace::StackTrace(double capacity, int itemNum)
  23. {
  24. ++depth;
  25. ostringstream temp;
  26. int i;
  27. for(i = 0;i<depth-1;++i)
  28. {
  29. for(unsigned j= 0;j<spaceLength;++j)
  30. temp << " ";
  31. //cout << " ";
  32. }
  33. if(i<depth)
  34. {
  35. if(spaceLength==0)
  36. ; //null statement
  37. else
  38. {
  39. temp << "└";
  40. for(unsigned j=0; j<spaceLength-1; ++j)
  41. temp << "-";
  42. }
  43. }
  44. temp << "(" << itemNum << ", " << capacity << ")" << endl;
  45. content.push_back(temp.str());
  46. }
  47. void StackTrace::writeToFile(std::ostream &os, outputType type)
  48. {
  49. if(type == reformat)
  50. {
  51. generateFirstNotSpace();
  52. textReplace();
  53. }
  54. outputResult(os);
  55. clear();
  56. }
  57. void StackTrace::outputResult(ostream &os)
  58. {
  59. for(const string &temp:content)
  60. os << temp;
  61. os << flush;
  62. }
  63. void StackTrace::generateFirstNotSpace()
  64. {
  65. for(size_t i= 0; i<content.size();++i)
  66. firstNotSpace.push_back(content[i].find_first_not_of(' '));
  67. }
  68. void StackTrace::textReplace()
  69. {
  70. for(size_t i=1; i<content.size();++i)
  71. {
  72. size_t pos = 0;
  73. while((pos = content[i].find("└",pos)) != string::npos)
  74. {
  75. for(int j = i-1;j>=0;--j)
  76. {
  77. if(firstNotSpace[j]==string::npos)
  78. continue;
  79. if(firstNotSpace[j] <= pos )
  80. goto END2LOOP;
  81. else
  82. {
  83. content[j][pos] = '|';
  84. continue;
  85. }
  86. }
  87. }
  88. END2LOOP: ;
  89. }
  90. }

以下是结果范例:
  1. └---(5, 3)
  2. └---(4, 1)
  3. | └---(3, 0)
  4. | └---(3, 1)
  5. | └---(2, 1)
  6. | └---(1, 0)
  7. | └---(1, 1)
  8. | └---(0, 0.9)
  9. | | └---(-1, 0.6)
  10. | | └---(-1, 0.9)
  11. | └---(0, 1)
  12. | └---(-1, 0.7)
  13. | └---(-1, 1)
  14. └---(4, 3)
  15. └---(3, 2)
  16. | └---(2, 2)
  17. | └---(1, 1)
  18. | | └---(0, 0.9)
  19. | | | └---(-1, 0.6)
  20. | | | └---(-1, 0.9)
  21. | | └---(0, 1)
  22. | | └---(-1, 0.7)
  23. | | └---(-1, 1)
  24. | └---(1, 2)
  25. | └---(0, 1.9)
  26. | | └---(-1, 1.6)
  27. | | └---(-1, 1.9)
  28. | └---(0, 2)
  29. | └---(-1, 1.7)
  30. | └---(-1, 2)
  31. └---(3, 3)
  32. └---(2, 3)
  33. └---(1, 2)
  34. | └---(0, 1.9)
  35. | | └---(-1, 1.6)
  36. | | └---(-1, 1.9)
  37. | └---(0, 2)
  38. | └---(-1, 1.7)
  39. | └---(-1, 2)
  40. └---(1, 3)
  41. └---(0, 2.9)
  42. | └---(-1, 2.6)
  43. | └---(-1, 2.9)
  44. └---(0, 3)
  45. └---(-1, 2.7)
  46. └---(-1, 3)



这里有别人写的类似的类:





posted @ 2015-06-23 22:09  cmicat  阅读(591)  评论(0编辑  收藏  举报