现在的位置: 首页 > 综合 > 正文

BST的插入和删除

2019年10月17日 ⁄ 综合 ⁄ 共 3334字 ⁄ 字号 评论关闭
/*
 * binarySearchTree.cpp
 *
 *  Created on: 2012-4-17
 *      Author: jiyiqin
 *	实现二叉查找树的构造,插入,删除,查找节点等基本操作。
 */
#include <iostream>
#include <string>
#include <stdio.h>

using namespace std;

class BinarySearchTree{
private:

	typedef struct treeNode{
		int value;
		struct treeNode *parent;
		struct treeNode *left;
		struct treeNode *right;
	}NODE;

	NODE *malloc_node(int value, NODE *left, NODE *right){
		NODE *newNode = (NODE *)malloc(sizeof(NODE));
		newNode->value = value;
		newNode->left = left;
		newNode->right = right;
		return newNode;
	}
public:
	NODE *root;

	BinarySearchTree(){
		root = NULL;
	}

	/**
	 * 从一个数组构造BST:
	 * 构造的方法就是从空树开始
	 * 不断插入新的节点
	 * */
	void buildTree(int node[], int length){
		int i;

		for(i=0;i<length;i++){
			cout<<"insert "<<node[i]<<endl;
			insertNode(node[i]);
		}
	}

	/**
	 * 插入节点:
	 * 首先要明白,新插入的节点一定是作为叶子(没有孩子)
	 *	所以说插入的顺序不同,BST的结构会不同
	 *
	 * 所以插入操作就变得很简单,不用分不同情况,两步即可:
	 * (1)找到插入位置(NULL):使用两个指针,一个寻找插入位置,一个指向其父节点;
	 * (2)插入(作为其父节点的儿子);
	 * */
	void insertNode(int newValue){
		NODE *p,*q;

		//if this node have exist
		if(search(root, newValue) != NULL){
			cout<<newValue<<"have existed"<<endl;
			return;
		}

		//insert first node
		if(root == NULL){
			cout<<"root is null"<<endl;
			root = malloc_node(newValue, NULL, NULL);
			return;
		}

		//find insert location
		q = root;
		while(q != NULL){
			p = q;
			if(newValue < q->value)
				q = q->left;
			else
				q = q->right;
		}

		//insert
		NODE *newNode = malloc_node(newValue, NULL, NULL);
		newNode->parent = p;
		if(newNode->value < p->value)
			p->left = newNode;
		else
			p->right = newNode;
	}

	/**
	* 删除节点:分三种情况
	* (1) 待删除节点没有孩子
	*	直接删除,无需调整
	* (2) 待删除节点有一个孩子
	*	将待删除节点的父节点指向待删除节点的孩子
	* (3) 待删除节点有两个孩子
	*	找到待删除节点的后继,同样将其删除(递归),
	*	然后用该后继把待删除节点覆盖掉。
	*	问:如果不是调整其后继,而是调整其前驱可以么?
	*		--- 我觉得是可以
	* */
	void deleteNode(int value){
		NODE *parent, *child, *successor;

		//返回节点指针
		cout<<"delete"<<value<<endl;
		NODE *dnode = search(root,value);		
		
		if(dnode->left == NULL && dnode->right == NULL){		//没有孩子
			
			//直接将叶子删掉
			parent = dnode->parent;
			if(parent->left != NULL && dnode->value == parent->left->value)
				parent->left = NULL;
			else
				parent->right = NULL;
		}
		else if(dnode->left == NULL || dnode->right == NULL){	//一个孩子
			
			//找到待删除节点的孩子(左/右)
			if(dnode->left != NULL){
				child = dnode->left;
			}
			else{
				child = dnode->right;
			}

			//将待删除节点的父节点指向其孩子
			parent = dnode->parent;
			if(parent->left != NULL && dnode->value == parent->left->value)
				parent->left = child;
			else
				parent->right = child;
		}
		else if(dnode->left != NULL && dnode->right != NULL){	//两个孩子

			//找到后继
			successor = searchSuccessor(dnode);

			//递归删除该后继
			deleteNode(successor->value);

			//将后继的卫星数据拷贝到"本来应该删除的节点"
			dnode->value = successor->value;
			
		}
		else{
			cout<<"delete error"<<endl;
		}
	}

	/**
	 * 从node为根的BST上查找value节点
	 * @return
	 * NULL: search fail
	 * not NULL: NODE*
	 * */
	NODE *search(NODE *node, int value){
		if(node == NULL || value == node->value)
			return node;
		if(value < node->value)
			return search(node->left, value);
		else
			return search(node->right, value);
	}

	/**
	 * 返回节点的后继
	 * */
	NODE *searchSuccessor(NODE *node){
		NODE *p,*q;

		//先转向右
		p = node;
		q = p->right;
		if(q == NULL) return NULL;

		//再向左走到头
		while(q != NULL){
			p = q;
			q = q->left;
		}
		return p;
	}

	/**
	 * 递归中序遍历
	 * */
	void printTreeByInOrder(NODE *node){
		if(node != NULL){
			printTreeByInOrder(node->left);
			cout<<node->value<<" ";
			printTreeByInOrder(node->right);
		}
	}

	/**
	 * 随机填充一个数组
	 * */
	void radomArray(int a[], int size){
		int i;
		for(i=0;i<size;i++){
			*a++ = rand() % 30;
		}
	}
};

int main(){
	int a[15];
	BinarySearchTree bst;

	//随机填充数组a
	bst.radomArray(a, 15);

	//用数组a来构造BST
	bst.buildTree(a, 15);

	//中序输出
	cout<<endl<<"In-Order-Out:";
	bst.printTreeByInOrder(bst.root);

	//删除一个节点并中序输出
	cout<<endl;
	bst.deleteNode(a[1]);
	cout<<endl<<"In-Order-Out:";
	bst.printTreeByInOrder(bst.root);

	//删除一个节点并中序输出
	cout<<endl;
	bst.deleteNode(a[2]);
	cout<<endl<<"In-Order-Out:";
	bst.printTreeByInOrder(bst.root);

	//删除一个节点并中序输出
	cout<<endl;
	bst.deleteNode(a[4]);
	cout<<endl<<"In-Order-Out:";
	bst.printTreeByInOrder(bst.root);
	return 0;
}

抱歉!评论已关闭.