二叉树进阶

在这里插入图片描述

欢迎来到Cefler的博客😁
🕌博客主页:那个传说中的man的主页
🏠个人专栏:题目解析
🌎推荐文章:题目大解析(3)

在这里插入图片描述


👉🏻二叉搜索树

概念

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:

  • 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 它的左右子树也分别为二叉搜索树

即:左<根<右

在这里插入图片描述

👉🏻二叉搜索树模拟实现(1)

Insert插入

bool Insert(const K& key)
	{
		if (_root == nullptr)//如果为空直接创建新结点
		{
			_root = new Node(key);
			return true;
		}
		Node* cur = _root;
		Node* parent = nullptr;
		while (cur)//key比当前cur结点的key值小往左边走,大则往右边走,直到遇到空
		{
			parent = cur;
			if (cur->_key < key)
			{
				cur = cur->_right;
			}
			else if (cur->_key > key)

			{
				cur = cur->_left;
			}
			else
			{
				return false;
			}
		}
		cur = new Node(key);//此时遇到空要创建新结点
		//但此时我们还要记得将其与parent连接起来,至于是在parent的左边还是右边,看比大小
		if (parent->_key < key)
		{
			parent->_right = cur;
		}
		else
		{
			parent->_left = cur;
		}
		return true;
	}

过程即为:小于往左走,大于往右走,遇到空创建新结点,进行连接父节点

find查找

bool Find(const K& key)
	{
		Node* cur = _root;
		while (cur)
		{
			if (cur->_key < key)
			{
				cur = cur->_right;
				
			}
			else if (cur->_key > key)
			{
				cur = cur->_left;
			}
			else
				return true;//相等说明找到,返回true
		}
		return false;
	}

中序遍历

void _InOrder(Node* root)//中序遍历
	{
		if (root == nullptr)
			return;
		_InOrder(root->_left);
		cout << root->_key << " ";
		_InOrder(root->_right);

	}
	void InOrder()//套一层
	{
		_InOrder(_root);
		cout << endl;
	}

Erase删除

首先查找元素是否在二叉搜索树中,如果不存在,则返回, 否则要删除的结点可能分下面四种情
况:
a. 要删除的结点无孩子结点
b. 要删除的结点只有左孩子结点
c. 要删除的结点只有右孩子结点
d. 要删除的结点有左、右孩子结点

而a情况可以归属于b和c任意一个情况,a情况当把结点删除后,父节点想向指向左右哪边都行,反正都为空无所谓。

  • 情况b:删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点–直接删除
  • 情况c:删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点–直接删除
  • 情况d:在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点
    中,再来处理该结点的删除问题–替换法删除

替换法删除:
1.要么从左子树中找到最大结点来替换
2.要么从右子树找到最小结点来替换

所以现在梳理一下代码思路
1.先找到要删除的结点位置,能找到再删除,找不到返回false
2.开始删除,判情况(b,c,d),对症下药

代码如下

