二分搜索树

 

目录

1.二分查找法,在有序数组arr中,查找target        ~~!!!有序数组!!!~~

2.二分搜索树的查找于插入  不一定是完全二叉树

3.二分搜索树的遍历 深搜 以及层序遍历 广搜

4.删除最大值,最小值

5.二分搜索树任意节点的删除

完整代码


1.二分查找法,在有序数组arr中,查找target        ~~!!!有序数组!!!~~

二分查找

#include <iostream>
using namespace std;

//!!!!!有序数组
//二分查找,在有序数组arr中,查找target
//!!!!!有序数组
template<typename T>
int binarySearch(T arr[], int n, T target){
	//在arr[l....r]之中查找target
	int l = 0, r = n-1;
	while(l<=r){
		//int mid = (l + r)/2;
		int mid = l + (r-l)/2;
		if( arr[mid] == target ){
			return mid;
		}
		if( arr[mid] < target ){
			r = mid - 1;
		}
		else{
			l = mid + 1;
		}
	}
	return -1;
} 
int main(){
	return 0;
}

2.二分搜索树的查找于插入  不一定是完全二叉树

每个节点的健值大于左孩子
每个节点的健值小于右孩子
以左右为根的子树仍为二分搜索树

#include <iostream>
using namespace std;
/*二分搜索树  不一定是完全二叉树
每个节点的健值大于左孩子
每个节点的健值小于右孩子
以左右为根的子树仍为二分搜索树
*/
template<typename Key, typename Value>
class BST{
private:
	struct Node{
		Key key;//键值对
		Value value;
		Node *left;//左右孩子
		Node *right;

		NOde(Key key, Value value){
			this->key = key;
			this->value = value;
			this->left = this->right = NULL;
		}
	};
	Node *root; //指针
	int count;//共有多少节点

public:
	BST(){
		root = NULL; 
		count = 0;
	}
	~BST(){
	
	}
	int size(){
		return count;
	}
	int isEmpty(){
		return count = 0;
	}
	int insert(Key key, Value value){
		root = insert(root, key, value);
	}
	bool contain(Key key){
		return contain(root,key);
	}
	/*
	search的返回值有3种方案:
	1.返回Node,需要暴露Node类型,用于还要了解Node结构,不好
	2.返回Value,C++中返回变量不允许为NULL(查找不到节点的时候需要返回NULL),需要结合contain函数尽心预判断,太麻烦也不好
	3.最佳方案,返回Value*,指针可以为空,最为理想
	*/
	Value* search(Key key){
		return search( root, key );
	}
private:
	//向以node为跟的二叉搜索树中,插入节点(key, value)
	//返回插入新节点后的二叉搜索树
	Node* insert(Node *node, Key key, Value value){
		if(node == NULL){
			count ++;
			return new Node(key,value);
		}
		if(key == node->key)
			node->value = value;
		else if( key < node->key )
			node->left = insert( node->left, key, value);
		else
			node->right = insert(node->right,key,value);
		return node;
	}
	//查看以node为跟的二叉搜索树中是否包含键值为key的节点
	bool contain(Node* node, Key key){
		if(node == NUll) return false;
		if( key == node->key)
			return true;
		else if( key < node->key )
			return contain(root->left,key);
		else 
			return contain(root->right,key);
	}
	//是以node为跟的二叉搜索树中查找key所对定的value
	Value* search(Node* node, Key key){
		if(node == NUll) return NULL;
		if( key == node->key)
			return &(node->key);
		else if( key < node->key )
			return search(root->left,key);
		else 
			return search(root->right,key);
	}
}
int main(){
	return 0;
}

3.二分搜索树的遍历 深搜 以及层序遍历 广搜

二分搜索树的前中后序遍历
    前序遍历:先访问当前节点,再依次递归左右子树。
    中序遍历:先访问左子树,在访问自身,再递归访问右子树。
    后序遍历:先递归访问左右子树,在访问自身节点。


#include <iostream>
using namespace std;
/*二分搜索树  不一定是完全二叉树
每个节点的健值大于左孩子
每个节点的健值小于右孩子
以左右为根的子树仍为二分搜索树
*/
/*
二分搜索树的前中后序遍历
	前序遍历:先访问当前节点,再依次递归左右子树。
	中序遍历:先访问左子树,在访问自身,再递归访问右子树。
	后序遍历:先递归访问左右子树,在访问自身节点。
*/
template<typename Key, typename Value>
class BST{
private:
	struct Node{
		Key key;//键值对
		Value value;
		Node *left;//左右孩子
		Node *right;
 
