BST树

BST概念:

BST树叫二叉搜索树,是树的最基本数据结构。主要用处在按值查找数据,这里就有人问了,查询数据直接在一个有序数组中用二分算法不就行了,这样是可以,但这仅仅是一个算法。如果,我们还要为这个数组新增新删,复杂度就为O(n),这时我们的关注点就要聚焦于数据结构了,把底层数组结构实现成BST树,增删查改时间复杂度都为O(long2n)。当然,更高级的还有AVL树,RB树,另外还有哈希表。(注:这里也说明了算法和数据结构相辅相成)

知识点:

  1. 成员变量 struct Node{int data, Node* left, Node* right}; Node* root;

  2. 非递归实现时,由于无法找到父节点,所以要记录父节点

  3. 删除非递归:
    (1)分析问题,待删节点分别有0,1,2个孩子;
    (2)查找待删节点位置;
    (3)2 -》 0/1;2个孩子的情况转换成0/1个孩子的情况,只需将old->data=cur->data就行
    (4)0/1孩子的情况一致,cur把它的孩子给它的父亲就行,无论它的孩子是否为nullptr,cur是待删节点
    (5)特殊情况考虑:若删除的是root,首先对两个孩子的结果不影响,但是对0/1情况要处理,root指向cur的孩子

  4. 递归实现一:框架

void  func(Node* cur)
{
	func(cur->left);
	func(cur->right);
}

很简单,调用两次自身,参数分别穿左右孩子,就能遍历整个树。

  1. 递归实现二:参数
    (1)传值func(int i):下一层不影响上一层的,如i表示当前层数,即使下一层改变完回退后,上一层i也不改变,原来是什么还是什么。
    (2)传引用func(int &i):下一层影响上一层的,如i表示计数,下一层函数num++,回退后,上一层也要改变,要不然基数还有什么意义。
    (3)总结:数组/指针穿的是指针都不会用错,如果参数是容器的话,记得穿引用或指针,如果是变量的话,一定要想清楚,其中子集树中的i常常传值,需要用参数带回去的一般红引用。

  2. 递归实现三:返回值
    返回值不是void的函数递归真的很烧脑,如果想不通,建议直接拿参数带回去,记得这种参数一般都是传引用。但接下来,我们还是要分析一波返回值不是void类型的函数,直接来看例子吧:

Node* getLastK(Node* cur, int& k)
{
	if (cur == nullptr)
		return nullptr;
		
    Node* res = getLastK(cur->right, k);    //(1)
	if (res != nullptr)
	{
		return res;
	}
	if (--k == 0)
	{
		return cur;
	}
	return getLastK(cur->left, k);   //(2)
}

这里,有两处调用了自身函数(1)(2)。(2)很简单,直接就把值返还给上一层就行了。那么,(1)如果这样做return getLastK(cur->right, k); ,这样就永远执行不到下面的语句了,所以它的返回值要有判断。

代码

五个部分:成员变量、构造析构、非递归增删查改、递归增删查改、经典题型

#include<iostream>
#include<vector>

namespace user
{
	template<typename T>
	class BST
	{
	private://成员方法
		struct Node
		{
			Node(T val = T()) :data(val), left(nullptr), right(nullptr) {}
			~Node() {}
			T data;
			Node* left;
			Node* right;
		};
		Node* root;

	public://构造析构
		BST() :root(nullptr) {}

		~BST()
		{
			if (root != nullptr)
			{
				Delete(root);
			}
		}
		void Delete(Node* cur)
		{
			if (cur->left != nullptr)
			{
				Delete(cur->left);
			}

			if (cur->right != nullptr)
			{
				Delete(cur->right);
			}

			delete cur;
		}


	public://非递归
		//增
		void nonInsert(T val)
		{
			if (root == nullptr)
			{
				root = new Node(val);
				return;
			}

			Node* cur = root;
			Node* parent = nullptr;

			while (cur != nullptr)
			{
				parent = cur;
				if (val < cur->data)
				{
					cur = cur->left;
				}
				else if (val > cur->data)
				{
					cur = cur->right;
				}
				else
				{
					std::cout << "程序不支持相同的元素" << std::endl;
					break;
				}
			}

			Node* node = new Node(val);
			if (val < parent->data)
			{
				parent->left = node;
			}
			else
			{
				parent->right = node;
			}
		}

