BST树(二叉查找树)C++的实现

二叉查找树(Binary Search Tree),也称二叉搜索树、有序二叉树(ordered binary tree),排序二叉树(orted binary tree),是指一棵空树或者具有下列性质的二叉树:

  • 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
  • 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
  • 任意节点的左、右子树也分别为二叉查找树;
  • 没有键值相等的节点

二叉查找树相比于其他数据结构的优势在于查找、插入的时间复杂度较低,均为O(log n)。二叉查找树是基础性数据结构,用于构建更为抽象的数据结构,如集合、multiset、关联数组等。

如图就是一颗BST树

BST树的实现:

template<typename T>
class BSTree
{
public:
	BSTree():_root(nullptr){}

    // 非递归实现BST树的插入操作
	void noninsert(const T &val);
 
    // 非递归实现BST树的删除操作
	void nonremove(const T &val);

    // 非递归实现层序遍历(从根节点开始,一层一层按从左向右的顺序打印BST树节点的值)
	void nonlevelOrder();

    //查看val的值是否存在
        bool query(const T &val);

private:
	// 定义BST树节点的类型
	struct BSTNode
	{
		BSTNode(T data=T()):_data(data),_left(nullptr),_right(nullptr)
		{}
		T _data;
		BSTNode *_left;
		BSTNode *_right;
	};
};

BST树的插入:如果bst是空树,则将s所指结点作为根节点插入,若val等于b的根节点的数据域之值,则返回,若val小于b的根节点的数据域之值,则把s所指节点插入到左子树中,把s所指节点插入到右子树中(新插入节点总是叶子节点)。

    template<class T>
	void BSTree<T>::noninsert(const T &val)
	{
		if(_root == nullptr)
		{
			_root = new BSTNode(val);
			return;
		}

		BSTNode *pre = nullptr;
		BSTNode *cur = _root;
		while(cur != nullptr)
		{
			pre = cur;
			if(val < cur->_data)
			{
				cur = cur->_left;
			}
			else if(val > cur->_data) 
			{
				cur = cur->_right;
			}
			else
			{
				return;
			}
		}

		if(val < pre->_data)
		{
			pre->_left = new BSTNode(val);
		}
		else
		{
			pre->_right = new BSTNode(val);
		}
	}

BST树的删除:在删除BST树的节点时,会发现当前的节点会有三种情况

  1. 被删除的节点下面没有子节点。
  2. 被删除的节点下面只有一个子节点。
  3. 被删除的节点下面有两个子节点。

如果要删除67的值我们可以用前驱节点代替当前待删除的节点,然后直接删除前驱节点即可。

前驱节点:当前节点左子树中最大的值。  后继节点:当前节点右子树中最小的值。

    template<class T>
	void BSTree<T>::nonremove(const T &val)
	{
		// 1. 从_root开始寻找值为val的节点,cur指向它
		BSTNode *pre = nullptr;
		BSTNode *cur = _root;
		while(cur != nullptr)
		{
			if(val < cur->_data)
			{
				pre = cur;
				cur = cur->_left;
			}
			else if(val > cur->_data)
			{
				pre = cur;
				cur = cur->_right;
			}
			else
			{
				break;
			}
		}

		if(cur == nullptr)
			return;

		// 2. 先判断是否满足情况3,如果满足,需要找cur的前驱节点,用前驱把cur节点的值给覆盖掉,直接删前驱
		if(cur->_left != nullptr && cur->_right != nullptr)
		{
			BSTNode *old = cur;
			pre = cur;
			cur = cur->_left;
			while(cur->_right != nullptr)
			{
				pre = cur;
				cur = cur->_right;
			}
			old->_data = cur->_data;
		}
		// 3. 删除情况1和情况2   直接删除cur指针指向的节点就可以了
		BSTNode *child = cur->_left;
		if(child == nullptr)
		{
			child = cur->_right;
		}

		if(pre == nullptr) // cur指向的根节点
		{
			_root = child;
		}
		else
		{
			// 要把删除节点的孩子赋给cur父节点相应的地址域里面
			if(cur == pre->_left)
			{
				pre->_left = child;
			}
			else
			{
				pre->_right = child;
			}
		}
		delete cur;
	}

BST树的遍历

    // 非递归实现层序遍历(从根节点开始,一层一层按从左向右的顺序打印BST树节点的值)    
    template<class T>
	void BSTree<T>::nonlevelOrder()
	{
		// 1.如果_root为空,直接返回
		if(_root == nullptr)
			return;
		// 2._root -> queue
		queue<BSTNode*> que;
		que.push(_root);

		// 3.循环判断队列是否为空, 不为空取出队头元素,分别判断左右孩子是否为nullptr,不为空
		// 就要依次入队,然后打印队头元素,继续判断下一个队头元素
		while(!que.empty())
		{
			BSTNode *front = que.front();
			cout<<front->_data<<" ";
			que.pop();
			if(front->_left != nullptr)
			{
				que.push(front->_left);
			}
			if(front->_right != nullptr)
			{
				que.push(front->_right);
			}
		}
	}

val查找:

template<class T>
	bool BSTree<T>::query(const T &val)
	{
		if(_root == nullptr)
		{
			cout<<"empty tree"<<endl;
			return true;
		}

		BSTNode *cur = _root;
		while(cur != nullptr)
		{
			if(val < cur->_data)
			{
				cur = cur->_left;
			}
			else if(val > cur->_data) 
			{
				cur = cur->_right;
			}
			else
			{
				cout<<"exist"<<endl;
				return true;
			}
		}
		cout<<"not exist"<<endl;
		return false;
	}

测试用例:

int main(int argc, char* argv[])
{
	BSTree<int> bst;
	bst.noninsert(80);
	bst.noninsert(67);
	bst.noninsert(100);
	bst.noninsert(75);
	bst.noninsert(50);
	bst.noninsert(120);
	bst.nonlevelOrder();
	cout<<endl;
	bst.query(75);
	bst.nonremove(75);
	bst.nonlevelOrder();
	cout<<endl;
	bst.query(75);
	cout<<endl;
	return 0;
}
发布了35 篇原创文章 · 获赞 13 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_41078889/article/details/90644787