目录
二叉树的结构:
class Node {
public:
Node(int v) {
value = v;
}
public:
int value;
Node* left;
Node* right;
};
一、非递归形式实现前中后序遍历
1.1 先序遍历
1.弹出就打印
2.如有右,压入右
3.如有左,压入左
void pre(Node* head) {
cout << "前序遍历:" << endl;
if (head != nullptr) {
stack<Node*> stack;
stack.push(head);
while (!stack.empty()) {
head = stack.top();
stack.pop();
cout << head->value << " ";
if (head->right != nullptr) {
stack.push(head->right);
}
if (head->left != nullptr) {
stack.push(head->left);
}
}
}
cout << endl;
}
1.2 后序遍历(用两个栈)
那么 头 右 左 的顺序是不是有点眼熟呢?没错,这不倒过来不就是后序遍历了吗。
1.弹出就放入到第二个栈res中
2.如有左,压入左
3.如有右,压入右
4.最后将res中的全部打印
void pos(Node* head) {
cout << "后序遍历:" << endl;
if (head != nullptr) {
stack<Node*> st1;
stack<Node*> st2;
st1.push(head);
while (!st1.empty()) {
head = st1.top();
st1.pop();
st2.push(head);
if (head->left != nullptr) {
st1.push(head->left);
}
if (head->right != nullptr) {
st1.push(head->right);
}
}
while (!st2.empty()) {
cout << st2.top()->value << " ";
st2.pop();
}
}
cout << endl;
}
1.3 后序遍历(用一个栈)骚操作
只用一个栈去完成
void pos2(Node* h) {
cout<<"后序遍历炫技版: "<<endl;
if (h != nullptr) {
stack<Node*> stack;
stack.push(h);
Node* c = nullptr;
while (!stack.empty()) {
c = stack.top();
//说明这个c的左树都还没处理呢,肯定先要去处理左树
if (c->left != nullptr && h != c->left && h != c->right) {
stack.push(c->left);
}
//说明左树处理了,但右树没有处理,那就去处理右树
else if (c->right != nullptr && h != c->right) {
stack.push(c->right);
}
//左右树都处理完了,那就去处理头
else {
cout << stack.top()->value<<" ";
stack.pop();
h = c;//处理一个,那就让h记录刚处理的位置
}
}
}
cout << endl;
}
1.4中序遍历
1. 将整条左边界依次压入栈
2. 1无法执行了,就弹出栈,并到弹出的右树上继续执行
为什么会这样做呢?
void in(Node* cur) {
cout<<"中序遍历 : "<<endl;
if (cur != nullptr) {
stack<Node*> stack;
while (!stack.empty() || cur != nullptr) {
if (cur != nullptr) {
stack.push(cur);
cur = cur->left;
}
else {
cur = stack.top();
stack.pop();
cout << cur->value << " ";
cur = cur->right;
}
}
}
cout << endl;
}
二、实现二叉树的按层遍历
1、用队列
弹出就打印,先进左树,再进右树
void level(Node* head) {
if (head == nullptr) {
return;
}
queue<Node*> queue;
queue.push(head);
while (!queue.empty()) {
Node* cur = queue.front();
cout << cur->value << " ";
queue.pop();
//System.out.println(cur.value);
if (cur->left != nullptr) {
queue.push(cur->left);
}
if (cur->right != nullptr) {
queue.push(cur->right);
}
}
}
还可以用牛客给的答案的方法:实现之字形打印
vector<vector<int> > levelOrder(TreeNode* root) {
// write code here
vector<vector<int>> vt;
if(root==nullptr)
return vt;
//队列存储,进行层次遍历
queue<TreeNode*> q;
q.push(root);
TreeNode* cur;
while(!q.empty()){
vector<int> temp;
int n=q.size();
for(int i=0;i<n;++i){
cur=q.front();
q.pop();
temp.push_back(cur->val);
if(cur->left)
q.push(cur->left);
if(cur->right)
q.push(cur->right);
}
vt.push_back(temp);//一层都统计完之后再加入
}
return vt;
}
三、统计二叉树最多的层
不仅要打印每一层,还要发现一个层的开始或结束
1、用map
int maxWidthUseMap(Node* head) {
if (head == nullptr) {
return 0;
}
queue<Node*> queue;
queue.push(head);
// key 在 哪一层,value
unordered_map <Node*, int> levelMap;
levelMap.insert(make_pair(head,1));
int curLevel = 1; // 当前你正在统计哪一层的宽度
int curLevelNodes = 0; // 当前层curLevel层,宽度目前是多少
int Max = 0;
while (!queue.empty()) {
Node* cur = queue.front();
queue.pop();
int curNodeLevel = levelMap[cur];//当前的层数
if (cur->left != nullptr) {
levelMap.insert(make_pair(cur->left, curNodeLevel + 1));
queue.push(cur->left);
}
if (cur->right != nullptr) {
levelMap.insert(make_pair(cur->right, curNodeLevel + 1));
queue.push(cur->right);
}
if (curNodeLevel == curLevel) {
curLevelNodes++;
}
else {
Max = max(Max, curLevelNodes);
curLevel++;
curLevelNodes = 1;//刚开始的时候下一层肯定是1
}
}
Max = max(Max, curLevelNodes);
return Max;
}
2、不用map
int maxWidthNoMap(Node* head) {
if (head == nullptr) {
return 0;
}
queue<Node*> queue;
queue.push(head);
Node* curEnd = head; // 当前层,最右节点是谁
Node* nextEnd = nullptr; // 下一层,最右节点是谁
int Max = 0;
int curLevelNodes = 0; // 当前层的节点数
while (!queue.empty()) {
Node* cur = queue.front();
queue.pop();
if (cur->left != nullptr) {
queue.push(cur->left);
nextEnd = cur->left;
}
if (cur->right != nullptr) {
queue.push(cur->right);
nextEnd = cur->right;
}
curLevelNodes++;
if (cur == curEnd) {
Max = max(Max, curLevelNodes);
curLevelNodes = 0;
curEnd = nextEnd;
}
}
return Max;
}
题:给二叉树的某节点,返回它的后继节点
后继节点指他中序遍历的下一个节点
1、暴力:
最简单的方法就是一直去找parent,直到找到父节点,然后中序遍历,找到他的下一个
2、直接去找他的后继
既然是中序遍历,肯定是遵从 左 头 右 的顺序,
那如果一个树有右子树的话,他的后继直接就是右子树最左边的那个子树
如果没有右子树的话,就一直往上去找,直到父子关系是子树是父的左子树,(右子树的话就继续向上)
当然,最后一个节点是没有后继的,必然找不到,那就返回nullptr就是了
代码:
Node* getSuccessorNode(Node* node) {
if (node == nullptr) {
return node;
}
if (node->right != nullptr) {
return getLeftMost(node->right);
}
else { // 无右子树
Node* parent = node->parent;
while (parent != nullptr && parent->right == node) { // 当前节点是其父亲节点右孩子
node = parent; // 那就继续向上去找
parent = node->parent;
}
return parent;
}
}
Node* getLeftMost(Node* node) {
if (node == nullptr) {
return node;
}
while (node->left != nullptr) {
node = node->left;
}
return node;
}
同理,找前驱就是反过来就行了
这棵树其实根本就i不存在,但我用递归模拟了他
明确规定的树,根本不用建树,就可以打印了