C++: Searching a binary tree

Table of contents

1. Introduction to binary search numbers

1 Introduction

2. Time complexity:

        The structure of the tree can be determined by two traversal results, one of which must be an in-order traversal.

2. Simulation implementation

The first stage: add, check 

Phase 2: Non-recursive version and recursive version - addition, deletion, assignment operator overloading, copy construction, destruction

3. Application of binary search tree

K model: Find the Chinese corresponding to the word

KV model: record the number of fruits

Supplement: operator bool in cin

 operator int is also possible

4. Search element binary tree problem

1.606. Create a string from a binary tree

Personal way of writing:

Official writing:

2. 102. Level-order traversal of binary tree

Personal handwriting:

Guan Fang writing method: 

3.236. The most recent common ancestor of a binary tree

Method 1: Use p and q to find it on both sides of the most recent common ancestor

Personal writing method: non-recursive version

Official writing: recursive version

Method 2: Find path intersections

Personal handwriting:

Official writing:

4. Binary search tree and doubly linked list_NiukeTiba_Niuke.com (nowcoder.com) 

Personal handwriting:

Official writing: 

5.105. Construct a binary tree from preorder and inorder traversal sequences

Personal handwriting:

Official writing:

6. 106. Construct a binary tree from inorder and postorder traversal sequences

7. Non-recursion that you can’t write yourself (difficult) 144. Preorder traversal of binary trees

8. In-order of the same type as question 7 94. In-order traversal of binary tree

9.145. Postorder traversal of a binary tree

Traditional recursive writing:

Non-recursive method (key point):


1. Introduction to binary search numbers

1 Introduction

Binary search tree is also called binary sorting tree. It is either an empty tree or a binary tree with the following properties:
①If its left subtree is not empty, the values ​​of all nodes on the left subtree are less than the value of the root node
②If its right subtree is not empty, the values ​​of all nodes on the right subtree are greater than the value of the root node
③ Its left and right subtrees are also binary search trees respectively.
Right now:
Any subtree needs to satisfy that the value of the left subtree < root < the value of the right subtree is the binary search number.
Performing in-order traversal on a binary search tree will definitely yield an ordered sequence.

2. Time complexity:

In the worst case, a binary search tree will degenerate into a single tree. Therefore, its search efficiency is O(N), and the time complexity of O(N) is linear.

        The structure of the tree can be determined by two traversal results, one of which must be an in-order traversal.

According to pre-order traversal and in-order traversal, the structure of a tree can be determined. Two traversal results are used to determine the structure of the tree. One of the traversal results must be the in-order traversal result.

explain:

Preorder: root, left subtree, right subtree - determine the root
in sequence. Middle order: left subtree, root, right subtree - divide the left and right subtree intervals.

2. Simulation implementation

The first stage: add, check 

Error-prone: insert returns type bool

#pragma once

template<class K>
//struct BinarySearchTreeNode
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:
	bool Insert(const K& key)
	{
		if (_root == nullptr)
		{
			_root = new Node(key);
			return true;
		}

		Node* parent = nullptr;
		Node* cur = _root;
		while (cur)
		{
			if (cur->_key < key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_key > key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				return false;
			}
		}

		cur = new Node(key);
		if (parent->_key < key)
		{
			parent->_right = cur;
		}
		else
		{
			parent->_left = cur;
		}

		return true;
	}

	//const Node* Find(const K& key)
	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;
			}
		}

		return false;
	}

	bool Erase(const K& key);

	void InOrder()
	{
		_InOrder(_root);
	}

private:
	void _InOrder(Node* root)
	{
		if (root == nullptr)
			return;

		_InOrder(root->_left);
		cout << root->_key << " ";
		_InOrder(root->_right);
	}
private:
	Node* _root = nullptr;
};

void TestBSTree()
{
	BSTree<int> t;
	int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
	for (auto e : a)
	{
		t.Insert(e);
	}
	t.InOrder();

	t.Insert(16);
	t.Insert(9);

	t.InOrder();
}

Delete 7, 14, 3,
and 8 in order. 7 and 14 are directly deleted scenes.
3 and 8 are scenes that need to be deleted by substitution.
The two children cannot be given to their father, and the father cannot support them. Find someone to raise my children instead of me.
This person is: the maximum node of the left subtree, or the minimum node of the right subtree.

Phase 2: Non-recursive version and recursive version - addition, deletion, assignment operator overloading, copy construction, destruction

