二叉搜索树(BST)

BST树称作二叉搜索树(Binary Search Tree)或者二叉排序树(Binary Sort Tree) ,它或者是一颗空树;或者是具有下
列性质的二叉树:

  1. 若左子树不为空,则左子树上所有节点的值均小于它的根节点的值
  2. 若右子树不为空,则右子树上所有节点的值均大于它的根节点的值
  3. 左右子树也分别满足二叉搜索树性质

特点:每一个节点都满足左孩子的值 (不为空) < 父节点的值<右孩子的值(不为空)。

二分查找就是利用了bst树的性质。

BST树的插入:

1.BST为空,生成新的根节点。

2.不为空,从根节点开始进行比较,找到合适的位置,生成新的节点,并把节点的地址写入父节点相应的地址域。

//非递归插入
	void insert(const T & val)
	{
		if (_root == nullptr)
		{
			_root = new Node(val);
			return;
		}
		Node *parent = nullptr;
		Node *cur = _root;
		while (cur != nullptr)
		{
			if (cur->_data == val)
			{
				return;
			}
			else if(cur->_data < val)
			{
				parent = cur;
				cur=cur->_right;
			}
			else
			{
				parent = cur;
				cur = cur->_left;
			}
		}
		if (val < parent->_data)
		{
			parent->_left = new Node(val);
		}
		else
		{
			parent->_right = new Node(val);
		}
	}

BST的删除操作

  1. 没有孩子的节点,父节点地址域置为nullptr
  2. 有一个,孩子写入父节点
  3. 有两个,找到待删除孩子的前驱或后继节点,用前驱或者后继节点把待删除节点的值覆盖,然后直接删除前驱或者后继节点就可以了。前驱(当前节点左子树中值最大的节点)
void remove(const T & val)
	{
		if (_root == nullptr)
		{
			return;
		}
		Node *parent = nullptr;
		Node *cur = _root;
		while (cur != nullptr)
		{
			if (cur->_data==val)	
			{
				break;
			}
			else if (cur->_data< val) 
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				parent = cur;
				cur = cur->_left;	
			}
		}
		if (cur == nullptr)		//没找到
		{
			return;
		}

		//先进行处理情况3
		if (cur->_left != nullptr && cur->_right != nullptr)
		{
			parent = cur;
			Node *pre = cur->_left;
			while (pre->_right != nullptr)
			{
				parent = pre;
				pre = pre->_right;
			}
			cur->_data = pre->_data;
			cur = pre;		//cur指向前驱节点,转化为情况1或者2
		}
								//统一处理情况1和2 cur指向删除节点
		Node *child = cur->_left;
		if (child != nullptr)
		{
			child = cur->_right;
		}
		//删除根节点
		if (parent == nullptr)
		{
			_root = child;
		}
		else
		{
			//把待删除节点的孩子写到父节点相应的地址域
			if (parent->_left == cur)
			{
				parent->_left = child;
			}
			else
			{
				parent->_right = child;
			}
		}
		delete cur;
	}


//递归删除
void remove(const T &val)
	{
		root_ = remove(root_, val);
	}
// 递归删除操作实现
	Node* remove(Node *node, const T &val)
	{
		if (node == nullptr)
			return nullptr;
		
		if (node->data_ == val) // 找到待删除节点
		{
			// 情况3
			if (node->left_ != nullptr && node->right_ != nullptr)
			{
				// 找前驱节点
				Node *pre = node->left_;
				while (pre->right_ != nullptr)
				{
					pre = pre->right_;
				}
				node->data_ = pre->data_; 
				// 通过递归直接删除前驱节点 
				node->left_ = remove(node->left_, pre->data_);
			}
			else // 情况1和情况2
			{
				if (node->left_ != nullptr) 
				{
					// 删除节点以后,把非空的左孩子返回,回溯时更新其父节点地址域
					Node *left = node->left_;
					delete node;
					return left;
				}
				else if (node->right_ != nullptr)
				{
					// 删除节点以后,把非空的右孩子返回,回溯时更新其父节点地址域
					Node *right = node->right_;
					delete node;
					return right;
				}
				else // 删除的是没有孩子的节点  叶子节点
				{
					delete node;
					return nullptr; // 回溯时更新其父节点地址域为nullptr
				}
			}
		}
		else if (comp_(node->data_, val))
		{
			node->right_ = remove(node->right_, val);
		}
		else
		{
			node->left_ = remove(node->left_, val);
		}
		return node; // 把当前节点返回给父节点,更新父节点相应的地址域
	}

