重学数据结构系列之——二叉排序树

学习来源:计蒜客

1.定义

对任意结点,如果左子树不为空,则左子树上所有结点的权值都小于该结点的权值;如果右子树不为空,则右子树上所有结点的权值都大于该结点的权值;任意结点的左子树和右子树都是一棵二叉排序树;

前驱和后继:结点的前驱就是指小于结点权值的结点中,权值最大的一个结点;对应的,结点的后继就是指大于结点权值的结点中,权值最小的一个结点。
我要说:前驱简单来说就是查找左子树中的最大值,后继就是查找右子树中的最小值

2.实现


这里面的实现是以二叉树为基础的: http://blog.csdn.net/u012763794/article/details/50953067

#include<iostream>
using namespace std;
class Node {
public:
    int data;
	//father就是父亲结点,就是往上走一级的那一个
    Node *lchild, *rchild, *father;
    Node(int _data, Node *_father=NULL) {
        data = _data;
        lchild = NULL;
        rchild = NULL;
		father = _father;
    }
    ~Node() {
        if (lchild != NULL) {
            delete lchild;
        }
        if (rchild != NULL) {
            delete rchild;
        }
    }
	//插入函数
	void insert(int value){
		//value已经在二叉树上,直接返回
		if (value == data) {
			return;
		//大于当前结点的数据,在右子树插入,否则在左子树	
		}else if (value > data) {
			//右子树为空,就把value当做新结点,父节点是当前的结点
			if (rchild == NULL) {
				rchild = new Node(value, this);
			}else{
			//否则递归调用插入函数
				rchild->insert(value);
			}
		}else{
		//这里基本跟上面的逻辑差不多,这里是左子树而已
			if (lchild == NULL) {
				lchild = new Node(value, this);
			}else{
				lchild->insert(value);
			}
		}
	}
	//查找函数
	Node* search(int value){
		//value == data,表示查找到了,返回当前结点
		if (value == data) {
			return this;
		//大于当前结点,向右子树查找	
		}else if (value > data) {
			//右子树为空,代表查找失败
			if (rchild == NULL) {
				return NULL;
			//否则递归对右子树调用查找
			}else{
				return rchild->search(value);
			}
		}else{
		//这里基本跟上面的逻辑差不多,这里是左子树而已
			if (lchild == NULL) {
				return NULL;
			}else{
				return lchild->search(value);
			}	
		}
	}
	//查找前驱(简单来说就是在左子树找最大的)
	Node* predecessor(){
		//首先用temp保存左孩子
		Node *temp = lchild;
		//当前的结点和他的右孩子不能为空,这样我们才能继续查找比这个结点的值大的结点
		while (temp != NULL && temp->rchild != NULL) {
			//继续向右孩子查找
			temp = temp->rchild;
		}
		//循环结束,temp就是我们要找的前驱
		return temp;
	}
	//查找后继(简单来说就是在右子树找最小的)
	Node* successor(){
		//首先用temp保存右孩子
		Node *temp = rchild;
		//当前的结点和他的左孩子不能为空,这样我们才能继续查找比这个结点的值小的结点
		while (temp != NULL && temp->lchild != NULL) {
			temp = temp->lchild;
		}
		//循环结束,temp就是我们要找的后继
		return temp;
	}
	//删除结点(只删除度为0或1的结点,度就是分支的数目),这个很方便地删除前驱和后继
	void remove_node(Node *delete_node){
		//用来记录当前结点的孩子结点
		Node *temp = NULL;
		//如果要删除的结点的左孩子不为空
		if (delete_node->lchild != NULL) {
			//更新它的父亲为delete_node的父亲
			temp = delete_node->lchild;
			temp->father = delete_node->father;
			//并且把delete_node的左孩子置为空
			delete_node->lchild = NULL;
		}
		//如果要删除的结点的右孩子不为空
		if (delete_node->rchild != NULL) {
			//更新它的父亲为delete_node的父亲
			temp = delete_node->rchild;
			temp->father = delete_node->father;
			//并且把delete_node的右孩子置为空
			delete_node->rchild = NULL;
		}
		//如果delete_node是父亲的左孩子,则更新temp为delete_node的父亲的左孩子,否则就更新为右孩子
		if (delete_node->father->lchild == delete_node) {
			delete_node->father->lchild = temp;
		}else{
			delete_node->father->rchild = temp;
		}
		//最后删除该结点
		delete delete_node;
	}
	//删除二叉树上value值的结点(原理是将孩子结点的值覆盖value结点上的值)
	bool delete_tree(int value){
		//delete_node:要删除的结点
		//current_node:当前结点(value值的)
		Node *delete_node, *current_node;
		//找到value值所对应的结点
		current_node = search(value);
		//若果返回为空,表明二叉树上没有这么一个结点,返回false,表示删除失败
		if (current_node == NULL) {
			return false;
		}
		//如果左孩子不为空,就找前驱(即用左孩子中最大的替换当前结点的value值,再删除左孩子中最大的结点)
		if (current_node->lchild != NULL) {
			delete_node = current_node->predecessor();
		//如果右孩子不为空,就找后继(即用右孩子中最小的替换当前结点的value值,再删除右孩子中最小的结点)
		}else if (current_node->rchild != NULL) {
			delete_node = current_node->successor();
		//左右孩子都没有,就删除当前结点
		}else{
            delete_node = current_node;
		}
		//将要删除的前驱或后继的值覆盖current_node的值
			/*
			如果有左孩子没有右孩子:delete_node是前驱
			如果有右孩子,不管有没有左孩子:delete_node是后继
			如果左右孩子都没有:delete_node就是current_node
			*/
        current_node->data = delete_node->data;
		//删除delete_node(这样子的delete_node要么就是1度,要么就是0度)
		remove_node(delete_node);
		return true;
		
	}
};
class BinaryTree {
private:
    Node *root;
public:
    BinaryTree() {
        root = NULL;
    }
    ~BinaryTree() {
        if (root != NULL) {
            delete root;
        }
    }
	void insert(int value){
		//若树根为空,以value值建立一个根结点
		if (root == NULL) {
			root = new Node(value);
		}else{
		//否则就调用以root为根的(当前)二叉树的插入函数进行插入	
			root->insert(value);
		}
	}
	bool find(int value){
		//根据查找结果返回
		if(root->search(value) == NULL) {
			return false;
		}else{
			return true;
		}
	}
	//删除二叉树上value值的结点
	bool delete_tree(int value){
		return root->delete_tree(value);
	}
};
int main() {
	BinaryTree binarytree;
	int arr[10] = { 8, 9, 10, 3, 2, 1, 6, 4, 7, 5 };
	for (int i = 0; i < 10; i++) {
		binarytree.insert(arr[i]);
	}
	int value;
	for (int j = 0; j < 2; j++) {
		cin>>value;
		if(binarytree.find(value)) {
			cout<<"search success!"<<endl;		
		}else{
			cout<<"search failed!"<<endl;
		}
	}
	for (int k = 0; k < 2; k++) {
		cin>>value;
		if (binarytree.delete_tree(value)) {
			cout<<"delete success!"<<endl;
		}else{
			cout<<"delete falied!"<<endl;
		}
	}
    return 0;
}

3.运行结果





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值