【数据结构·考研】二叉搜索树的插入与删除

建立一棵二叉搜索树

二叉搜索树的巨大优势就是:在平均情况下,能够在 O(logN) 的时间内完成搜索和插入元素。

递归版本:

//插入值为key的结点(递归) 
TreeNode* insertIntoBST(Tree& t, int key) {
    if(t == NULL){ //找到插入目标 
    	t = new TreeNode;
        t->val = key;
        return t;
    }
    if(key > t->val) t->right = insertIntoBST(t->right,key); //key大于t->val,去右子树寻找 
    else if (key < t->val) t->left = insertIntoBST(t->left,key); //key小于t->val,去左子树寻找
    else return t; //存在值为key的结点,返回  
    return t; //返回这棵树 
}

迭代版本:

//插入值为key的结点(迭代) 
void insertIntoBST2(Tree& t, int key) {
	if(t == NULL){
	    t = new TreeNode;
            t->val = key;
            return;
	}
    TreeNode* p = t;
    while(p != NULL){
        if(key > p->val){ //key大于t->val,去右子树寻找 
            if(p->right == NULL){
                p->right = new TreeNode;
                p->right->val = key; //插入成功 
                return;
            }
			else p = p->right;
        }
		else if(key < p->val){ //key小于t->val,去左子树寻找
            if(p->left == NULL){
                p->left = new TreeNode;
                p->left->val = key; //插入成功 
                return;
            }
			else p = p->left;
        }
        else return; //存在值为key的结点,返回 
    }
}

删除二叉搜索树中值为key的结点

如果该节点是叶子节点,则直接删除它,如果该节点不是叶子节点且有右节点,则用它的后继节点的值替代,然后删除后继节点;如果该节点不是叶子节点且只有左节点,则用它的前驱节点的值替代,然后删除前驱节点。

//中序遍历序列的下一个节点,即比当前节点大的最小节点,简称后继节点。
int successor(TreeNode* p){
    p = p->right;
    while(p->left != NULL) p = p->left;
    return p->val;
}
//中序遍历序列的前一个节点,即比当前节点小的最大节点,简称前驱节点。 
int predecessor(TreeNode* p){
    p = p->left;
    while(p->right != NULL) p = p->right;
    return p->val;
}

//删除值为key的结点 
TreeNode* deleteNode(Tree& t, int key) {
    if(t == NULL) return NULL;
    if(key > t->val) t->right = deleteNode(t->right,key); //如果 key > t->val,说明要删除的节点在右子树
    else if(key < t->val) t->left = deleteNode(t->left,key); //如果 key < t->val,说明要删除的节点在左子树
    else{ //如果 key == root.val,则该节点就是我们要删除的节点
        if(t->left == NULL && t->right == NULL) t = NULL; //如果该节点是叶子节点,则直接删除它
        else if(t->right != NULL){ //如果该节点不是叶子节点且有右节点,则用它的后继节点的值替代,然后删除后继节点
            t->val = successor(t);
            t->right = deleteNode(t->right,t->val);
        }
        else{ //如果该节点不是叶子节点且只有左节点,则用它的前驱节点的值替代,然后删除前驱节点
            t->val = predecessor(t);
            t->left = deleteNode(t->left,t->val);
        } 
    }
    return t;
}

完整代码如下:

#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;

typedef struct node{
	int val;
	struct node* left = NULL;
	struct node* right = NULL;
}TreeNode,*Tree;

void InOrder(Tree& t){ //二叉树中序遍历 
	if(t == NULL) return;
	InOrder(t->left);
	cout<<t->val<<" ";
	InOrder(t->right);
}

//插入值为key的结点(递归) 
TreeNode* insertIntoBST(Tree& t, int key) {
    if(t == NULL){ //找到插入目标 
    	t = new TreeNode;
        t->val = key;
        return t;
    }
    if(key > t->val) t->right = insertIntoBST(t->right,key); //key大于t->val,去右子树寻找 
    else if (key < t->val) t->left = insertIntoBST(t->left,key); //key小于t->val,去左子树寻找
    else return t; //存在值为key的结点,返回  
	return t; //返回这棵树 
}