BST树的查询

	bool query(const T & val)
	{
		Node *cur = _root;
		while (cur != nullptr)
		{
			if (cur->_data == val)
			{
				return true;
			}
			else if (cur->_data < val)
			{
				cur = cur->_right;
			}
			else
			{
				cur = cur->_left;
			}
		}
		return false;
	}

中序遍历

递归版本:一层一层的打印

	//递归层遍历
	void levelorder()
	{
		int h = high();
		for (int i = 0; i < h; ++i)
		{
			levelorder(_root,i);
		}
		cout << endl;
	}

//层数
	int high()
	{
		return high(_root);
	}

	int high(Node * node)
	{
		if (node == nullptr)
		{
			return 0;
		}
		int left = high(node->_left)  ;
		int right = high(node->_right) ;
		return left > right ? left + 1 : right + 1;
	}

        void levelorder(Node *node, int i)
	{
		if (node == nullptr)
		{
			return ;
		}
		if (i == 0)
		{
			cout << node->_data << "  ";
			return;
		}

		levelorder(node->_left,i-1);
		levelorder(node->_right,i-1);
	}



	//非递归层序
	void n_levelorder()
	{
		if (_root == nullptr)
		{
			return;
		}
		queue<Node*> q;
		q.push(_root);
		while (!q.empty())
		{
			Node* front = q.front();
			q.pop();
			cout << front->_data << " ";
			if (front->_left != nullptr)
			{
				q.push(front->_left);
			}
			if (front->_right != nullptr)
			{
				q.push(front->_right);
			}
		}
	}

非递归:

前序遍历

前序为:58 24 0 5 34 41 67 62 42 69 78

//递归
        void preorder()	
	{
		preorder(_root);
		cout << endl;
	}

        void preorder(Node *node)
	{
		if (node != nullptr)
		{
			cout << node->_data << "   ";
			preorder(node->_left);
			preorder(node->_right);
		}
	}

//非递归
void n_preOrder()
	{
		if (_root == nullptr)
		{
			return;
		}

		stack<Node*> s;
		s.push(_root);
		while (!s.empty())
		{
			Node *top = s.top();
			s.pop();

			cout << top->_data<< " "; // V

			if (top->_right != nullptr)
			{
				s.push(top->_right);   // R
			}

			if (top->_left != nullptr)
			{
				s.push(top->_left);    // L
			}
		}
		cout << endl;
	}

中序遍历

中序为:0 5 24 34 41 58 62 64 67 69 78

//非递归中序遍历
	void n_inOrder()
	{
		if (_root == nullptr)
		{
			return;
		}

		stack<Node*> s;
		Node* cur = _root;

		while (!s.empty() || cur != nullptr)
		{
			if (cur != nullptr)
			{
				s.push(cur);
				cur = cur->_left;
			}
			else
			{
				Node* top = s.top();
				s.pop();
				cout << top->_data << " ";
				cur = top->_right;
			}
		}
	}

后序遍历

后序为:5 0 41 34 24 64 62 78 69 67 58 

//非递归后序遍历
	void n_postOrder()
	{
		cout << "非递归后序遍历:";
		if (_root == nullptr)
		{
			return;
		}
		stack<Node*> s1;
		stack<Node*> s2;
		s1.push(_root);
		while (!s1.empty())
		{
			Node *top = s1.top();
			s1.pop();

			s2.push(top); // V
			if (top->_left != nullptr)
			{
				s1.push(top->_left);  // L
			}
			if (top->_right != nullptr)
			{
				s1.push(top->_right);  // R
			}
		}
		while (!s2.empty())
		{
			cout << s2.top()->_data << " ";
			s2.pop();
		}
		cout << endl;
	}