Question: Why does FindR need a layer?

Error-prone: The last if condition of non-recursive Erase, if (minParent->_left == minRight), is written incorrectly, the copy constructor cannot be written, and the copy function CopyTree is recursive and difficult to write.

#pragma once

template<class K>
//struct BinarySearchTreeNode
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;
private:
	void DestoryTree(Node* root)
	{
		if (root == nullptr)
			return;
		
		DestoryTree(root->_left);
		DestoryTree(root->_right);
		delete root;
	}

	Node* CopyTree(Node* root)
	{
		if (root == nullptr)
			return nullptr;

		Node* copyNode = new Node(root->_key);
		copyNode->_left = CopyTree(root->_left);
		copyNode->_right = CopyTree(root->_right);

		return copyNode;
	}
public:
	// 强制编译器自己生成构造
	// C++11
	BSTree() = default; //默认构造很好用,但是拷贝构造也是构造函数,就不会自动生成构造函数

	BSTree(const BSTree<K>& t)    //拷贝构造
	{
		_root = CopyTree(t._root);
	}

	// t1 = t2
	BSTree<K>& operator=(BSTree<K> t)
	{
		swap(_root, t._root);
		return *this;
	}

	~BSTree()
	{
		DestoryTree(_root);
		_root = nullptr;
	}

	bool Insert(const K& key)
	{
		if (_root == nullptr)
		{
			_root = new Node(key);
			return true;
		}

		Node* parent = nullptr;
		Node* cur = _root;
		while (cur)
		{
			if (cur->_key < key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_key > key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				return false;
			}
		}

		cur = new Node(key);
		if (parent->_key < key)
		{
			parent->_right = cur;
		}
		else
		{
			parent->_left = cur;
		}

		return true;
	}

	//const Node* Find(const K& key)
	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;
			}
		}

		return false;
	}

	bool Erase(const K& key)    
	{
		Node* parent = nullptr;
		Node* cur = _root;
		while (cur)
		{
			if (cur->_key < key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_key > key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{   // 左右都为空可算做 左为空 or 右为空 的一种
				// 一个孩子--左为空 or 右为空
				// 两个孩子 -- 替换法
				if (cur->_left == nullptr) //如果左为空
				{
					//if (parent == nullptr)
					if (cur == _root)    //如果要删除的节点就是根节点
					{
						_root = cur->_right;    //直接把根的右做根
					}
					else
					{
						if (cur == parent->_left)   //要删的节点是父亲的左
						{ //因为被删节点的左是空,就让被删节点的右做父亲的左
							parent->_left = cur->_right;
						}
						else    //要删的节点是父亲的右
						{ //因为被删节点的左是空,就让被删节点的右做父亲的右
							parent->_right = cur->_right;
						}
					}
					delete cur;
				}
				else if (cur->_right == nullptr)
				{
					//if (parent == nullptr)
					if (cur == _root)
					{
						_root = cur->_left;
					}
					else
					{
						if (cur == parent->_left)
						{
							parent->_left = cur->_left;
						}
						else
						{
							parent->_right = cur->_left;
						}
					}

					delete cur;
				}
				else // 两个孩子都不为空
				{
					// 右子树的最小节点替代
					Node* minParent = cur;
					Node* minRight = cur->_right;
					while (minRight->_left)
					{
						minParent = minRight;
						minRight = minRight->_left;
					}

					swap(minRight->_key, cur->_key);
					//cur->_key = minRight->_key;
					if (minParent->_left == minRight)
					{
						minParent->_left = minRight->_right;
					}
					else
					{
						minParent->_right = minRight->_right;
					}

					delete minRight;
				}

				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);
	}

private:
	bool _EraseR(Node*& root, const K& key)    
//key是10时,root是8的右孩子这个指针的别名,同时指向10
	{
		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
		{
			Node* del = root;
			// 删除
			if (root->_left == nullptr)
			{
				root = root->_right;    //因为root是引用,直接让root等于他的右
			}
			else if (root->_right == nullptr)
			{
				root = root->_left;
			}
			else //这里可以按照非递归的方法也可以,只需要把cur改成root就行
			{    //这里还可以交换3和4值以后,去他的右子树继续删3
				Node* minRight = root->_right;
				while (minRight->_left)
				{
					minRight = minRight->_left;
				}

				swap(root->_key, minRight->_key);    
//交换上图的3和4值后,不能直接递归删3,因为交换后已经不满足搜索二叉树了,应该去他的右子树继续删3
				return _EraseR(root->_right, key);

                /* 按非递归方法
				Node* minParent = root;
				Node* minRight = root->_right;
				while (minRight->_left)
				{
					minParent = minRight;
					minRight = minRight->_left;
				}

				swap(minRight->_key, root->_key);
				if (minParent->_left == minRight)
				{
					minParent->_left = minRight->_right;
				}
				else
				{
					minParent->_right = minRight->_right;
				}

				delete minRight;*/
			}

			delete del;
			return true;
		}
	}

	bool _InsertR(Node*& root, const K& key)
	{
		if (root == nullptr)
		{
			root = new Node(key);
			return true;
		}

		if (root->_key < key)
			return _InsertR(root->_right, key);
		else if (root->_key > key)
			return _InsertR(root->_left, key);
		else
			return false;
	}

	bool _FindR(Node* root, const K& key)
	{
		if (root == nullptr)
			return false;

		if (root->_key < key)
		{
			return _FindR(root->_right, key);
		}
		else if (root->_key > key)
		{
			return _FindR(root->_left, key);
		}
		else
		{
			return true;
		}
	}

	void _InOrder(Node* root)
	{
		if (root == nullptr)
			return;

		_InOrder(root->_left);
		cout << root->_key << " ";
		_InOrder(root->_right);
	}
private:
	Node* _root = nullptr;
};

void TestBSTree1()
{
	BSTree<int> t;
	int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
	for (auto e : a)
	{
		t.Insert(e);
	}
	t.InOrder();

	t.Insert(16);
	t.Insert(9);

	t.InOrder();
}


void TestBSTree2()
{
	BSTree<int> t;
	int a[] = { 8, 7, 9, 12, 5, 19, 20, 30,7,12 };
	for (auto e : a)
	{
		t.Insert(e);
	}
	t.InOrder();
}

void TestBSTree3()
{
	BSTree<int> t;
	int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
	for (auto e : a)
	{
		t.Insert(e);
	}
	t.InOrder();

	t.Erase(3);
	t.Erase(8);

	t.InOrder();
	t.Erase(14);
	t.Erase(7);
	t.InOrder();

	for (auto e : a)
	{
		t.Erase(e);
	}
	t.InOrder();
}

void TestBSTree4()
{
	BSTree<int> t;
	int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
	for (auto e : a)
	{
		t.Insert(e);
	}
	t.InOrder();

	BSTree<int> copy = t;
	copy.InOrder();
}

void TestBSTree5()
{
	BSTree<int> t;
	int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
	for (auto e : a)
	{
		t.InsertR(e);
	}
	t.InOrder();

	t.InsertR(9);

	BSTree<int> copy = t;
	copy.InOrder();
}

void TestBSTree6()
{
	BSTree<int> t;
	int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
	for (auto e : a)
	{
		t.InsertR(e);
	}
	t.InOrder();
	t.EraseR(3);
	t.EraseR(8);

	t.InOrder();
	t.EraseR(14);
	t.EraseR(7);
	t.InOrder();

	for (auto e : a)
	{
		t.EraseR(e);
	}
	t.InOrder();
}

3. Application of binary search tree

1. K model: The K model only has key as the key code. Only the Key needs to be stored in the structure. The key code is what needs to be searched.
value . ( K- set)
For example: given a word word, determine whether the word is spelled correctly . The specific method is as follows:
Construct a binary search tree using each word in the set of all words in the vocabulary as a key
Retrieve whether the word exists in the binary search tree. If it exists, it is spelled correctly. If it does not exist, it is spelled incorrectly.
2. KV model: Each key key has a corresponding value Value, that is, a key-value pair of <Key, Value> . This kind of recipe
The formula is very common in real life:
For example, the English-Chinese dictionary is the correspondence between English and Chinese . Through English, you can quickly find the corresponding Chinese, English
A Chinese word and its corresponding Chinese <word, chinese> form a key-value pair;
Another example is counting the number of words . After the counting is successful, the number of times a given word appears can be quickly found, and the word and its occurrence can be quickly found.
The number of occurrences is <word, count>, which forms a key-value pair

KV-map

namespace key_value
{
#pragma once

	template<class K, class V>
	struct BSTreeNode
	{
		BSTreeNode<K, V>* _left;
		BSTreeNode<K, V>* _right;

		const 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:

		void InOrder()
		{
			_InOrder(_root);
			cout << endl;
		}

		///
		Node* FindR(const K& key)
		{
			return _FindR(_root, key);
		}

		bool InsertR(const K& key, const V& value)
		{
			return _InsertR(_root, key, value);
		}

		bool EraseR(const K& key)
		{
			return _EraseR(_root, key);
		}

	private:
		bool _EraseR(Node*& root, const K& key)
		{
			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
			{
				Node* del = root;
				// 删除
				if (root->_left == nullptr)
				{
					root = root->_right;
				}
				else if (root->_right == nullptr)
				{
					root = root->_left;
				}
				else
				{
					Node* minRight = root->_right;
					while (minRight->_left)
					{
						minRight = minRight->_left;
					}

					swap(root->_key, minRight->_key);

					return _EraseR(root->_right, key);
				}

				delete del;
				return true;
			}
		}

		bool _InsertR(Node*& root, const K& key, const V& value)
		{
			if (root == nullptr)
			{
				root = new Node(key, value);
				return true;
			}

			if (root->_key < key)
				return _InsertR(root->_right, key, value);
			else if (root->_key > key)
				return _InsertR(root->_left, key, value);
			else
				return false;
		}

		Node* _FindR(Node* root, const K& key)
		{
			if (root == nullptr)
				return nullptr;

			if (root->_key < key)
			{
				return _FindR(root->_right, key);
			}
			else if (root->_key > key)
			{
				return _FindR(root->_left, key);
			}
			else
			{
				return root;
			}
		}

		void _InOrder(Node* root)
		{
			if (root == nullptr)
				return;

			_InOrder(root->_left);
			cout << root->_key << ":" << root->_value << endl;
			_InOrder(root->_right);
		}
	private:
		Node* _root = nullptr;
	};

K model: Find the Chinese corresponding to the word

void TestBSTree1()
	{
		BSTree<string, string> ECDict;
		ECDict.InsertR("root", "根");
		ECDict.InsertR("string", "字符串");
		ECDict.InsertR("left", "左边");
		ECDict.InsertR("insert", "插入");
		//...
		string str;
		while (cin >> str)  //while (scanf() != EOF)
		{
			//BSTreeNode<string, string>* ret = ECDict.FindR(str);
			auto ret = ECDict.FindR(str);
			if (ret != nullptr)
			{
				cout << "对应的中文:" << ret->_value << endl;
				//ret->_key = "";
				ret->_value = "";
			}
			else
			{
				cout << "无此单词,请重新输入" << endl;
			}
		}
	}

KV model: record the number of fruits

void TestBSTree2()
	{
		string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
		// 水果出现的次数
		BSTree<string, int> countTree;
		for (const auto& str : arr)
		{
			auto ret = countTree.FindR(str);
			if (ret == nullptr)
			{
				countTree.InsertR(str, 1);
			}
			else
			{
				ret->_value++;  // 修改value
			}
		}

		countTree.InOrder();
	}

Supplement: operator bool in cin

operator bool

The while (cin >> str) //while (scanf() != EOF) of the above K model can handle multiple sets of inputs because the istream type of cin overloads operator bool

#include<iostream>
using namespace std;
class A
{
public:
	explicit A(int a = 0)
		:_a(a)
	{}

	operator bool()
	{
		if (_a < 10)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	void Print()
	{
		cout << _a << endl;
	}

	void Set(int a)
	{
		_a = a;
	}

private:
	int _a;
};

void test()
{
	A a;
	bool ret = a;
	int x;
	while (a) //while (a.operator bool())
	{
		a.Print();
		cin >> x;
		a.Set(x);
	}
}
int main()
{
	test();
	return 0;
}

 operator int is also possible

Built-in types <--custom types

explicit operator int() will cause implicit type conversion int y = a; not supported

#include<iostream>
using namespace std;
class A
{
public:
	explicit A(int a = 0)
		:_a(a)
	{}
	operator int()    //explicit operator int() 会导致隐式类型转换 int y = a;不支持
	{
		if (_a < 10)
		{
			return 1;
		}
		else
		{
			return 0;
		}
	}

	void Print()
	{
		cout << _a << endl;
	}

	void Set(int a)
	{
		_a = a;
	}

private:
	int _a;
};

void test()
{
	A a;
	//int y = a;
	int x;
	//while (a.operator bool())
	while (a)
	{
		a.Print();
		cin >> x;
		a.Set(x);
	}
}
int main()
{
	test();
	return 0;
}

4. Search element binary tree problem

1. 606. Create a string based on a binary tree

Personal way of writing:

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;
    }
};

Official writing:

2.  102. Level-order traversal of binary tree

Use levelSize to output layer by layer

Personal handwriting:

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> vv;
        if(root==nullptr)
            return vv;
        queue<TreeNode*> q;
        int levelSize=1;
        q.push(root);
        while(levelSize)
        {
            vector<int> levelV;
            while(levelSize--)
            {
            TreeNode* front=q.front();
            levelV.push_back(front->val);
            if(front->left)
                q.push(front->left);
            if(front->right)
                q.push(front->right);
            q.pop();
            }
            vv.push_back(levelV);
            levelSize=q.size();
        }
        
        return vv;
    }
};