		NOde(Key key, Value value){
			this->key = key;
			this->value = value;
			this->left = this->right = NULL;
		}
	};
	Node *root; //指针
	int count;//共有多少节点
 
public:
	//前序遍历
	void preOrder(){
		preOrder(root);
	}
	//中序遍历
	void inOrder(){
		inOrder(root);
	}
	//后序遍历
	void postOrder(){
		postOrder(root);
	}
	//层序遍历
	void levelOrder(){
		queue<Node*> q;
		q.push(root);//入驻根节点
		while(!q.empty()){
			Node* node = q.front();//每次取出队首元素
			q.pop();

			cout<<node->ley<<endl;
			if(node->left)//如果有左孩子就入队
				q.push( node->left);
			if(node->right)//如果有右孩子就入队
				q.push( node->right);

		}
	}
private:

	//是以node为跟的二叉搜索树前序遍历
	void preOrder(Node* node){
		if( node != NULL){
			cout<<node->key<<endl;
			preOrder(node->left);
			preOrder(node->right);
		}
	}
	//是以node为跟的二叉搜索树中序遍历
	void inOrder(Node* node){
		if( node != NULL){
			inOrder(node->left);
			cout<<node->key<<endl;
			inOrder(node->right);
		}
	}
	//是以node为跟的二叉搜索树中序遍历
	void postOrder(Node* node){
		if( node != NULL){
			postOrder(node->left);
			postOrder(node->right);
			cout<<node->key<<endl;
		}
	}
	void destory(Node* node){
		if( node != NULL ){
			destory(node->left);
			destory(node->right);

			delete node;
			count--;
		}
	}
}
int main(){
	return 0;
}

4.删除最大值,最小值

        删除最小值:
            递归向左找到第一个没有左孩子的节点,就是最小值,然后用该节点的右子节点代替当前节点位置。
        删除最大值:
            递归向右找到第一个没有右孩子的节点,就是最大值,然后用该节点的左子节点代替当前节点位置。

#include <iostream>
#include <queue>
#include <cassert>
using namespace std;
/*二分搜索树  不一定是完全二叉树
每个节点的健值大于左孩子
每个节点的健值小于右孩子
以左右为根的子树仍为二分搜索树
*/
/*
二分搜索树的前中后序遍历
	前序遍历:先访问当前节点,再依次递归左右子树。
	中序遍历:先访问左子树,在访问自身,再递归访问右子树。
	后序遍历:先递归访问左右子树,在访问自身节点。
*/
template<typename Key, typename Value>
class BST{
private:
	struct Node{
		Key key;//键值对
		Value value;
		Node *left;//左右孩子
		Node *right;
 
		NOde(Key key, Value value){
			this->key = key;
			this->value = value;
			this->left = this->right = NULL;
		}
	};
	Node *root; //指针
	int count;//共有多少节点
 
public:
/*
	删除最小值:
		递归向左找到第一个没有左孩子的节点,就是最小值,然后用该节点的右子节点代替当前节点位置。
	删除最大值:
		递归向右找到第一个没有右孩子的节点,就是最大值,然后用该节点的左子节点代替当前节点位置。
*/
		//寻找最小的键值
	    Key minimum(){
			assert(count != 0);
			Node* minNode = minimim( root );
			return minNode->key;
		}
		//寻找最大的键值
		Key maximum(){
			assert(count != 0);
			Node* maximum = maximum( root );
			return maximum->key;
		}
		//在二叉树中删除最小值所在节点
		void removeMin(){
			if( root ){
				root = removeMin( root );
			}
		}
		//在二叉树中删除最大值所在节点
		void removeMax(){
			if( root ){
				root = removeMax( root );
			}
		}
	}