BST树区间元素搜索的查找

利用中序遍历之后为有序的从大到小的性质。

        void findValues(vector<T> &vec, int i, int j)
	{
		findValues(root_, vec, i, j);
	}

// 求满足区间的元素值[i, j]实现
	void findValues(Node *node, vector<T> &vec, int i, int j)
	{
		if (node != nullptr)
		{
			// 在当前节点的左子树中搜索
			if (node->data_ > i)
			{
				findValues(node->left_, vec, i, j); // L
			}

			if (node->data_ >= i && node->data_ <= j)// V
			{
				vec.push_back(node->data_); // 存储满足区间元素的值
			}

			// 在当前节点的右子树中搜索
			if (node->data_ < j)
			{
				findValues(node->right_, vec, i, j); // R
			}
		}
	}

判断一个二叉树是否为BST树

// 判断二叉树是否是BST树
	bool isBSTree()
	{
		Node *pre = nullptr;
		return isBSTree(root_, pre);
	}

// 判断二叉树是否是BST树的实现 利用BST树中序遍历是一个升序的特点
	bool isBSTree(Node *node, Node *&pre)
	{
		if (node == nullptr)
		{
			return true;
		}

		if (!isBSTree(node->left_, pre)) // L 主要判断使递归结束的条件
		{
			return false;
		}
		// V
		if (pre != nullptr)
		{
			if (node->data < pre->data_) // 主要判断使递归结束的条件
			{
				return false;
			}
		}
		pre = node; // 更新中序遍历的前驱节点

		return isBSTree(node->right_, pre); // R

	}

判断子树问题实现


// 判断子树问题
	bool isChildTree(BSTree<T> &child)
	{
		// 在当前二叉树上找child的根节点
		if (child.root_ == nullptr)
		{
			return true;
		}

		Node *cur = root_;
		while (cur != nullptr)
		{
			if (cur->data_ == child.root_->data_)
			{
				break;
			}
			else if (cur->data_ < child.root_->data_)
			{
				cur = cur->right_;
			}
			else
			{
				cur = cur->left_;
			}
		}
		if (cur == nullptr)
		{
			return false;
		}
		return isChildTree(cur, child.root_);
	}

// 判断子树问题实现
	bool isChildTree(Node *father, Node *child)
	{
		if (father == nullptr && child == nullptr)
		{
			return true;
		}

		if (father == nullptr) // 子树里面有的节点,当前二叉树没有
		{
			return false; 
		}

		if (child == nullptr)
		{
			return true;
		}

		// 判断值不相同
		if (father->data_ != child->data_)  // V
		{
			return false;
		}

		return isChildTree(father->left_, child->left_) // L
			&& isChildTree(father->right_, child->right_); // R
	}

最近公共祖先节点

// 最近公共祖先节点
	int getLCA(int val1, int val2)
	{
		Node *node = getLCA(root_, val1, val2);
		if (node == nullptr)
		{
			throw "no LCA!";
		}
		else
		{
			return node->data_;
		}
	}

	// 最近公共祖先节点实现
	Node* getLCA(Node *node, int val1, int val2)
	{
		if (node == nullptr)
		{
			return nullptr;
		}

		if( (node->data_ < val1) && (node->data_<val2))
		{
			return getLCA(node->right_, val1, val2);
		}
		else if ((val1 < node->data_) && (val2 < node->data_))
		{
			return getLCA(node->left_, val1, val2);
		}
		else
		{
			return node;
		}
	}

镜像翻转


// 镜像翻转
	void mirror01()
	{
		mirror01(root_);
	}

// 镜像翻转
	void mirror01(Node *node)
	{
		if (node == nullptr)
			return;

		// V
		Node *tmp = node->left_;
		node->left_ = node->right_;
		node->right_ = tmp;

		mirror01(node->left_);  // L
		mirror01(node->right_); // R
	}