Guan Fang writing method: 

3. 236. The most recent common ancestor of a binary tree

Method 1: Use p and q to find it on both sides of the most recent common ancestor

Personal writing method: non-recursive version

class Solution {
public:
    bool IsInSubTree(TreeNode* tree, TreeNode* x)   //看是否在此根节点下
    {
        if(tree==nullptr)
            return false;
        if(tree==x)         //要比较地址!!
            return true;
        return IsInSubTree(tree->left, x)||IsInSubTree(tree->right, x);
    }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        TreeNode* cur=root;
        while(cur)
        {
            if(p==cur||q==cur)
                return cur;
            bool pInLeft=IsInSubTree(cur->left, p);
            bool pInRight= !pInLeft;
            bool qInLeft=IsInSubTree(cur->left, q);
            bool qInRight= !qInLeft;
            if((pInLeft && qInRight)||(qInLeft && pInRight))
                return cur;
            else if(pInLeft && qInLeft)
                cur=cur->left;
            else if(pInRight && qInRight)
                cur=cur->right;
        }
        return nullptr;
    }
};

Official writing: recursive version

 Because every time you go to a node in this way, you need to find p and q nodes in its left and right subtrees, N nodes, and the worst-case search for each node is N/2. The time complexity is O(N²), so you need to use time complexity Low degree method two.

