废话不多说,直接上代码。工程中一共三个文件:main.cpp、MyNode.h、MyNode.cpp。二叉树采用类的方式进行创建。
//main.cpp函数
#include<iostream>
#include "MyNode.h"
using namespace std;
int main()
{
MyNode *head = new MyNode(1);
head->left = new MyNode(-222222222);
head->right = new MyNode(3);
head->left->left = new MyNode(8888);
head->right->left = new MyNode(55555555);
head->right->right = new MyNode(66);
head->left->left->right = new MyNode(777);
cout << "*********直观打印二叉树*********\n";
MyNode::printTree(head);
cout << "*********前序打印二叉树*********\n";
MyNode::print_pre(head);
cout << "\n*********中序打印二叉树*********\n";
MyNode::print_mid(head);
cout << "\n*********后序打印二叉树*********\n";
MyNode::print_later(head);
return 0;
}
//MyNode.h文件
#include <iostream>
#include <string>
#include <stack>//栈的头文件
using namespace std;
class MyNode
{
public:
//构造函数
MyNode(int data);
//析构函数
~MyNode();
static string getSpace(int num);//获取一定空间函数,看起来更加好看,防止数据之间长短不一,造成错位
static void printInOrder(MyNode *head, int height, string to, int len);
//直观打印二叉树
static void printTree(MyNode *head);//这里一定要加static,否则报错
//前序打印二叉树
static void print_pre(MyNode *head);
//中序打印二叉树
static void print_mid(MyNode *head);
//后序打印二叉树
static void print_later(MyNode *head);
//成员变量
int value;
MyNode *left;
MyNode *right;
};
//MyNode.cpp文件
#include "MyNode.h"
//构造函数的定义
MyNode::MyNode(int data)
{
this->value = data;
this->left = NULL;
this->right = NULL;
}
//获取一定空间函数,看起来更加好看【不必纠结】
string MyNode::getSpace(int num) {
string result = "";
for (int i = 0; i < num; i++) {
result.append(" ");//追加字符或字符串
}
return result;
}
//遍历二叉树
void MyNode::printInOrder(MyNode *head, int height, string to, int len) {
if (head == NULL) {
return;
}
printInOrder(head->right, height + 1, "v", len);//右子树
string val = to + to_string(head->value) + to;//to_string函数将数值转化为字符串。返回对应的字符串
int lenM = val.length();
int lenL = (len - lenM) / 2;
int lenR = len - lenM - lenL;
val = getSpace(lenL) + val + getSpace(lenR);
cout << (getSpace(height * len) + val) << "\n";
printInOrder(head->left, height + 1, "^", len);//左子树
}
//打印二叉树
void MyNode::printTree(MyNode *head) {
printInOrder(head, 0, "H", 17);
cout << endl;
}
//前序遍历的方式打印树的结点数据【非递归】
void MyNode::print_pre(MyNode *head)
{
if(head == NULL)
return;
stack<MyNode*> s;
s.push(head);
while(!s.empty())
{
head = s.top();
cout << head->value << " ";//返回第一个元素(栈顶元素)
s.pop();//出栈操作(删除栈顶),只是出栈,没有返回值
if(head->right != NULL)
{
s.push(head->right);
}
if(head->left != NULL)
{
s.push(head->left);
}
}
}
/**中序遍历的方式打印树的结点数据【非递归】
*当前结点为空的话,先打印,然后当前结点右移【即变为原结点的右孩子】
*当前结点不为空的话,当前结点压入栈中,然后当前结点左移【即变为原结点的左孩子】
*/
void MyNode::print_mid(MyNode *head)
{
if(head != NULL)
{
stack<MyNode*> s;//申请一个存储树的栈
while( !s.empty() || head != NULL)
{
if(head != NULL)
{
s.push(head);
head = head->left;
}
else
{
head = s.top();
cout << head->value << " ";//返回第一个元素(栈顶元素)
s.pop();//出栈操作(删除栈顶),只是出栈,没有返回值
head = head->right;
}
}
}
}
/** 后序遍历的方式打印树的结点数据【非递归】
* 由前序遍历的打印顺序可知为:中左右。很容易实现打印顺序为:中右左
* 实现打印顺序为中右左后,元素把打印而是把其压入一个栈中,当所有的树结点遍历完了
* 最后从栈中弹出,打印得到的顺序即为:左右中
*/
void MyNode::print_later(MyNode *head)
{
if(head != NULL)
{
stack<MyNode*> s;//申请一个存储树的栈
stack<MyNode*> S2;//临时栈
s.push(head);
while( !s.empty())
{
head = s.top();
//cout << T->data << " ";//返回第一个元素(栈顶元素)
//这里不打印,而是将树的结点压入栈中
S2.push(head);
s.pop();//出栈操作(删除栈顶),只是出栈,没有返回值
if(head->left != NULL)
{
s.push(head->left);
}
if(head->right != NULL)
{
s.push(head->right);
}
}
while( !S2.empty())
{
head = S2.top();
cout << head->value << " ";//返回第一个元素(栈顶元素)
S2.pop();//出栈操作(删除栈顶),只是出栈,没有返回值
}
}
}
//析构函数定义
MyNode::~MyNode()
{
}
最终运行的结果如下所示:【直观打印的二叉树需要把你的脑袋瓜逆时针转九十度。】
怎么清晰地确定任何一个节点的父节点呢?
(1)如果一个节点打印结果的前缀与后缀都有“H",说明这个节点是头节点
(2)如果一个节点打印结果的前缀与后缀都有“v”,表示父节点在该节点所在列的前一列, 在该节点所在行的下方,并且是离该节点最近的节点。“v3v”、“v66v”和“v777v", 父节点分别为“HIH",“v3v”和“^8888^”。
(3)如果一个节点打印结果的前缀与后缀都有“^”,表示父节点在该节点所在列的前一列, 在该节点所在行的上方,并且是离该节点最近的节点。^-222222222^、^55555555^、^8888^,父节点分别为HIH、v3v、^-222222222^