		//按值删除,按位置删除也没有意义
		void nonRemove(T val)
		{
			Node* cur = root;
			Node* parent = nullptr;

			//找位置
			while (cur != nullptr && cur->data != val)
			{
				parent = cur;
				if (val < cur->data)
				{
					cur = cur->left;
				}
				else
				{
					cur = cur->right;
				}
			}
			if (cur == nullptr)
			{
				std::cout << "no val\n";
				return;
			}

			//3 -> 1/2
			if (cur->left != nullptr && cur->right != nullptr)
			{
				Node* old = cur;
				parent = cur;
				cur = cur->left;
				while (cur->right != nullptr)
				{
					parent = cur;
					cur = cur->right;
				}
				old->data = cur->data;
			}

			//1,2本质一样
			Node* child = cur->left;
			if (child == nullptr)
			{
				child = cur->right;
			}
			if (root == cur) //判断root
			{
				root = child;
			}
			else
			{
				if (cur == parent->left)
				{
					parent->left = child;
				}
				else
				{
					parent->right = child;
				}
			}
			delete cur;
		}

		//查
		bool nonselect(int val)
		{
			Node* cur = root;
			while (cur != nullptr)
			{
				if (val == cur->data)
				{
					return true;
				}
				if (val < cur->data)
				{
					cur = cur->left;
				}
				else
				{
					cur = cur->right;
				}
			}
			return false;
		}

		//非递归遍历



	public://递归实现

		//递归删除
		//递归插入
		//递归查找

		//中序
		void inOrder()
		{
			std::cout << "inOrder: ";
			inOrder(root);
			std::cout << "\n";
		}
		void inOrder(Node* cur)
		{
			if (cur == nullptr)
				return;

			inOrder(cur->left);
			std::cout << cur->data << " ";
			inOrder(cur->right);
		}

		//前序
		void preOrder()
		{
			std::cout << "preOrder: ";
			preOrder(root);
			std::cout << std::endl;
		}
		void preOrder(Node* cur)
		{
			if (cur == nullptr)
				return;

			std::cout << cur->data << " ";
			preOrder(cur->left);
			preOrder(cur->right);
		}

		//层序
		void levelOrder()
		{
			std::cout << "levelOrder: ";
			int height = level();
			for (int i = 1; i <= height; ++i)
			{
				levelOrder(root, 1, i);
			}
			std::cout << std::endl;
		}
		void levelOrder(Node* cur, int i, int height)
		{
			if (cur == nullptr)
			{
				return;
			}

			if (i == height)
			{
				std::cout << cur->data << " ";
			}
			else
			{
				levelOrder(cur->left, i + 1, height);
				levelOrder(cur->right, i + 1, height);
			}
		}

		//高度
		int level()
		{
			return level(root);
		}
		int level(Node* cur)
		{
			if (cur == nullptr)
				return 0;

			int leftHeight = level(cur->left) + 1;
			int rightHeight = level(cur->right) + 1;

			return leftHeight > rightHeight ? leftHeight : rightHeight;
		}

		// 递归实现获取BST树节点的总数量
		int number()
		{
			return number(root);
		}
		int number(Node* cur)
		{
			if (cur == nullptr)
				return 0;

			return number(cur->left) + number(cur->right) + 1;
		}



	public://经典例题
		//将树镜像,中序从小到大变为从大到小
		void mirror()
		{
			mirror(root);
		}
		void mirror(Node* cur)
		{
			if (cur == nullptr)
				return;

			Node* tmp = cur->left;
			cur->left = cur->right;
			cur->right = tmp;

			mirror(cur->left);
			mirror(cur->right);
		}

		// 判断一颗二叉树是否是BST树
		bool isBST()
		{
			const int SIZE = number();
			T* arr = new T[SIZE]();
			int pos = 0;
			isBST(root, arr, pos);
			for (int i = 0; i < SIZE - 1; ++i)
			{
				std::cout << arr[i] << " ";
				if (arr[i] > arr[i + 1])
				{
					delete[]arr; //2.所以用智能指针,要不然这里就很容易忘了析构
					return false;
				}
			}
			delete[]arr;
			return true;
		}
		void isBST(Node* cur, T* arr, int& i)//1.这里的i前面的依靠后面的,需要用&接收,和子集树中的变量作用完全不一样
		{
			if (cur == nullptr)
				return;

			isBST(cur->left, arr, i);
			arr[i++] = cur->data;
			isBST(cur->right, arr, i);
		}