Method 2: Find path intersections

According to the trident chain (each node has three pointers, left, right, and father), you can use the stack to record the path from node p, q to the root, and then find the intersecting path (first let the long one be as long as the short one, and then simultaneously Go, equality is the intersection point, and the intersection point is the nearest common ancestor)

Error-prone points: FindPath path function (putting the path on the stack) is difficult to write recursively

Personal handwriting:

class Solution {
public:
    bool FindPath(TreeNode* root,TreeNode* x,stack<TreeNode*>& Path)
    {
        if(root==nullptr)
            return false;
        Path.push(root);
        if(root==x)
            return true;
        if(FindPath(root->left,x,Path))
            return true;
        if(FindPath(root->right,x,Path))
            return true;
        // root不是要找的节点x,左子树和右子树都没有找到,那么root不是x的的路径中节点,
        Path.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())
        {
            qPath.pop();
        }
        while(pPath.size()>qPath.size())
        {
            pPath.pop();
        }
        while(qPath.top() != pPath.top())
        {
            qPath.pop();
            pPath.pop();
        }
        return pPath.top();
    }
};

Official writing:

4. Binary search tree and doubly linked list_NiukeTiba_Niuke.com (nowcoder.com) 

During in-order traversal, change the left and right pointing of each node into the form of a head and tail doubly linked list, use prev to record the previous node, let the left of pRootOfTree point to prev, and let the right of prev point to itself, and so on.