bool Erase(const K& key)
	{
		Node* cur = _root;
		Node* parent = nullptr;
		while (cur)//寻找要删除的结点
		{	
			if (cur->_key > key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (cur->_key < key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				//找到了就可以开始删除了,但是要判情况,对症下药
				if (cur->_left == nullptr)
				{
					//左边为空,则删除后,将父节点连接cur的右边
					if (cur == _root)//如果要删除的结点就是初始根结点
					{
						_root = cur->_right;
					}
					//先确定此时cur在父节点的左边还是右边
					if (cur == parent->_left)
					{
						parent->_left = cur->_right;
					}
					else
					{
						parent->_right = cur->_right;

					}
					
				}
				else if (cur->_right == nullptr)
				{
					//右边为空
					if (cur == _root)//如果要删除的结点就是初始根结点
					{
						_root = cur->_left;
					}
					if (cur == parent->_left)
					{
						parent->_left = cur->_left;
					}
					else
					{
						parent->_right = cur->_left;

					}
					
				}
				else
				{
					//左右都不为空,此时用替换法
					//这里我们以寻找右边树最小值的替换法执行;而右边树最小值即可以认为就是右边树最左边结点
					Node* parent = cur;
					Node* subleft = cur->_right;
					while (subleft->_left)//当左边遇到空,说明此时subleft已经遍历到最左边
					{
						parent = subleft;
						subleft = subleft->_left;
					}
					//找到后,可以进行交换了
					swap(cur->_key, subleft->_key);
					//现在进行删除,而且删除情况属于a情况
					if (subleft == parent->_left)
					{
						parent->_left = subleft->_right;//这边=subleft->_right或者subleft->_left都可以
					}
					else
					{
						parent->_right = subleft->_right;
					}
					

				}
				return true;
			}
		}
		return false;
	}

InsertR递归插入

bool _InsertR(Node*& root, const K& key)//递归插入
	{
		if (root == nullptr)
		{
			root = new Node(key);//传引用的好处就是此时的root就是其父节点的左/右节点,无需记录父节点
			return true;
		}
		if (root->_key > key)
		{
			_InsertR(root->_left, key);
		}
		else if (root->_key < key)
		{
			_InsertR(root->_right, key);
		}
		else
			return false;

	}

FindR递归查找

bool _FindR(Node* root, const K& key)//递归查找
	{
		if (root == nullptr)
			return false;
		if (root->_key > key)
		{
			FindR(root->_left, key);
		}
		else if (root->_key < key)
		{
			FindR(root->_right, key);
		}
		else
			return true;
	}

EraseR递归删除

bool _EraseR(Node*& root, const K& key)//这里我们仍然用引用root,这样连接时就不用记录父节点了
	{
		if (root == nullptr)
			return false;

		if (root->_key < key)
		{
			return _EraseR(root->_right, key);
		}
		else if (root->_key > key)
		{
			return _EraseR(root->_left, key);
		}
		else
		{
			//开始删除
			if (root->_left == nullptr)
			{
				//左为空
				root = root->_right;
			}
			else if (root->_right == nullptr)
			{
				root = root->_left;
			}
			else
			{
				//左右都不为空
				//这里以寻找右子树最小值
				Node* subleft = root->_right;
				while (subleft->_left)
				{
					subleft = subleft->_left;
				}
				swap(root->_key, subleft->_key);

				// 转换成在子树去递归删除
				return _EraseR(root->_right, key);
			}
		}
	}

析构函数

~BSTree()
	{
		Destroy(_root);
	}
void Destroy(Node*& root)
	{
		if (root == nullptr)
			return;
		Destroy(root->_left);
		Destroy(root->_right);
		delete root;
	}

👉🏻二叉搜索树模拟实现(2)

拷贝构造函数

BTTree(const BSTree<K>& bt)
	{
		_root = Copy(bt._root);
	}
Node* Copy(Node* root)
	{
		if (root == nullptr)
			return nullptr;
		Node* newRoot = new Node(root->_key);
		newRoot->_left = Copy(root->_left);
		
		newRoot->_right = Copy(root->_right);
		return newRoot;
	}

赋值重载运算符

BSTree<K>& operator=(BSTree<K> bt)
	{
		swap(_root, bt._root);
		return *this;
	}

🍒BinarySearchTree.h

#pragma once
#include <iostream>
using namespace std;
template <class K>
struct BSTreeNode
{
	BSTreeNode<K>* _left;
	BSTreeNode<K>* _right;
	K _key;
	BSTreeNode(const K& key)
		:_left(nullptr)
		, _right(nullptr)
		, _key(key)
	{}
};
template <class K>
class BSTree
{
	typedef BSTreeNode<K> Node;
public:
	//构造函数
	BSTree(){}
	//拷贝构造函数
	BSTree(const BSTree<K>& bt)
	{
		_root = Copy(bt._root);
	}
	bool Insert(const K& key)
	{
		if (_root == nullptr)//如果为空直接创建新结点
		{
			_root = new Node(key);
			return true;
		}
		Node* cur = _root;
		Node* parent = nullptr;
		while (cur)//key比当前cur结点的key值小往左边走,大则往右边走,直到遇到空
		{
			parent = cur;
			if (cur->_key < key)
			{
				cur = cur->_right;
			}
			else if (cur->_key > key)

			{
				cur = cur->_left;
			}
			else
			{
				return false;
			}
		}
		cur = new Node(key);//此时遇到空要创建新结点
		//但此时我们还要记得将其与parent连接起来,至于是在parent的左边还是右边,看比大小
		if (parent->_key < key)
		{
			parent->_right = cur;
		}
		else
		{
			parent->_left = cur;
		}
		return true;
	}
	bool Find(const K& key)
	{
		Node* cur = _root;
		while (cur)
		{
			if (cur->_key < key)
			{
				cur = cur->_right;
				
			}
			else if (cur->_key > key)
			{
				cur = cur->_left;
			}
			else
				return true;//相等说明找到,返回true
		}
		return false;
	}
	bool Erase(const K& key)
	{
		Node* cur = _root;
		Node* parent = nullptr;
		while (cur)//寻找要删除的结点
		{	
			if (cur->_key > key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (cur->_key < key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				//找到了就可以开始删除了,但是要判情况,对症下药
				if (cur->_left == nullptr)
				{
					//左边为空,则删除后,将父节点连接cur的右边
					if (cur == _root)//如果要删除的结点就是初始根结点
					{
						_root = cur->_right;
					}
					//先确定此时cur在父节点的左边还是右边
					if (cur == parent->_left)
					{
						parent->_left = cur->_right;
					}
					else
					{
						parent->_right = cur->_right;

					}
					
				}
				else if (cur->_right == nullptr)
				{
					//右边为空
					if (cur == _root)//如果要删除的结点就是初始根结点
					{
						_root = cur->_left;
					}
					if (cur == parent->_left)
					{
						parent->_left = cur->_left;
					}
					else
					{
						parent->_right = cur->_left;

					}
					
				}
				else
				{
					//左右都不为空,此时用替换法
					//这里我们以寻找右边树最小值的替换法执行;而右边树最小值即可以认为就是右边树最左边结点
					Node* parent = cur;
					Node* subleft = cur->_right;
					while (subleft->_left)//当左边遇到空,说明此时subleft已经遍历到最左边
					{
						parent = subleft;
						subleft = subleft->_left;
					}
					//找到后,可以进行交换了
					swap(cur->_key, subleft->_key);
					//现在进行删除,而且删除情况属于a情况
					if (subleft == parent->_left)
					{
						parent->_left = subleft->_right;//这边=subleft->_right或者subleft->_left都可以
					}
					else
					{
						parent->_right = subleft->_right;
					}
					

				}
				return true;
			}
		}
		return false;
	}
	
	void InOrder()//套一层
	{
		_InOrder(_root);
		cout << endl;
	}
	bool FindR(const K& key)
	{
		return _FindR(_root, key);
	}
	bool InsertR(const K& key)
	{
		return _InsertR(_root,key);
	}
	bool EraseR(const K& key)
	{
		return _EraseR(_root, key);
	}
	~BSTree()
	{
		Destroy(_root);
	}
	BSTree<K>& operator=(BSTree<K> bt)
	{
		swap(_root, bt._root);
		return *this;
	}
private:
	Node* Copy(Node* root)
	{
		if (root == nullptr)
			return nullptr;
		Node* newRoot = new Node(root->_key);
		newRoot->_left = Copy(root->_left);
		
		newRoot->_right = Copy(root->_right);
		return newRoot;
	}
	void Destroy(Node*& root)
	{
		if (root == nullptr)
			return;
		Destroy(root->_left);
		Destroy(root->_right);
		delete root;
	}
	bool _EraseR(Node*& root, const K& key)//这里我们仍然用引用root,这样连接时就不用记录父节点了
	{
		if (root == nullptr)
			return false;

		if (root->_key < key)
		{
			return _EraseR(root->_right, key);
		}
		else if (root->_key > key)
		{
			return _EraseR(root->_left, key);
		}
		else
		{
			//开始删除
			if (root->_left == nullptr)
			{
				//左为空
				root = root->_right;
			}
			else if (root->_right == nullptr)
			{
				root = root->_left;
			}
			else
			{
				//左右都不为空
				//这里以寻找右子树最小值
				Node* subleft = root->_right;
				while (subleft->_left)
				{
					subleft = subleft->_left;
				}
				swap(root->_key, subleft->_key);

				// 转换成在子树去递归删除
				return _EraseR(root->_right, key);//root->_right或者root->_left都可以,反正都是空
			}
		}
	}
	bool _InsertR(Node*& root, const K& key)//递归插入
	{
		if (root == nullptr)
		{
			root = new Node(key);//传引用的好处就是此时的root就是其父节点的左/右节点,无需记录父节点
			return true;
		}
		if (root->_key > key)
		{
			_InsertR(root->_left, key);
		}
		else if (root->_key < key)
		{
			_InsertR(root->_right, key);
		}
		else
			return false;

	}
	bool _FindR(Node* root, const K& key)//递归查找
	{
		if (root == nullptr)
			return false;
		if (root->_key > key)
		{
			FindR(root->_left, key);
		}
		else if (root->_key < key)
		{
			FindR(root->_right, key);
		}
		else
			return true;
	}
	void _InOrder(Node* root)//中序遍历
	{
		if (root == nullptr)
			return;
		_InOrder(root->_left);
		cout << root->_key << " ";
		_InOrder(root->_right);

	}
	Node* _root = nullptr;
};

👉🏻二叉搜索树改造key_value模型

概念

KV模型:每一个关键码key,都有与之对应的值Value,即<Key, Value>的键值对。该种方
式在现实生活中非常常见:

  • 比如英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英
    文单词与其对应的中文<word, chinese>就构成一种键值对;
  • 再比如统计单词次数,统计成功后,给定单词就可快速找到其出现的次数,单词与其出
    现次数就是<word, count>就构成一种键值对

模拟实现

#pragma once
#include<iostream>
using namespace std;
namespace kv
{
	template <class K,class V>
	struct BSTreeNode
	{
		BSTreeNode<K,V>* _left;
		BSTreeNode<K,V>* _right;
		K _key;
		V _value;
		BSTreeNode(const K& key,const V& value)
			:_left(nullptr)
			, _right(nullptr)
			, _key(key)
			, _value(value)
		{}
	};
	template <class K,class V>
	class BSTree
	{
		typedef BSTreeNode<K,V> Node;
	public:
		bool Insert(const K& key,const V& value)
		{
			if (_root == nullptr)//如果为空直接创建新结点
			{
				_root = new Node(key,value);
				return true;
			}
			Node* cur = _root;
			Node* parent = nullptr;
			while (cur)//key比当前cur结点的key值小往左边走,大则往右边走,直到遇到空
			{
				parent = cur;
				if (cur->_key < key)
				{
					cur = cur->_right;
				}
				else if (cur->_key > key)

				{
					cur = cur->_left;
				}
				else
				{
					return false;
				}
			}
			cur = new Node(key,value);//此时遇到空要创建新结点
			//但此时我们还要记得将其与parent连接起来,至于是在parent的左边还是右边,看比大小
			if (parent->_key < key)
			{
				parent->_right = cur;
			}
			else
			{
				parent->_left = cur;
			}
			return true;
		}
		Node* Find(const K& key)
		{
			Node* cur = _root;
			while (cur)
			{
				if (cur->_key < key)
				{
					cur = cur->_right;

				}
				else if (cur->_key > key)
				{
					cur = cur->_left;
				}
				else
					return cur;
			}
			return nullptr;
		}
		bool Erase(const K& key)
		{
			Node* cur = _root;
			Node* parent = nullptr;
			while (cur)//寻找要删除的结点
			{
				if (cur->_key > key)
				{
					parent = cur;
					cur = cur->_left;
				}
				else if (cur->_key < key)
				{
					parent = cur;
					cur = cur->_right;
				}
				else
				{
					//找到了就可以开始删除了,但是要判情况,对症下药
					if (cur->_left == nullptr)
					{
						//左边为空,则删除后,将父节点连接cur的右边
						if (cur == _root)//如果要删除的结点就是初始根结点
						{
							_root = cur->_right;
						}
						//先确定此时cur在父节点的左边还是右边
						if (cur == parent->_left)
						{
							parent->_left = cur->_right;
						}
						else
						{
							parent->_right = cur->_right;

						}

					}
					else if (cur->_right == nullptr)
					{
						//右边为空
						if (cur == _root)//如果要删除的结点就是初始根结点
						{
							_root = cur->_left;
						}
						if (cur == parent->_left)
						{
							parent->_left = cur->_left;
						}
						else
						{
							parent->_right = cur->_left;

						}

					}
					else
					{
						//左右都不为空,此时用替换法
						//这里我们以寻找右边树最小值的替换法执行;而右边树最小值即可以认为就是右边树最左边结点
						Node* parent = cur;
						Node* subleft = cur->_right;
						while (subleft->_left)//当左边遇到空,说明此时subleft已经遍历到最左边
						{
							parent = subleft;
							subleft = subleft->_left;
						}
						//找到后,可以进行交换了
						swap(cur->_key, subleft->_key);
						//现在进行删除,而且删除情况属于a情况
						if (subleft == parent->_left)
						{
							parent->_left = subleft->_right;//这边=subleft->_right或者subleft->_left都可以
						}
						else
						{
							parent->_right = subleft->_right;
						}


					}
					return true;
				}
			}
			return false;
		}

		void InOrder()//套一层
		{
			_InOrder(_root);
			cout << endl;
		}
	

	private:
	
	
		void _InOrder(Node* root)//中序遍历
		{
			if (root == nullptr)
				return;
			_InOrder(root->_left);
			cout << root->_key << ":" << root->_value << endl;
			_InOrder(root->_right);

		}
		Node* _root = nullptr;
	};
}

key_valueTest.cpp

#include "key_value.h"
int main()
{
	kv::BSTree<string, string> dict;
	dict.Insert("love", "爱");
	dict.Insert("is", "是");
	dict.Insert("stream", "细水长流");
	kv::BSTreeNode<string, string>* it;
	string str;
	while (cin >> str)
	{
		it = dict.Find(str);
		if (it)
		{
			cout << it->_value << endl;
		}
		else
			cout << "None" << endl;
	}

	return 0;
}

在这里插入图片描述

✍🏻二叉树题目

根据二叉树创建字符串

原题链接根据二叉树创建字符串

1.左右为空可以省略
2.右为空,左不为空可以省
3.左为空,右不为空,不能省,省了就不能确定左右哪个空了

mycode:

class Solution {
public:
    string tree2str(TreeNode* root) {
        string str;
        if(root==nullptr)
        return str;
        str += to_string(root->val);

        //先处理左子树
        if(root->left||root->right)//左不为空||左为空,右不为空,此时左边不能省略括号
        {
            str+='(';
            str += tree2str(root->left);
            str+= ')';
        }
        //再处理右子树
        if(root->right)//右不为空
        {
            str+='(';
            str += tree2str(root->right);
            str+= ')';
        }
        return str;
    } 
};

二叉树的最近公共祖先

原题链接二叉树的最近公共祖先
法一左右法
mycode:

class Solution {
public:
    bool isHere(TreeNode* root,TreeNode* x)
    {
        if(root==nullptr)
        return false;
        if(root==x)
        return true;
        return isHere(root->left,x)||isHere(root->right,x);
    }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root==p||root==q)
        return root;

        bool pInLeft = isHere(root->left,p);
        bool pInRight = !pInLeft;//不是在左就是在右

        bool qInLeft = isHere(root->left,q);
        bool qInRight = !qInLeft;

        if((pInLeft&&qInRight)
        ||(qInLeft&&pInRight))//如果p、q在结点的两侧
        {
            return root;
        }
        else if(pInLeft&&qInLeft)//都在左
        {
            return lowestCommonAncestor(root->left,p,q);
        }
        else if(pInRight&&qInRight)//都在右
        {
            return lowestCommonAncestor(root->right,p,q);
        }
        return nullptr;//随便给个值敷衍一下编译器
    }
};

