C++--二叉搜索树--二叉树的非递归--1022--27

二叉搜索树

特性

一颗二叉树,可以为空,若不为空则满足:1.非空左子树的所有值小于其根节点的值。2.非空右子树的所有值大于其根节点的值。3.左右子树都是二叉搜索树

二叉搜索树的查找效率最好是O(log_2 N),但最差情况下回退化为O(N)

二叉搜索的相关实现

准备工作

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:
	//二叉搜索树的插入
	bool Insert(const K& val)
	{
		if (_root == nullptr)
		{
			_root= new Node(val);
			return true;
		}
		Node* parent = nullptr;
		Node* cur = _root;
		while (cur)
		{
			if (val > cur->_key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (val < cur->_key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				//该搜索二叉树已经有这个值了 插入失败
				return false;
			}
		}
		//cur目前指向空 parent已到位需要链接一下
		cur = new Node(val);
		if (parent->_key < val) parent->_right = cur;
		else parent->_left = cur;
		return true;
	}
        //以下函数为了显示结果看写的代码对不对
    void _InOrder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		_InOrder(root->_left);
		std::cout << root->_key << " ";
		_InOrder(root->_right);
	}
private:
    _root=nullptr;
};

注意:这里_InOder打印调用会出现问题。

BSTree<int> tree1;

//tree._InOder(tree._root);在函数外拿不到this指针。而且递归需要显示的传参数

这里需要封装一层

 再创建一个成员函数InOrder()

class BSTree
{
public:
    void InOrde()
    {
        _InOrder(_root);
    }
};

 测试代码

void Insert_test1()
{
	BSTree<int> tree1;
	int a[] = { 8,3,1,10,6,4,7,14,13 };
	for (auto e : a)
	{
		tree1.Insert(e);
	}
	//tree1.InOrder(tree1._root); 因为InOrder()是成员函数
	//但我在类外拿不到this指针需要在改进一下
	tree1.InOrder();
}

非递归:二叉搜索树的删除

bool Erase(const K& key)
{
	//这部分代码同上 不再重复写了
	else
	{//找到了 开始删除
		//分情况 1、要删除的节点有左子树 2、有右子树 3、都有
	    if (cur->left == nullptr)
		{
			if (cur != _root)
			{
				if (parent->_left == cur) parent->_left = cur->_right;
				else parent->_right = cur->_right;
			}
			else
			{
				_root = cur->_right;
			}
			delete cur;
		}
		else if (cur->right == nullptr)
		{
			if (cur != _root)
			{
				if (parent->_left == cur) parent->_left = cur->_left;
				else parent->_right = cur->_left;
			}
			else
			{
				_root = cur->_left;
			}
			delete cur;
		}
		else
		{
			//采用替换法
			//可以找左子树的最右值,也可以找右子树的最左值,这里采用后者
			Node* parent_minNode = cur;
			Node* minNode = cur->_right;
			while (minNode->_left)
			{
				parent_minNode = minNode;
				minNode = minNode->_left;
			}
			swap(cur->_key, minNode->_key);
			//不确定这个最左值是不是还有右子树

			parent_minNode->left=cur->right;//不准确
			
            delete minNode;

		}
	
		//...
	}

这样会有一种极端情况无法处理 删除根节点key=8

 这里10就是最小的左子树,此时

parent_minNode->right=minNode->right

swap(cur->_key, minNode->_key);
if (minNode == parent_minNode->left)
{
	parent_minNode->_left = minNode->_right;
}
else
{
	parent_minNode->_right = minNode->_right;
}
delete minNode;

 递归法插入:

class BSTree
{
//...
public:
    bool InsertR(const K&key)
	{
		return _InsertR(_root,key);
	}
private:
    bool _InsertR(Node*&root,const K&key)
	{
		if (root == nullptr)
		{
			//开始插入
			Node* cur = new Node(key);
			root = cur;
			return true;
		}

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

递归法删除:

class BSTree
{
//...
pubilc:
    bool EraseR(const K& key)
    {
        return _EraseR(_root,key);
    }

private:
    bool _EraseR(Node*&root,const K& key)
	{
		if (root == nullptr)
		{
			return false;
		}

		if (key > root->_key)
		{
			return _EraseR(root->_right, key);
		}
		else if (key < root->_key)
		{
			return _EraseR(root->_left, key);
		}
		else
		{
			//找到了
			Node* cur = root;
			if (root->_left == nullptr)
				root = root->_right;
			else if (root->_right == nullptr)
				root = root->_left;
			else
			{
				Node* minNode = cur->_right;
				while (minNode->_left)
				{
					minNode = minNode->_left;
				}
				std::swap(minNode->_key, cur->_key);
				return _EraseR(cur->_right, key);
			}
			delete cur;
			return true;
		}
	}
//...
};

测试代码

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

二叉树的非递归遍历

二叉树的非递归前序遍历

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;
            }
            //出来了表示左树全部遍历完毕,只剩右树
            cur=st.top()->right;
            st.pop();
        }
        return v;
    }
};

二叉树的非递归中序遍历

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

题目

1. 根据前序遍历和中序遍历,是可以确定一棵树的结构,使用两个遍历结果确定树的结构, 其中有一个遍历结果必须要是中序遍历结果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值