Personal handwriting:

class Solution {
public:
    void InOrderConvert(TreeNode* pRootOfTree,TreeNode*& prev)
    {
        if(pRootOfTree==nullptr)
        {
            return ;
        }
        InOrderConvert( pRootOfTree->left,prev);
        pRootOfTree->left=prev;
        if(prev)
        {
            prev->right= pRootOfTree;
        }
        prev=pRootOfTree;
        InOrderConvert( pRootOfTree->right,prev);
    }
    TreeNode* Convert(TreeNode* pRootOfTree) {
        if(pRootOfTree==nullptr)
            return nullptr;
        TreeNode* prev=nullptr;
        InOrderConvert(pRootOfTree,prev);
        while(pRootOfTree->left)
        {
            pRootOfTree=pRootOfTree->left;
        }
        return pRootOfTree;
    }
};

Official writing: 

5. 105. Construct a binary tree from preorder and inorder traversal sequences

Idea:

Preorder: root, left subtree, right subtree - determine the root
in sequence. Middle order: left subtree, root, right subtree - divide the left and right subtree intervals.

Personal handwriting:

class Solution {
public:
    TreeNode* _buildTree(vector<int>& preorder, vector<int>& inorder,
                    int& prei,int inbegin,int inend)
    {
        if(inbegin>inend)
        {
            return nullptr;
        }
        TreeNode* root=new TreeNode(preorder[prei]);
        int rooti=0;
        while(inorder[rooti]!=preorder[prei])
        {
             ++rooti;
        }
        ++prei;
        root->left=_buildTree(preorder,inorder,prei,inbegin,rooti-1);
        root->right=_buildTree(preorder,inorder,prei,rooti+1,inend);
        return root;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        int prei=0,inbegin=0,inend=inorder.size()-1;
        return _buildTree(preorder,inorder,prei,inbegin,inend);
    }
};