法二:链表相交法

class Solution {
public:
    bool FindPath(TreeNode* root,TreeNode* x,stack<TreeNode*>& st)
    {
        if(root==nullptr)
        return false;
        st.push(root);
        if(root==x)//当前结点找到
        return true;
        if(FindPath(root->left,x,st))//左子树找到
            return true;
        if(FindPath(root->right,x,st))//右子树找到
            return true;
        //当前结点左右都没找到
        st.pop();
        return false;//告诉上一结点,我这里没找到
    }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        stack<TreeNode*> pPath,qPath;
        FindPath(root,p,pPath);
        FindPath(root,q,qPath);
        while(pPath.size()!=qPath.size())
        {
            if(pPath.size()>qPath.size())
            pPath.pop();
            else
            qPath.pop();
        }
        while(pPath.top()!=qPath.top())
        {
            pPath.pop();
            qPath.pop();
        }
        return pPath.top();
    }
};

二叉搜索树与双向链表

原题链接二叉搜索树与双向链表

mycode:

class Solution {
public:
	void InorderConvert(TreeNode* cur,TreeNode*& prev)
	{
		if(cur==nullptr)
		return ;
		InorderConvert(cur->left,prev);//prev给引用就是因为这里递归会改变prev,要让下面的prev同步改变,就必须要使用引用
		cur->left = prev;
		if(prev)//prev可能为空
		prev->right = cur;
		prev = cur;
		InorderConvert(cur->right,prev);
	}
    TreeNode* Convert(TreeNode* pRootOfTree) {
        TreeNode* root = pRootOfTree,*prev = nullptr;
		InorderConvert(root,prev);
		//接下来要找头节点,也就是原二叉搜索树的最左结点
		TreeNode* head = prev;
		while(head&&head->left)//前者防止本身案例为空
		{
			head = head->left;
		}
		return head;
    }
};

