zoukankan      html  css  js  c++  java
  • 重学数据结构系列之——二叉排序树

    学习来源:计蒜客

    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.运行结果





  • 相关阅读:
    win10 创建安卓模拟器及启动的方法
    win10 virtualenv
    win10安装nodejs
    python模块打包方法
    win10 安装java
    git push后自动部署
    ubuntu配置无密码登录
    mysql while,loop,repeat循环,符合条件跳出循环
    centos 安装mysql密码修改后还是不能连接的原因
    查看SQLServer数据库信息的SQL语句
  • 原文地址:https://www.cnblogs.com/cnsec/p/13286556.html
Copyright © 2011-2022 走看看