private:
	Node* minimum(Node* node){
		if( node->left == NULL)
			return node;

		return minimum(node->left);
	}
	Node* maximum(Node* node){
		if( node->right == NULL)
			return node;

		return maximum(node->right);
	}
	//删除以node为根的二分搜索树中的最小节点
	//返回删除节点后新的二分搜索树的根
	Node* removeMin(Node* node){
		if( node->left == NULL ){

			Node* rightNode = node->right;
			delete node;
			count--;
			return rightNode;
		}
		node->left = removeMin(node->left);
		return node;
	}
	//删除以node为根的二分搜索树中的最大节点
	//返回删除节点后新的二分搜索树的根
	Node* removeMax(Node* node){
		if( node->right == NULL ){

			Node* leftNode = node->left;
			delete node;
			count--;
			return leftNode;
		}
		node->left = removeMax(node->right);
		return node;
	}

};
int main(){
	return 0;
}

5.二分搜索树任意节点的删除

 

  1. 如果要删除的元素没有左子树,那么把右子树接上即可,参考removeMin
  2. 如果要删除的元素没有右子树,那么把左子树接上即可,参考remvoeMax
  3. 如果要删除的元素左右子树都存在,那么可以拿右子树的最左边的节点(后继)代替删除元素或者拿左子树的最右节点(前驱代替删除元素,事实上,如果将所有元素排好序,任何元素的前一个元素正是位于左子树的最右节点(前驱),后一个元素正是右子树的最左节点(后继)
    
    #include <iostream>
    #include <queue>
    #include <cassert>
    using namespace std;
    /*二分搜索树  不一定是完全二叉树
    每个节点的健值大于左孩子
    每个节点的健值小于右孩子
    以左右为根的子树仍为二分搜索树
    */
    
    template<typename Key, typename Value>
    class BST{
    private:
    	struct Node{
    		Key key;//键值对
    		Value value;
    		Node *left;//左右孩子
    		Node *right;
     
    		Node(Key key, Value value){
    			this->key = key;
    			this->value = value;
    			this->left = this->right = NULL;
    		}
    		Node(Node *node){
    			this->key = node->key;
    			this->value = node->value;
    			this->left = node->left;
    			this->right = node->right;
    		}
    
    	};
    	Node *root; //指针
    	int count;//共有多少节点
     
    public:
    
    		/*
    		删除最小值:
    			递归向左找到第一个没有左孩子的节点,就是最小值,然后用该节点的右子节点代替当前节点位置。
    		删除最大值:
    			递归向右找到第一个没有右孩子的节点,就是最大值,然后用该节点的左子节点代替当前节点位置。
    		*/
    		//寻找最小的键值
    		Key minimum(){
    			assert(count != 0);
    			Node* minNode = minimim( root );
    			return minNode->key;
    		}
    		//寻找最大的键值
    		Key maximum(){
    			assert(count != 0);
    			Node* maximum = maximum( root );
    			return maximum->key;
    		}
    		//在二叉树中删除最小值所在节点
    		void removeMin(){
    			if( root ){
    				root = removeMin( root );
    			}
    		}
    		//在二叉树中删除最大值所在节点
    		void removeMax(){
    			if( root ){
    				root = removeMax( root );
    			}
    		}
    /*二分搜索树节点的删除
      1、如果要删除的元素没有左子树,那么把右子树接上即可,参考removeMin
      2、如果要删除的元素没有右子树,那么把左子树接上即可,参考remvoeMax
      3、如果要删除的元素左右子树都存在,那么可以拿右子树的最左边的节点(后继)
    	 代替删除元素或者拿左子树的最右节点(前驱)代替删除元素,事实上,如果将所有元素排好序,
         任何元素的前一个元素正是位于左子树的最右节点(前驱),后一个元素正是右子树的最左节点(后继)
    */
    		void remove(Key key){
    			root = remove( root, key);
    		}
    	}
    private:
    	Node* minimum(Node* node){
    		if( node->left == NULL)
    			return node;
    
    		return minimum(node->left);
    	}
    	Node* maximum(Node* node){
    		if( node->right == NULL)
    			return node;
    
    		return maximum(node->right);
    	}
    	//删除以node为根的二分搜索树中的最小节点
    	//返回删除节点后新的二分搜索树的根
    	Node* removeMin(Node* node){
    		if( node->left == NULL ){
    
    			Node* rightNode = node->right;
    			delete node;
    			count--;
    			return rightNode;
    		}
    		node->left = removeMin(node->left);
    		return node;
    	}
    	//删除以node为根的二分搜索树中的最大节点
    	//返回删除节点后新的二分搜索树的根
    	Node* removeMax(Node* node){
    		if( node->right == NULL ){
    
    			Node* leftNode = node->left;
    			delete node;
    			count--;
    			return leftNode;
    		}
    		node->left = removeMax(node->right);
    		return node;
    	}
    	Node* remove(Node* node,key key){
    		if( node == NULL )
    			return NULL:
    		if( key < node->key ){
    			node->left = remove( node->left ,key );
    			return node;
    		}
    		else if( key > node->key ){
    			node->right = remove( node->right ,key );
    			return node;
    		}
    		else{ // key == node->key
    			if(node->left == NULL){
    				Node* rightNode = node->right;
    				delete node;
    				count--;
    				return rightNode;
    			}
    			if(node->right == NULL){
    				Node* leftNode = node->left;
    				delete node;
    				count--;
    				return leftNode;
    			}
    			//!!!! node->right!=NULL && node->right != NULL !!!
    			//新建一个successor结点,将node结点的右结点 的最小值赋予新的结点
    			Node *successor = new Node(minimum(node->right));
    			count ++;
    			successor->right = removeMin(node->right);
    			successor->right = node->left;
    			delete node;
    			count --;
    			return successor;
    		}
    	}
    };
    int main(){
    	return 0;
    }
    

    完整代码


