二叉搜索树(二叉排序树)(含力扣相关题及题解)

文章目录

  • 二叉搜索树(二叉排序树)
    • 1、二叉搜索树概念
    • 2、二叉搜索树的操作
      • 2.1、二叉搜索树的查找
      • 2.2、二叉搜索树的插入
      • 2.2、二叉树的删除
    • 3、二叉搜索树的实现(含递归版本)
    • 4、二叉搜索树的应用
      • 4.1、K模型
      • 4.2、KV模型
    • 5、二叉搜索树的性能分析
    • 6、二叉树进阶面试题

img

二叉搜索树(二叉排序树)

1、二叉搜索树概念

**二叉搜索树又叫二叉排序树和二叉查找树。**二叉搜索树可以为空。若当前二叉搜索树不为空,它有以下性质:

  1. 若左子树不为空,则根结点的的值大于左子树中所有结点的值

  2. 若右子树不为空,则根结点的的值小于左子树中所有结点的值

  3. 左右子树也有以上性质


2、二叉搜索树的操作

插入序列:

int arr[] = {8,3,1,10,6,4,7,14,13};

2.1、二叉搜索树的查找

  1. 从根开始比较,比根小的去根的左子树中查找,比根大的去根的右子树中查找
  2. 一直查找直到找到,没找到的话则走到了空。

template<class K>
struct BSTreeNode {//typedef BSTreeNode<K> Node;BSTreeNode<K> *_left;BSTreeNode<K> *_right;K _key;BSTreeNode(const K &key) : _left(nullptr), _right(nullptr), _key(key) {}};template<class K>
class BinarySearchTree {
public:typedef BSTreeNode<K> Node;bool Find(const K &key) {Node *cur = _root;if (cur == nullptr)return false;while (cur) {if (cur->_key < key) {cur = cur->_right;} else if (cur->_key > key) {cur = cur->_left;} else {return true;}}return false;}
private:Node *_root = nullptr;
};

2.2、二叉搜索树的插入

  1. 若树为空则直接插入
  2. 若树不为空,按查找的性质去找查找位置

template<class K>
struct BSTreeNode {//typedef BSTreeNode<K> Node;BSTreeNode<K> *_left;BSTreeNode<K> *_right;K _key;BSTreeNode(const K &key) : _left(nullptr), _right(nullptr), _key(key) {}};template<class K>
class BinarySearchTree {
public:typedef BSTreeNode<K> Node;bool Insert(const K &key) {Node *cur = _root;Node *parent = nullptr;if (cur == nullptr) {Node *newNode = new Node(key);_root = newNode;return true;}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 == nullptrNode *newNode = new Node(key);if (parent->_key < key)parent->_right = newNode;else if (parent->_key > key)parent->_left = newNode;return true;}
private:Node *_root = nullptr;
};

2.2、二叉树的删除

首先查找要查找的值是否在该树中,如果不存在,则返回。否则要删除的结点分下面四种情况:

  1. 要删除的结点无孩子
  2. 要删除的结点无左孩子,只有右孩子
  3. 要删除的结点无右孩子,只有左孩子
  4. 要删除的结点有左右孩子

上面1,2,3其实可以结合起来,即将要删除的结点无孩子直接归类为无左孩子(2)或者无右孩子(3)。如下:

  1. 若要删除的结点是其双亲结点的左孩子,则让其双亲的左指针指向要删除的结点的右孩子,若要删除的结点是其双亲结点的右孩子,则让其双亲的右指针指向要删除的结点的右孩子。
  2. 若要删除的结点是其双亲结点的左孩子,则让其双亲的左指针指向要删除的结点的左孩子,若要删除的结点是其双亲结点的右孩子,则让其双亲的右指针指向要删除的结点的左孩子。
  3. 找当前要删除结点的左子树中的最大值(或者右子树最小值)来替换当前结点(非递归直接赋值,递归直接交换值,仅交换值,不是交换结点)

template<class K>
struct BSTreeNode {//typedef BSTreeNode<K> Node;BSTreeNode<K> *_left;BSTreeNode<K> *_right;K _key;BSTreeNode(const K &key) : _left(nullptr), _right(nullptr), _key(key) {}};template<class K>
class BinarySearchTree {
public:typedef BSTreeNode<K> Node;bool Erase(const K &key) {Node *cur = _root;Node *parent = nullptr;if (cur == nullptr)return false;while (cur) {if (cur->_key < key) {parent = cur;cur = cur->_right;} else if (cur->_key > key) {parent = cur;cur = cur->_left;} else {//找到要删的结点// 当前要删的结点有一个孩子或者没有孩子if (cur->_left == nullptr) {// 判断跟结点是否只有一颗子树if (cur == _root) {_root = _root->_right;} else {if (parent->_left == cur)parent->_left = cur->_right;elseparent->_right = cur->_right;}delete cur;return true;} else if (cur->_right == nullptr) {// 判断跟结点是否只有一颗子树if (cur == _root) {_root = _root->_left;} else {if (parent->_left == cur)parent->_left = cur->_left;elseparent->_right = cur->_left;}delete cur;return true;} else {// 当前要删的结点有两个孩子// 找个替代的值去删  -- 找左子树的最右结点,即左子树最大的结点Node *LeftMax = cur->_left;Node *LeftMaxParent = cur;while (LeftMax->_right) {LeftMaxParent = LeftMax;LeftMax = LeftMax->_right;}cur->_key = LeftMax->_key;if (LeftMaxParent->_left == LeftMax)LeftMaxParent->_left = LeftMax->_left;elseLeftMaxParent->_right = LeftMax->_left;delete LeftMax;return true;}}}return false;}
private:Node *_root = nullptr;
};

3、二叉搜索树的实现(含递归版本)

template<class K>
struct BSTreeNode {//typedef BSTreeNode<K> Node;BSTreeNode<K> *_left;BSTreeNode<K> *_right;K _key;BSTreeNode(const K &key) : _left(nullptr), _right(nullptr), _key(key) {}};template<class K>
class BinarySearchTree {
public:typedef BSTreeNode<K> Node;BinarySearchTree() = default;BinarySearchTree(const BinarySearchTree<K> &b) {_root = Copy(b._root);}Node *Copy(Node *root) {if (root == nullptr)return nullptr;Node *newNode = new Node(root->_key);newNode->_left = Copy(root->_left);newNode->_right = Copy(root->_right);return newNode;}BinarySearchTree<K> &operator=(BinarySearchTree<K> b) {swap(b._root, _root);return *this;}~BinarySearchTree() {Destroy(_root);}void Destroy(Node *root) {if (root == nullptr)return;Destroy(root->_left);Destroy(root->_right);delete root;}bool Erase(const K &key) {Node *cur = _root;Node *parent = nullptr;if (cur == nullptr)return false;while (cur) {if (cur->_key < key) {parent = cur;cur = cur->_right;} else if (cur->_key > key) {parent = cur;cur = cur->_left;} else {//找到要删的结点// 当前要删的结点有一个孩子或者没有孩子if (cur->_left == nullptr) {// 判断跟结点是否只有一颗子树if (cur == _root) {_root = _root->_right;} else {if (parent->_left == cur)parent->_left = cur->_right;elseparent->_right = cur->_right;}delete cur;return true;} else if (cur->_right == nullptr) {// 判断跟结点是否只有一颗子树if (cur == _root) {_root = _root->_left;} else {if (parent->_left == cur)parent->_left = cur->_left;elseparent->_right = cur->_left;}delete cur;return true;} else {// 当前要删的结点有两个孩子// 找个替代的值去删  -- 找左子树的最右结点,即左子树最大的结点Node *LeftMax = cur->_left;Node *LeftMaxParent = cur;while (LeftMax->_right) {LeftMaxParent = LeftMax;LeftMax = LeftMax->_right;}cur->_key = LeftMax->_key;if (LeftMaxParent->_left == LeftMax)LeftMaxParent->_left = LeftMax->_left;elseLeftMaxParent->_right = LeftMax->_left;delete LeftMax;return true;}}}return false;}bool Insert(const K &key) {Node *cur = _root;Node *parent = nullptr;if (cur == nullptr) {Node *newNode = new Node(key);_root = newNode;return true;}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 == nullptrNode *newNode = new Node(key);if (parent->_key < key)parent->_right = newNode;else if (parent->_key > key)parent->_left = newNode;return true;}bool Find(const K &key) {Node *cur = _root;if (cur == nullptr)return false;while (cur) {if (cur->_key < key) {cur = cur->_right;} else if (cur->_key > key) {cur = cur->_left;} else {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) {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->_right == nullptr)root = root->_left;else if (root->_left == nullptr)root = root->_right;else {// 将当前要删的结点的值和当前结点的左子树最大值的结点交换Node *LeftMax = root->_left;while (LeftMax->_right) {LeftMax = LeftMax->_right;}swap(LeftMax->_key, root->_key);return _EraseR(root, key);}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;if (root->_left)_InOrder(root->_left);cout << root->_key << " ";if (root->_right)_InOrder(root->_right);}Node *_root = nullptr;
};

4、二叉搜索树的应用

4.1、K模型

K模型即只有key作为关键码,结构中只需要存储key即可,关键码即为需要搜索到的值。

比如:上述实现的就是,比如存的就是整型值,看该树中是否有要查找的值。或者给一个单词word,判断该单词是否拼写正确。


4.2、KV模型

KV模型即每一个关键码key,都有与之对应的值value,即<key, value>的键值对。

比如:英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英文单词与其对应的中文<word,chinese>就构成一种键值对。

  • 对K模型的二叉搜索树进行小改造就可以得到KV模型的二叉搜索树
template<class K, class V>struct BSTreeNode {//typedef BSTreeNode<K> Node;BSTreeNode<K, V> *_left;BSTreeNode<K, V> *_right;K _key;V _val;BSTreeNode(const K &key,const K &val) : _left(nullptr), _right(nullptr), _key(key),_val(val) {}};template<class K, class V>class BinarySearchTree {public:typedef BSTreeNode<K, V> Node;BinarySearchTree() = default;BinarySearchTree(const BinarySearchTree<K, V> &b) {_root = Copy(b._root);}Node *Copy(Node *root) {if (root == nullptr)return nullptr;Node *newNode = new Node(root->_key);newNode->_left = Copy(root->_left);newNode->_right = Copy(root->_right);return newNode;}BinarySearchTree<K, V> &operator=(BinarySearchTree<K, V> b) {swap(b._root, _root);return *this;}~BinarySearchTree() {Destroy(_root);}void Destroy(Node *root) {if (root == nullptr)return;Destroy(root->_left);Destroy(root->_right);delete root;}bool Erase(const K &key) {Node *cur = _root;Node *parent = nullptr;if (cur == nullptr)return false;while (cur) {if (cur->_key < key) {parent = cur;cur = cur->_right;} else if (cur->_key > key) {parent = cur;cur = cur->_left;} else {//找到要删的结点// 当前要删的结点有一个孩子或者没有孩子if (cur->_left == nullptr) {// 判断跟结点是否只有一颗子树if (cur == _root) {_root = _root->_right;} else {if (parent->_left == cur)parent->_left = cur->_right;elseparent->_right = cur->_right;}delete cur;return true;} else if (cur->_right == nullptr) {// 判断跟结点是否只有一颗子树if (cur == _root) {_root = _root->_left;} else {if (parent->_left == cur)parent->_left = cur->_left;elseparent->_right = cur->_left;}delete cur;return true;} else {// 当前要删的结点有两个孩子// 找个替代的值去删  -- 找左子树的最右结点,即左子树最大的结点Node *LeftMax = cur->_left;Node *LeftMaxParent = cur;while (LeftMax->_right) {LeftMaxParent = LeftMax;LeftMax = LeftMax->_right;}cur->_key = LeftMax->_key;if (LeftMaxParent->_left == LeftMax)LeftMaxParent->_left = LeftMax->_left;elseLeftMaxParent->_right = LeftMax->_left;delete LeftMax;return true;}}}return false;}bool Insert(const K &key,const K &val) {Node *cur = _root;Node *parent = nullptr;if (cur == nullptr) {Node *newNode = new Node(key,val);_root = newNode;return true;}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 == nullptrNode *newNode = new Node(key,val);if (parent->_key < key)parent->_right = newNode;else if (parent->_key > key)parent->_left = newNode;return true;}Node *Find(const K &key) {Node *cur = _root;if (cur == nullptr)return nullptr;while (cur) {if (cur->_key < key) {cur = cur->_right;} else if (cur->_key > key) {cur = cur->_left;} else {return cur;}}return nullptr;}void InOrder() {_InOrder(_root);cout << endl;}private:void _InOrder(Node *root) {if (root == nullptr)return;if (root->_left)_InOrder(root->_left);cout << root->_key << " ";if (root->_right)_InOrder(root->_right);}Node *_root = nullptr;};void test_BST_KV() {BinarySearchTree<string, string> bstkv;bstkv.Insert("hello", "你好");bstkv.Insert("xp", "徐鹏");bstkv.Insert("zl", "紫玲");bstkv.Insert("search", "搜索");string s;while (cin >> s) {auto ret = bstkv.Find(s);if (ret)cout << ret->_val << endl;elsecout << "没有这个" << endl;}
}

5、二叉搜索树的性能分析

由于二叉搜索树的插入和删除都用到了查找,所以查找效率代表了二叉搜索树的各操作的性能。

对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,深度越深,查找中比较的次数越多。

但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树。

时间复杂度:

  1. 在最优的情况下,二叉搜索树接近为完全二叉树,其平均比较次数为:nlogn
  2. 在最坏的情况下,二叉搜索树接近为单边二叉树,其平均比较次数为:n^2

如果退化为单边树,那么二叉搜索树的优势就失去了,怎么解决?后面学了AVL(平衡二叉树)和红黑树就可以解决这个问题。


6、二叉树进阶面试题

1、606. 根据二叉树创建字符串

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/// 606. 根据二叉树创建字符串class Solution {
public:string tree2str(TreeNode *root) {if (root == nullptr)return "";string str = to_string(root->val);// 要加括号:1、当前结点的左不空,左为空右不空也要加//         2、当前结点的右不空// 往左子树找if (root->left || root->right) {str += '(';str += tree2str(root->left);str += ')';}// 往右子树找if (root->right) {str += '(';str += tree2str(root->right);str += ')';}return str;}
};

2、102. 二叉树的层序遍历

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/// 102. 二叉树的层序遍历
class Solution {
public:vector <vector<int>> levelOrder(TreeNode *root) {vector <vector<int>> vv;if (root == nullptr)return vv;queue < TreeNode * > q;q.push(root);while (!q.empty()) {vector<int> v; // 用来每次尾插vvint size = q.size();// 当前层的元素个数for (int i = 0; i < size; ++i) {TreeNode *cur = q.front();v.push_back(cur->val);q.pop();if (cur->left)q.push(cur->left);if (cur->right)q.push(cur->right);}vv.push_back(v);}return vv;}
};

3、107. 二叉树的层序遍历 II

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/// 107. 二叉树的层序遍历 II
class Solution {
public:vector <vector<int>> levelOrderBottom(TreeNode *root) {vector <vector<int>> vv;if (root == nullptr)return vv;queue < TreeNode * > q;q.push(root);while (!q.empty()) {vector<int> v; // 用来每次尾插vvint size = q.size();// 当前层的元素个数for (int i = 0; i < size; ++i) {TreeNode *cur = q.front();v.push_back(cur->val);q.pop();if (cur->left)q.push(cur->left);if (cur->right)q.push(cur->right);}vv.push_back(v);}reverse(vv.begin(),vv.end());return vv;}
};

4、236. 二叉树的最近公共祖先

  • 解法一:
/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/class Solution {
public:bool IsInTree(TreeNode *root, TreeNode *cur) {if (root == nullptr)return false;return root == cur || IsInTree(root->left, cur) || IsInTree(root->right, cur);}TreeNode *lowestCommonAncestor(TreeNode *root, TreeNode *p, TreeNode *q) {if (root == nullptr)return nullptr;if (p == root || q == root)return root;bool pInLeft, pInRight, qInLeft, qInRight;pInLeft = IsInTree(root->left, p);pInRight = !pInLeft; // p肯定在左右子树中的一个qInLeft = IsInTree(root->left, q);qInRight = !qInLeft; // q肯定在左右子树中的一个if ((pInLeft && qInRight) || (pInRight && qInLeft)) {// 左右子树各一个,那么当前结点就是公共结点return root;} else if ((pInLeft && qInLeft)) {return lowestCommonAncestor(root->left, p, q);// 去左子树找} elsereturn lowestCommonAncestor(root->right, p, q);// 去右子树找}
};
  • 解法二:
/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*///  236. 二叉树的最近公共祖先
class Solution {
public:bool GetPath(TreeNode *root, TreeNode *cur, stack<TreeNode *> &v) {if (root == nullptr)return false;v.push(root);if (cur == root)return true;// 去左边找if (GetPath(root->left, cur, v))return true;// 去右边找if (GetPath(root->right, cur, v))return true;// 左右都没找到v.pop();return false;}TreeNode *lowestCommonAncestor(TreeNode *root, TreeNode *p, TreeNode *q) {stack < TreeNode * > sp;stack < TreeNode * > sq;GetPath(root, p, sp);GetPath(root, q, sq);// 两个路径找交点while (sp.size() != sq.size()) {if (sp.size() > sq.size())sp.pop();elsesq.pop();}while (sp.top() != sq.top()) {sp.pop();sq.pop();}return sp.top();}
};

5、JZ36 二叉搜索树与双向链表

/*
struct TreeNode {int val;struct TreeNode *left;struct TreeNode *right;TreeNode(int x) :val(x), left(NULL), right(NULL) {}
};*/// JZ36 二叉搜索树与双向链表
class Solution {
public:void InOrderConvert(TreeNode *cur, TreeNode *&pre) {if (cur == nullptr)return;InOrderConvert(cur->left, pre);// 关键cur->left = pre;if (pre)pre->right = cur;pre = cur;InOrderConvert(cur->right, pre);}TreeNode *Convert(TreeNode *pRootOfTree) {if (!pRootOfTree)return nullptr;TreeNode *pre = nullptr;InOrderConvert(pRootOfTree, pre);TreeNode *head = pRootOfTree;while (head->left) {head = head->left;}return head;}};

6、105. 从前序与中序遍历序列构造二叉树

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/// 105. 从前序与中序遍历序列构造二叉树
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 = inbegin;while (rooti <= inend) {if (inorder[rooti] != root->val)rooti++;elsebreak;}// 再构建左右子树// [inbegin,rooti-1]  [rooti+1,inend]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;return _buildTree(preorder, inorder, prei, 0, inorder.size() - 1);}
};

7、106. 从中序与后序遍历序列构造二叉树

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/// 106. 从中序与后序遍历序列构造二叉树
class Solution {
public:TreeNode *_buildTree(vector<int> &inorder, vector<int> &postorder, int &posti, int inbegin, int inend) {//   中序左右区间不对if (inbegin > inend)return nullptr;// 先创建结点 ,再构建它的左右子树TreeNode *root = new TreeNode(postorder[posti--]);// 中序序列划分左右区间 先构建右子树int rooti = inend;while (rooti >= inbegin) {if (inorder[rooti] != root->val)rooti--;elsebreak;}// 再构建右左子树// [inbegin,rooti-1]  [rooti+1,inend]root->right = _buildTree(inorder, postorder, posti, rooti + 1, inend);root->left = _buildTree(inorder, postorder, posti, inbegin, rooti - 1);return root;}TreeNode *buildTree(vector<int> &inorder, vector<int> &postorder) {int posti = postorder.size() - 1;return _buildTree(inorder, postorder, posti, 0, inorder.size() - 1);}
};

8、144. 二叉树的前序遍历

  • 用非递归方法:
/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/// 144. 二叉树的前序遍历
class Solution {
public:vector<int> preorderTraversal(TreeNode *root) {stack < TreeNode * > s;vector<int> v;TreeNode *cur = root;while (cur || !s.empty()) {while (cur) {v.push_back(cur->val);s.push(cur);cur = cur->left;}// 左子树已经走完TreeNode *top = s.top();s.pop();// 现在走右子树cur = top->right;}return v;}
};

9、94. 二叉树的中序遍历

  • 用非递归方法:
/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/// 94. 二叉树的中序遍历
class Solution {
public:vector<int> inorderTraversal(TreeNode *root) {stack < TreeNode * > s;vector<int> v;TreeNode *cur = root;while (cur || !s.empty()) {while (cur) {s.push(cur);cur = cur->left;}// 左子树已经走完TreeNode *top = s.top();s.pop();// 出栈的时候访问v.push_back(top->val);// 现在走右子树cur = top->right;}return v;}
};

10、145. 二叉树的后序遍历

  • 用非递归方法:
/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/// 145. 二叉树的后序遍历
class Solution {
public:vector<int> postorderTraversal(TreeNode *root) {stack < TreeNode * > s;vector<int> v;TreeNode *cur = root;TreeNode *pre = nullptr;while (cur || !s.empty()) {while (cur) {s.push(cur);cur = cur->left;}// 左子树已经走完TreeNode *top = s.top();// 当前结点的右子树为空,可以访问当前结点// 或者右子树不空,但是已经访问过,也可以访问当前结点// 否则去右子树继续访问if (top->right == nullptr || top->right == pre) {v.push_back(top->val);s.pop();// top被pop掉了说明top就变成上一个被访问的结点pre = top;} else {// 现在走右子树cur = top->right;}}return v;}
};

OKOK,二叉排序树的讲解就到这里。如果你对Linux和C++也感兴趣的话,可以看看我的主页哦。下面是我的github主页,里面记录了我的学习代码和leetcode的一些题的题解,有兴趣的可以看看。

Xpccccc的github主页

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/282233.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言例:设 int x; 则表达式 (x=4*5,x*5),x+25 的值

代码如下&#xff1a; #include<stdio.h> int main(void) {int x,m;m ((x4*5,x*5),x25);printf("(x4*5,x*5),x25 %d\n",m);//x4*520//x*5100//x2545return 0; } 结果如下&#xff1a;

拌合楼管理系统开发(十) 不谈技术只谈管理之大宗物资虚假贸易

前言:不谈技术只谈管理 大宗物资往往都是虚假贸易的重灾区,多年前规模就是面子的口号下,一大批国央企挖空心思做大规模,开展了一大批虚假贸易,同时为了面上的合规性,往往会有三方甚至更多方进入到整个链条中,钱货在这个链条中流转,甚至有些就是钱在流转,如果整个链条有一个环节…

电视盒子哪款好?数码小编分享电视盒子品牌排行榜

电视盒子是我们使用最多的数码产品自已&#xff0c;在挑选电视盒子这块超多朋友踩过雷&#xff0c;广告多&#xff0c;频繁卡顿&#xff0c;收费节目多&#xff0c;究竟电视盒子哪款好&#xff1f;本期小编要分享的就是目前最值得入手的电视盒子品牌排行榜&#xff0c;想买电视…

数据结构中单向链表(无头)的学习

一.数据结构 1.定义 一组用来保存一种或者多种特定关系的数据的集合&#xff08;组织和存储数据&#xff09; 程序的设计&#xff1a;将现实中大量而复杂的问题以特定的数据类型和特定的存储结构存储在内存中&#xff0c; 并在此基础上实现某个特定的功能的操…

SpringBoot-03 | SpringBoot自动配置

SpringBoot-03 | SpringBoot自动配置 原理分析代码示例源码剖析SpringBootConfiguration&#xff1a;组合注解&#xff0c;标记当前类为配置类ComponentScanEnableAutoConfigurationImport加载spring.factoriesrun初始化加载spring.factoriesspring.factories中的钩子类 网上盗…

58、服务攻防——应用协议设备KibanaZabbix远控向日葵VNCTeamViwer

文章目录 vnc默认端口&#xff1a;5900 or 5902&#xff0c;hydra支持vnc破解。VNC有三种模式&#xff1a;使用vnc密码、windows密码、无密码。 teamviewer、向日葵都是使用之前爆过漏洞进行测试。 zabbix&#xff1a;监控系统&#xff0c;蓝队部署平台。zabbix页面如下&#…

四川宏博蓬达法律咨询有限公司守护您的法律安全

在法治社会中&#xff0c;法律咨询服务的需求日益增长&#xff0c;而四川宏博蓬达法律咨询有限公司正是这一领域中一颗璀璨的明星。公司以其专业的法律服务和严谨的工作态度&#xff0c;为广大客户提供了安全、高效、全面的法律支持&#xff0c;赢得了社会各界的广泛赞誉。 一、…

高德地图——轨迹回放和电子围栏

功能点 地图的初始化显示电子围栏&#xff08;先初始化在调接口显示电子围栏&#xff09;显示定位显示轨迹轨迹回放 &#xff08;回放速度无法控制是因为高德地图的版本问题&#xff0c;不要设置版本&#xff0c;使用默认的即可生效&#xff09;获取当前城市及天气情况设置地图…

【小白成长记】new Error()传递对象数据

new Error()需要传递对象数据时遇到的小问题&#xff0c;简单记录如下。 如下图代码&#xff1a;单个Promise里&#xff0c;表单校验未通过处理为 reject&#xff0c;同时需要将 表单以及未校验通过的错误信息传递以便后续进行处理。经过测试&#xff0c;发现reject只能传递一…

电脑文件msvcp100.dll丢失原因,如何快速修复msvcp100.dll

电脑文件msvcp100.dll丢失原因&#xff0c;最近有朋友在问这个&#xff0c;显然会问这个的人&#xff0c;一般都是遇到了msvcp100.dll丢失的问题了&#xff0c;今天我们就来详细的给大家说说msvcp100.dll这个文件吧&#xff0c;我们只有了解了msvcp100.dll这个文件&#xff0c;…

Docker专题-03 Log-Driver日志转存

Docker专题教程 注&#xff1a; 本教程由羞涩梦整理同步发布&#xff0c;本人技术分享站点&#xff1a;blog.hukanfa.com 转发本文请备注原文链接&#xff0c;本文内容整理日期&#xff1a;2024-03-19 csdn 博客名称&#xff1a;五维空间-影子&#xff0c;欢迎关注 说明 容器…

MySQL 索引:索引为什么使用 B+树?

Hash 索引不支持顺序和范围查询&#xff1b; 二叉查找树(BST)&#xff1a;解决了排序的问题&#xff0c;极端情况下可能会退化成线性链表&#xff0c;查询效率急剧下降&#xff1b; 平衡二叉树(AVL) &#xff1a;通过旋转解决了平衡的问题&#xff0c;但是旋转操作效率太低&am…

Rust之构建命令行程序(五):环境变量

开发环境 Windows 11Rust 1.77.0 VS Code 1.87.2 项目工程 这次创建了新的工程minigrep. 使用环境变量 我们将通过添加一个额外的功能来改进minigrep:一个不区分大小写的搜索选项&#xff0c;用户可以通过环境变量打开该选项。我们可以将此功能设置为命令行选项&#xff0c;…

linux 升级openssl1.1.1w 亲测记录

下载好openssl源码包,解压到指定目录下 tar -xzvf openssl-1.1.1w.tar.gz -C /usr/localcd openssl-1.1.1w/*预编译、编译、安装*/./config --prefix/usr/local/openssl sharedmake && make install备份配置系统中原有的文件、创建软链接、动态库查找路径配置文件 ld.s…

SpringBoot实战(二十七)集成WebFlux

目录 一、WebFlux1.1 定义1.2 WebFlux 与 Spring MVC 区别 二、代码实现2.1 Maven 配置2.2 暴露 RESTful API 接口的方式方式一&#xff1a;基于注解的控制器方式二&#xff1a;函数式路由器&#xff08;Functional Endpoints&#xff09; 2.3 测试Service2.4 测试ServiceImpl2…

【Charles如何对手机APP进行抓包和弱网测试】

一、Charles对APP抓包 1、前提条件&#xff1a; 1&#xff09;电脑上必须安装Charles工具&#xff0c;如没有安装可参考&#xff1a;【Charles抓包工具下载安装详细操作步骤】-CSDN博客 2&#xff09;手机和电脑必须在同一个局域网内&#xff08;连接同一个WiFi&#xff09;…

ng发布静态资源 发布项目 发布数据

描述&#xff1a;把一个项目或者数据发布出来&#xff0c;通过http的形式访问&#xff0c;比如发布一个js文件&#xff0c;用http://localhost:6060/data/jquery/jquery.min.js访问。 步骤&#xff1a;配置nginx.conf文件&#xff0c;nginx.conf位于conf目录下&#xff0c;在se…

P2822 [NOIP2016 提高组] 组合数问题题解

题目 组合数表示的是从n个物品中选出m个物品的方案数。举个例子&#xff0c;从(1,2,3) 三个物品中选择两个物品可以有 (1,2),(1,3),(2,3)这三种选择方法。根据组合数的定义&#xff0c;我们可以给出计算组合数的一般公式&#xff1a; 其中n!12⋯n&#xff1b;特别地&#xff0…

Java 在PDF中插入页眉、页脚

在处理PDF文档时&#xff0c;有时需要为文档中的每一页添加页眉和页脚&#xff0c;以包含一些有用的信息&#xff0c;如文档标题、章节名称、日期、页码等。对于需要自动化处理的场景&#xff0c;或者需要在大量文档中添加一致的页眉和页脚&#xff0c;可以通过编程的方式来实现…

QGraphicsView的使用,view坐标,scene坐标,item坐标

Graphics View绘图构架 QGraphicsScene&#xff08;场景&#xff09;&#xff1a;可以管理多个图形项QGraphicsItem&#xff08;图形项&#xff09;&#xff1a;也就是图元&#xff0c;支持鼠标事件响应。QGraphicsView&#xff08;视图&#xff09;&#xff1a;关联场景可以让…