//插入值为key的结点(迭代) 
void insertIntoBST2(Tree& t, int key) {
	if(t == NULL){
	    t = new TreeNode;
            t->val = key;
            return;
	}
    TreeNode* p = t;
    while(p != NULL){
        if(key > p->val){ //key大于t->val,去右子树寻找 
            if(p->right == NULL){
                p->right = new TreeNode;
                p->right->val = key; //插入成功 
                return;
            }
			else p = p->right;
        }
		else if(key < p->val){ //key小于t->val,去左子树寻找
            if(p->left == NULL){
                p->left = new TreeNode;
                p->left->val = key; //插入成功 
                return;
            }
			else p = p->left;
        }
        else return; //存在值为key的结点,返回 
    }
}

//中序遍历序列的下一个节点,即比当前节点大的最小节点,简称后继节点。
int successor(TreeNode* p){
    p = p->right;
    while(p->left != NULL) p = p->left;
    return p->val;
}
//中序遍历序列的前一个节点,即比当前节点小的最大节点,简称前驱节点。 
int predecessor(TreeNode* p){
    p = p->left;
    while(p->right != NULL) p = p->right;
    return p->val;
}

//删除值为key的结点 
TreeNode* deleteNode(Tree& t, int key) {
    if(t == NULL) return NULL;
    if(key > t->val) t->right = deleteNode(t->right,key); //如果 key > t->val,说明要删除的节点在右子树
    else if(key < t->val) t->left = deleteNode(t->left,key); //如果 key < t->val,说明要删除的节点在左子树
    else{ //如果 key == root.val,则该节点就是我们要删除的节点
        if(t->left == NULL && t->right == NULL) t = NULL; //如果该节点是叶子节点,则直接删除它
        else if(t->right != NULL){ //如果该节点不是叶子节点且有右节点,则用它的后继节点的值替代,然后删除后继节点
            t->val = successor(t);
            t->right = deleteNode(t->right,t->val);
        }
        else{ //如果该节点不是叶子节点且只有左节点,则用它的前驱节点的值替代,然后删除前驱节点
            t->val = predecessor(t);
            t->left = deleteNode(t->left,t->val);
        } 
    }
    return t;
}

//层次遍历按行输出 
void levelOrderTraverse(Tree& t){
	if(t == NULL) return;
	queue<TreeNode*> q;
	TreeNode* p;
	q.push(t);
	while(!q.empty()){
		int width = q.size();
		for(int i = 0;i < width;i ++){
			p = q.front();
			q.pop();
			cout<<p->val<<" ";
			if(p->left) q.push(p->left);
			if(p->right) q.push(p->right);
		}
		cout<<endl;
	}
} 

int main(){
	Tree t = NULL;
	/*
	   4 3 5 1 6
	*/
	cout<<"插入4:"<<endl; 
	insertIntoBST(t,4);
	levelOrderTraverse(t);
	cout<<"插入3:"<<endl;
	insertIntoBST2(t,3);
	levelOrderTraverse(t);
	cout<<"插入5:"<<endl;
	insertIntoBST(t,5);
	levelOrderTraverse(t);
	cout<<"插入1:"<<endl; 
	insertIntoBST2(t,1);
	levelOrderTraverse(t);
	cout<<"插入6:"<<endl; 
	insertIntoBST(t,6);
	levelOrderTraverse(t);
	cout<<"中序遍历:"<<endl; 
	InOrder(t);
	cout<<endl<<"删除4:"<<endl;	 
	deleteNode(t,4);
	levelOrderTraverse(t);
	cout<<"删除5:"<<endl; 	
	deleteNode(t,5);	
	levelOrderTraverse(t);	
}

运行结果:

猜你喜欢

转载自blog.csdn.net/cjw838982809/article/details/108410962