从前序与中序遍历序列构造二叉树

class Solution {
public:
    TreeNode* _build(vector<int>& preorder, vector<int>& inorder,int& previ,int ibegin,int iend)
    {
        if(ibegin>iend)
        return nullptr;
        //先从中序数组找到根
        int cur = ibegin;
        while(preorder[previ]!=inorder[cur])
        {
            cur++;
        }
        //先序确定根
        TreeNode* root = new TreeNode(preorder[previ++]);
        //中序确定左右子树区间;[ibegin,cur-1],[cur+1,iend]
        root->left = _build(preorder,inorder,previ,ibegin,cur-1);
        root->right = _build(preorder,inorder,previ,cur+1,iend);

        return root;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        int previ = 0;
        TreeNode* root = _build(preorder,inorder,previ,0,inorder.size()-1);
        return root;
    }
};

从中序与后序遍历序列构造二叉树

class Solution {
public:
TreeNode* _build(vector<int>& inorder, vector<int>& postorder,int& endi,int ibegin,int iend)
    {
        if(ibegin>iend)
        return nullptr;
        //先从中序数组找到根
        int cur = ibegin;
        while(postorder[endi]!=inorder[cur])
        {
            cur++;
        }
        //后序确定根
        TreeNode* root = new TreeNode(postorder[endi--]);
        //中序确定左右子树区间;[ibegin,cur-1],[cur+1,iend]
        //先right再left是因为endi在右边开始起步
        root->right = _build(inorder,postorder,endi,cur+1,iend);

        root->left = _build(inorder,postorder,endi,ibegin,cur-1);

        return root;
    }
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        int endi = postorder.size()-1;
        TreeNode* root = _build(inorder,postorder,endi,0,inorder.size()-1);
        return root;
    }
};