		// 找满足指定值区间的元素并打印
		void findAreaData(int first, int last)
		{
			std::vector<T> vec;
			findAreaData(root, first, last, vec);
			for (auto val : vec)
			{
				std::cout << val << " ";
			}
			std::cout << std::endl;
		}
		void findAreaData(Node* node, int first, int last, std::vector<T>& vec)
		{
			if (node == nullptr)
				return;
			findAreaData(node->left, first, last, vec);
			if (node->data > last)
			{
				return;
			}
			if (first <= node->data && last >= node->data)
			{
				vec.push_back(node->data);
			}
			findAreaData(node->right, first, last, vec);
		}

		// 找BST树中,指定的两个值的最近公共祖先节点
		int getLCA(int a1, int a2)
		{
			int min = a1;
			int max = a2;
			if (a2 < a1)
			{
				min = a2;
				max = a1;
			}
			return getLCA(root, min, max);
		}
		int getLCA(Node* cur, int min, int max)
		{
			if (cur->data < min)
			{
				return getLCA(cur->right, min, max);
			}
			else if (cur->data > max)
			{
				return getLCA(cur->left, min, max);
			}
			else
			{
				return cur->data;
			}
		}

		//判断是否是子树
		bool isChildTree(user::BST<T>& bst)
		{
			Node* p = query(_root, bst._root->data);

			return isChildTree(p, bst._root);
		}
		bool isChildTree(Node* node, Node* Cnode)
		{
			if (node == nullptr && Cnode == nullptr)
			{
				return true;
			}

			if (node == nullptr)
			{
				return false;
			}

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

			if (node->_data != Cnode->_data)
			{
				return false;
			}

			return (isChildTree(Node * node->_left, Node * Cnode->_left)
				&& isChildTree(Node * node->_right, Node * Cnode->_right));
		}

		// 找BST树中,中序遍历倒数第K个节点的值并返回
		int getLastK(int k)
		{
			return getLastK(root, k)->data;
		}
		Node* getLastK(Node* cur, int& k)
		{
			if (cur == nullptr)
				return nullptr;

			Node* res = getLastK(cur->right, k);
			if (res != nullptr)
			{
				return res;
			}
			if (--k == 0)
			{
				return cur;
			}
			return getLastK(cur->left, k);
		}

		// 递归实现重建二叉树的过程
	    void rebuild(int* ar, int arsize, int* br, int brsize)
	    {
		    _root = rebuild(ar, 0, arsize - 1, br, 0, brsize - 1);
	    }
	    Node* rebuild(int* ar, int i, int iend, int br[], int j, int jend)
	    {
	  	    if (i > iend || j > jend)
			    return nullptr;

		    // 用前序遍历数组的第一个元素创建根节点
		    Node* node = new Node(ar[i]);
		    for (int k = j; k <= jend; ++k)
		    {
			    if (ar[i] == br[k])
			    {
				   node->_left = rebuild(ar, i + 1, i + (k - j), br, j, k - 1);
				    node->_right = rebuild(ar, i + (k - j) + 1, iend, br, k + 1, jend);
				    break;
			    }
		    }
		    return node;
	    }	
	    	
	};
}

void insertArray(user::BST<int>& bst, int* ar, int size)
{
	for (int i = 0; i < size; ++i)
	{
		bst.nonInsert(ar[i]);
	}
}

int main()
{
	int ar[] = { 58, 28, 12, 23, 34, 46, 80, 79, 92, 99 };
	const int SIZE = sizeof(ar) / sizeof(ar[0]);

	user::BST<int> bst;
	insertArray(bst, ar, sizeof(ar) / sizeof(ar[0]));
	bst.preOrder();
	bst.levelOrder();
	
	std::cout << "number: " << bst.number() << std::endl;	
	std::cout << "nonselect: " << bst.nonselect(78) << std::endl;
	std::cout << "isBST: " << bst.isBST() << std::endl;
	bst.findAreaData(20, 80);
	std::cout << "getLCA: " << bst.getLCA(80, 46) << std::endl;
	std::cout << "getLastK: " << bst.getLastK(4) << std::endl;

	//bst.mirror();
	//bst.inOrder();

	/*
	for (int i = 0; i < SIZE; ++i)
	{
		bst.nonRemove(ar[i]);
		bst.inOrder();
	}*/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值