#include <iostream>
#include <queue>
#include <cassert>
using namespace std;
/*二分搜索树  不一定是完全二叉树
每个节点的健值大于左孩子
每个节点的健值小于右孩子
以左右为根的子树仍为二分搜索树
*/
/*
二分搜索树的前中后序遍历
	前序遍历:先访问当前节点,再依次递归左右子树。
	中序遍历:先访问左子树,在访问自身,再递归访问右子树。
	后序遍历:先递归访问左右子树,在访问自身节点。
*/
template<typename Key, typename Value>
class BST{
private:
	struct Node{
		Key key;//键值对
		Value value;
		Node *left;//左右孩子
		Node *right;
 
		Node(Key key, Value value){
			this->key = key;
			this->value = value;
			this->left = this->right = NULL;
		}
		Node(Node *node){
			this->key = node->key;
			this->value = node->value;
			this->left = node->left;
			this->right = node->right;
		}

	};
	Node *root; //指针
	int count;//共有多少节点
 
public:
	BST(){
		root = NULL; 
		count = 0;
	}
	~BST(){
		destory( root );
	}
	int size(){
		return count;
	}
	int isEmpty(){
		return count = 0;
	}
	int insert(Key key, Value value){
		root = insert(root, key, value);
	}
	bool contain(Key key){
		return contain(root,key);
	}
	/*
	search的返回值有3种方案:
	1.返回Node,需要暴露Node类型,用于还要了解Node结构,不好
	2.返回Value,C++中返回变量不允许为NULL(查找不到节点的时候需要返回NULL),需要结合contain函数尽心预判断,太麻烦也不好
	3.最佳方案,返回Value*,指针可以为空,最为理想
	*/
	Value* search(Key key){
		return search( root, key );
	}
	//前序遍历
	void preOrder(){
		preOrder(root);
	}
	//中序遍历
	void inOrder(){
		inOrder(root);
	}
	//后序遍历
	void postOrder(){
		postOrder(root);
	}
	//层序遍历
	void levelOrder(){
		queue<Node*> q;
		q.push(root);//入驻根节点
		while(!q.empty()){
			Node* node = q.front();//每次取出队首元素
			q.pop();

			cout<<node->ley<<endl;
			if(node->left)//如果有左孩子就入队
				q.push( node->left);
			if(node->right)//如果有右孩子就入队
				q.push( node->right);

		}
		/*
		删除最小值:
			递归向左找到第一个没有左孩子的节点,就是最小值,然后用该节点的右子节点代替当前节点位置。
		删除最大值:
			递归向右找到第一个没有右孩子的节点,就是最大值,然后用该节点的左子节点代替当前节点位置。
		*/
		//寻找最小的键值
		Key minimum(){
			assert(count != 0);
			Node* minNode = minimim( root );
			return minNode->key;
		}
		//寻找最大的键值
		Key maximum(){
			assert(count != 0);
			Node* maximum = maximum( root );
			return maximum->key;
		}
		//在二叉树中删除最小值所在节点
		void removeMin(){
			if( root ){
				root = removeMin( root );
			}
		}
		//在二叉树中删除最大值所在节点
		void removeMax(){
			if( root ){
				root = removeMax( root );
			}
		}
/*二分搜索树节点的删除
  1、如果要删除的元素没有左子树,那么把右子树接上即可,参考removeMin
  2、如果要删除的元素没有右子树,那么把左子树接上即可,参考remvoeMax
  3、如果要删除的元素左右子树都存在,那么可以拿右子树的最左边的节点(后继)
	 代替删除元素或者拿左子树的最右节点(前驱)代替删除元素,事实上,如果将所有元素排好序,
     任何元素的前一个元素正是位于左子树的最右节点(前驱),后一个元素正是右子树的最左节点(后继)
*/
		void remove(Key key){
			root = remove( root, key);
		}
	}
private:
	//向以node为跟的二叉搜索树中,插入节点(key, value)
	//返回插入新节点后的二叉搜索树
	Node* insert(Node *node, Key key, Value value){
		if(node == NULL){
			count ++;
			return new Node(key,value);
		}
		if(key == node->key)
			node->value = value;
		else if( key < node->key )
			node->left = insert( node->left, key, value);
		else
			node->right = insert(node->right,key,value);
		return node;
	}
	//查看以node为跟的二叉搜索树中是否包含键值为key的节点
	bool contain(Node* node, Key key){
		if(node == NUll) return false;
		if( key == node->key)
			return true;
		else if( key < node->key )
			return contain(root->left,key);
		else 
			return contain(root->right,key);
	}
	//是以node为跟的二叉搜索树中查找key所对定的value
	Value* search(Node* node, Key key){
		if(node == NUll) return NULL;
		if( key == node->key)
			return &(node->key);
		else if( key < node->key )
			return search(root->left,key);
		else 
			return search(root->right,key);
	}
	//是以node为跟的二叉搜索树前序遍历
	void preOrder(Node* node){
		if( node != NULL){
			cout<<node->key<<endl;
			preOrder(node->left);
			preOrder(node->right);
		}
	}
	//是以node为跟的二叉搜索树中序遍历
	void inOrder(Node* node){
		if( node != NULL){
			inOrder(node->left);
			cout<<node->key<<endl;
			inOrder(node->right);
		}
	}
	//是以node为跟的二叉搜索树中序遍历
	void postOrder(Node* node){
		if( node != NULL){
			postOrder(node->left);
			postOrder(node->right);
			cout<<node->key<<endl;
		}
	}
	void destory(Node* node){
		if( node != NULL ){
			destory(node->left);
			destory(node->right);

			delete node;
			count--;
		}
	}
	Node* minimum(Node* node){
		if( node->left == NULL)
			return node;

		return minimum(node->left);
	}
	Node* maximum(Node* node){
		if( node->right == NULL)
			return node;

		return maximum(node->right);
	}
	//删除以node为根的二分搜索树中的最小节点
	//返回删除节点后新的二分搜索树的根
	Node* removeMin(Node* node){
		if( node->left == NULL ){

			Node* rightNode = node->right;
			delete node;
			count--;
			return rightNode;
		}
		node->left = removeMin(node->left);
		return node;
	}
	//删除以node为根的二分搜索树中的最大节点
	//返回删除节点后新的二分搜索树的根
	Node* removeMax(Node* node){
		if( node->right == NULL ){

			Node* leftNode = node->left;
			delete node;
			count--;
			return leftNode;
		}
		node->left = removeMax(node->right);
		return node;
	}
	Node* remove(Node* node,key key){
		if( node == NULL )
			return NULL:
		if( key < node->key ){
			node->left = remove( node->left ,key );
			return node;
		}
		else if( key > node->key ){
			node->right = remove( node->right ,key );
			return node;
		}
		else{ // key == node->key
			if(node->left == NULL){
				Node* rightNode = node->right;
				delete node;
				count--;
				return rightNode;
			}
			if(node->right == NULL){
				Node* leftNode = node->left;
				delete node;
				count--;
				return leftNode;
			}
			//!!!! node->right!=NULL && node->right != NULL !!!
			//新建一个successor结点,将node结点的右结点 的最小值赋予新的结点
			Node *successor = new Node(minimum(node->right));
			count ++;
			successor->right = removeMin(node->right);
			successor->right = node->left;
			delete node;
			count --;
			return successor;
		}
	}
};
int main(){
	return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值