镜像对称

如图,在二叉树中间两边互相对称。

// 镜像对称
	bool mirror02()
	{
		if (root_ == nullptr)
			return true;
		return mirror02(root_->left_, root_->right_);
	}

// 镜像对称
	bool mirror02(Node *node1, Node *node2)
	{
		if (node1 == nullptr && node2 == nullptr)
		{
			return true;
		}
		if (node1 == nullptr || node2 == nullptr)
		{
			return false;
		}
		if (node1->data_ != node2->data_)
		{
			return false;
		}
		return mirror02(node1->left_, node2->right_)
			&& mirror02(node1->right_, node2->left_);
	}

重建二叉树

我们利用前序遍历和中序遍历的特征,前序遍历的第一个是根节点,在中序遍历找到这个节点,该节点之前为该节点的左子树,之后为右子树。

// 重建二叉树
	void rebuild(int pre[], int i, int j, int in[], int m, int n)
	{
		root_ = _rebuild(pre, i, j, in, m, n);
	}

	// 重建二叉树递归实现
	Node* _rebuild(int pre[], int i, int j, int in[], int m, int n)
	{
		if (i > j || m > n)
		{
			return nullptr;
		}

		// 创建当前子树的根节点
		Node *node = new Node(pre[i]); // 拿前序的第一个数字创建子树根节点  V
		for (int k = m; k <= n; ++k)
		{
			if (pre[i] == in[k]) // 在中序遍历中找子树根节点的下标k
			{
				node->left_ = _rebuild(pre, i+1, i+(k-m), in, m, k-1); // L
				node->right_ = _rebuild(pre, i+(k-m)+1, j, in, k+1, n); // R
				return node;
			}
		}
		return node;
	}

判断BST树是否为平衡树

任意节点左右高度差不超过1

// 判断平衡树 效率比较低
	bool isBalance(Node *node)
	{
		if (node == nullptr)
			return true;
		if (!isBalance(node->left_))  // L
			return false;
		if (!isBalance(node->right_))  // R
			return false;

		int left = high(node->left_);
		int right = high(node->right_);
		return abs(left - right) <= 1;   // V
	}


// 判断平衡树
	bool isBalance()
	{
		int l = 0;
		bool flag = true;
		isBalance02(root_, l, flag);
		return flag;
	}

	// 判断平衡树 效率高 递归过程中,记录了节点的高度值  返回节点高度值
	int isBalance02(Node *node, int l, bool &flag)
	{
		if (node == nullptr)
		{
			return l;
		}

		int left = isBalance02(node->left_, l + 1, flag); // L
		if (!flag)
			return left;
		int right = isBalance02(node->right_, l + 1, flag); // R
		if (!flag)
			return right;

		// V
		if (abs(left - right) > 1) // 节点失衡了
		{
			flag = false;
		}
		return max(left, right);
	}

求中序遍历倒数第K个节点

// 求中序倒数第K个节点
	int getVal(int k)
	{
		Node *node = getVal(root_, k);
		if (node == nullptr)
		{
			string err = "no No.";
			err += k;
			throw err;
		}
		else
		{
			return node->data_;
		}
	}


int i = 1;
	Node* getVal(Node *node, int k)
	{
		if (node == nullptr)
			return nullptr;

		Node *left = getVal(node->right_, k); // R
		if (left != nullptr)
			return left;
		// V
		if (i++ == k) // 在VRL的顺序下,找到正数第k个元素
		{
			return node;
		}
		return getVal(node->left_, k); // L
	}

析构

~BSTree() 
	{
		if (root_ != nullptr)
		{
			queue<Node*> s;
			s.push(root_);
			while (!s.empty())
			{
				Node *front = s.front();
				s.pop();

				if (front->left_ != nullptr)
				{
					s.push(front->left_);
				}
				if (front->right_ != nullptr)
				{
					s.push(front->right_);
				}
				delete front;
			}
		}
	}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值