二叉树的前序遍历非递归

原题链接:二叉树的前序遍历

  • 左路节点
  • 左路节点的右子树
    mycode:
class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        vector<int> v;
        TreeNode* cur = root;
        while(cur||!st.empty())//当cur不为空或者st为空时
        {
            //先存入左节点
            while(cur)
            {
                st.push(cur);
                v.push_back(cur->val);
                cur = cur->left;
            }
            //再处理子问题——左节点的右子树
            cur = st.top()->right;
            st.pop();
        }
        return v;
    }
};

二叉树的中序遍历非递归

原题链接:二叉树的中序遍历非递归

  • 左路节点
  • 根节点和右子树
    mycode:
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
         stack<TreeNode*> st;
        vector<int> v;
        TreeNode* cur = root;
        while(cur||!st.empty())
        {
            //先存入左节点
            while(cur)
            {
                st.push(cur);
                cur = cur->left;
            }
            //再处理根和右子树
            v.push_back(st.top()->val);//直接插入左
            cur = st.top()->right;
            st.pop();
        }
        return v;
    }
};

二叉树的后序遍历非递归

原题链接:二叉树的后序遍历非递归
version1:超出时间限制

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
         stack<TreeNode*> st;
        vector<int> v;
        TreeNode* cur = root;
        while(cur||!st.empty())
        {
           while(cur)
           {
               st.push(cur);
               cur = cur->left;
           }
           if(!st.top()->left&&!st.top()->right)
           {
               TreeNode* p = st.top();
               v.push_back(st.top()->val);
               st.pop();
               if(st.top()->left==p)
               st.top()->left = nullptr;
               if(st.top()->right==p)
               st.top()->right == nullptr;
           }
           cur = st.top()->right;
        }
        return v;
    }
};

version2

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
         stack<TreeNode*> st;
        vector<int> v;
        TreeNode* cur = root;
        TreeNode* prev = prev;
        while(cur||!st.empty())
        {
           while(cur)
           {
               st.push(cur);
               cur = cur->left;
           }
           TreeNode* top = st.top();
           if(top->right==nullptr||top->right == prev)
           {
               st.pop();
               v.push_back(top->val);
               prev = top;
           }
           else
           {
               cur = top->right;
           }
           
        }
        return v;
    }
};

如上便是本期的所有内容了,如果喜欢并觉得有帮助的话,希望可以博个点赞+收藏+关注🌹🌹🌹❤️ 🧡 💛,学海无涯苦作舟,愿与君一起共勉成长
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值