Official writing:

6.  106. Construct a binary tree from inorder and postorder traversal sequences

Similar to 5

class Solution {
public:
    TreeNode* _buildTree(vector<int>& postorder, vector<int>& inorder,
                    int& backi,int inbegin,int inend)
    {
        if(inbegin>inend)
        {
            return nullptr;
        }
        TreeNode* root=new TreeNode(postorder[backi]);
        int rooti=0;
        while(inorder[rooti]!=postorder[backi])
        {
             ++rooti;
        }
        --backi;
        root->right=_buildTree(postorder,inorder,backi,rooti+1,inend);
        root->left=_buildTree(postorder,inorder,backi,inbegin,rooti-1);
        return root;
    }
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        int backi=postorder.size()-1,inbegin=0,inend=inorder.size()-1;
        //cout<<backi;
        return _buildTree(postorder,inorder,backi,inbegin,inend);
    }
};

  Pay attention to the order of the _buildTree sub-functions. After debugging for a long time, I realized that the order was wrong.

7. Non-recursion that you can’t write yourself (difficult) 144. Preorder traversal of binary trees

Look at this tree:

 

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

            cur=top->right;
        }
        return v;
    }
};

Analysis:

8. In-order 94 of the same type as question 7.  In-order traversal of a binary tree

Look at this tree:

First go to 1, put 1 into v, cur = the right of 1, the right of 1 is empty, then enter the loop, put 3 into v, and then start accessing the right of 3

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

A node on the left is pushed into the stack. When a node comes out of the stack, its left subtree is considered to have been visited. Visit him and his right subtree.

9. 145. Post-order traversal of binary tree

Traditional recursive writing:

class Solution {
public:
    void _postorderTraversal(TreeNode* root,vector<int>& v)
    {
        if(root==nullptr)
            return ;
        _postorderTraversal(root->left,v);
        _postorderTraversal(root->right,v);
        v.push_back(root->val);
    }
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> v;
        _postorderTraversal(root,v);
        return v;
    }
};

Non-recursive method (key point):

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> v;
        stack<TreeNode*> st;
        TreeNode* cur=root;
        TreeNode* prev=nullptr;
        while(cur||!st.empty())
        {
            while(cur)
            {
                st.push(cur);
                cur=cur->left;
            }
            TreeNode* top=st.top();
//  1.top的左子树已经访问过了,如果top->right==nullptr,说明没有右节点,则可以直接
//访问此节点,把节点插入v中访问过这个节点后,这个节点就成为上一个访问的节点,用
//prev=top;来记录。
//  2.top->right!=nullptr时,如果top->right==prev,即他上一个访问的节点是右节点,右节
//点已访问过,则可以访问这个节点
            if(top->right==nullptr||top->right==prev)
            {
                v.push_back(top->val);
                st.pop();
                prev=top;
            }
            else
            {
                cur=top->right;
            }
        }
        return v;
    }
};

 explain:

1. After while (cur), the left subtree of top has been visited. If top->right==nullptr, it means that there is no right node, and you can directly access this node. After inserting the node into v, after accessing this node, this node It becomes the last visited node and is recorded with prev=top;.
2. When top->right!=nullptr, if top->right==prev, that is, the last node he visited was the right node, and the right node has been visited, then this node can be accessed

Guess you like

Origin blog.csdn.net/zhang_si_hang/article/details/126237630