NDK-044: 二叉搜索树

44. 二叉搜索树

定义:【比它(当前根节点)小的放左边,比它(当前根节点)大的放右边】

  1. 普通二叉搜索树的中序遍历,就是从小到大的排序 (解决了 数据排序)
    能快速找到最大值,最小值,能找到排名第一,第二的数据。搜索快。
  2. 删除
    当左右两节点都不为空的情况下,左和右放上去都不行
    从左边找最大值来替代,或者从右边找最小值
  3. 下次(AVL)下周六
    致命的弱点,接近排好序的数据,查找时会退化成 0(N)
    找资料(google)
    左旋,右旋,先左旋后右旋,先右旋后左旋

二叉搜索树,折半查找,O(logN)的级别。
致命的弱点,对与接近排序的数据,查找时 会退化成O(N)级别。
进而衍生出AVL树,两端均衡。

1.二叉搜索树-新增

2.二叉搜索树-查找

3.二叉搜索树-搜索

#include <jni.h>
#include <string>
#include "BST.hpp"
#include <android/log.h>

// 传入回调函数
void visit(int key, int value) {
    __android_log_print(ANDROID_LOG_ERROR, "TAG", "key = %d , value = %d", key, value);
}

extern "C"
JNIEXPORT jstring
JNICALL
Java_com_darren_ndk_day44_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {

    BST<int, int> *bst = new BST<int, int>();
    bst->put(2, 2);
    bst->put(-11, -11);
    bst->put(-13, -13);
    bst->put(0, 0);
    bst->put(8, 8);
    bst->put(3, 3);
    bst->put(7, 7);

    bst->remove(2);
    bst->inOrderTraverse(visit); // 中序遍历
  
    int* value = bst->get(100);
    if(value !=null) {
        //...
    } 
       
    // __android_log_print(ANDROID_LOG_ERROR,"TAG","%d", bst->contains(100));
    // __android_log_print(ANDROID_LOG_ERROR,"TAG","%d", bst->contains(7));
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}
// BST.hpp
#ifndef NDK_DAY44_BST_H
#define NDK_DAY44_BST_H
#include <iostream>

// c++   Map  MlitiMap  红黑树
// java Map 和 c++ Map 比较
template<class K, class V> // 两个泛型key,value
struct TreeNode {
public:
    TreeNode(TreeNode<K, V> *pNode) {
        this->left = pNode->left;
        this->right = pNode->right;
        this->key = key;
        this->value = value;
    }
    // 左右指针
    TreeNode<K, V> *left = NULL;
    TreeNode<K, V> *right = NULL;
   // 数据域
    K key;
    V value;

    TreeNode(K key, V value) {
        this->right = NULL;
        this->left = NULL;
        this->key = key;
        this->value = value;
    }
};

template<class K, class V>
class BST {
    TreeNode<K, V> *root;// 根节点
    int count; // 个数

public:
    BST() {
        root = NULL;
        count = 0;
    }
    ~BST() {
        // 大家自己去完成,delete所有节点。递归去delete。
    }

public:
// 新增 (key相等时 修改)
    void put(K key, V value) {
        root = addNode(root, key, value);
    }

    // 查找 (自己实现)
// 1.先判断是否包含,包含了再去查找,没包含不查找;
// 2.没找到返回V*, 没找到返回NULL。
    V *get(K key) {
        return NULL;
    }
    int size() {
        return count;
    }

    // 是否包含目标key,采用非递归方式实现(迭代)。
    bool contains(K key) {
        TreeNode<K, V> *node = root;
        while (node) {
            if (node->key == key) { // 找到了
                return node->value;
            } else if (node->key > key) { // 左子树中继续找
                node = node->left;
            } else { // 右子树中继续找
                node = node->right;
            }
        }
        return false;
    }

    // 删除 (最主要的内容)
    void remove(K key) {
        // 分情况解决
        root = removeNode(root, key);
    }

    // 中序遍历
    void inOrderTraverse(void (*fun)(K, V)) {
        inOrderTraverse(root, fun);
    }

private:
    // 返回一个节点 ,多去理解
    TreeNode<K, V> *addNode(TreeNode<K, V> *pNode, K key, V value) {
        if (pNode == NULL) {
            count++;
            return new TreeNode<K, V>(key, value); // 根节点
        }

        // 比较key
        if (pNode->key > key) {// 小:当前的key  大于插入的key,递归:插入到左边子树。
            pNode->left = addNode(pNode->left, key, value);
        } else if (pNode->key < key) { // 大,递归:插入到右子树中。
            pNode->right = addNode(pNode->right, key, value);
        } else { // 相等,更新value值
            pNode->value = value;
        }
        return pNode;
    }

    // 移除节点:重点代码,递归删除节点
    TreeNode<K, V> *removeNode(TreeNode<K, V> *pNode, K key) {
        if (pNode->key > key) { // 1.在左子树中递归删除
            pNode->left = removeNode(pNode->left, key);
        } else if (pNode->key < key) { //2. 在右子树中递归删除
            pNode->right = removeNode(pNode->right, key);
        } else { // 3.相等----关键代码
            count--;
            if (pNode->left == NULL && pNode->right == NULL) {
                // 3.1 左右叶子节点都为空,直接删除pNode节点
                delete pNode;
                return NULL; // 父节点的指向变成空。
            } else if (pNode->left == NULL) { // 3.2 左节点为空,有节点不为空
                TreeNode<K, V> *right = pNode->right; // 左边没有,把右边放上去。
                delete (pNode);
                return right;
            } else if (pNode->right == NULL) { // 3.3 右节点为空,左节点不为空
                TreeNode<K, V> *left = pNode->left; // 保存一下
                delete (pNode);
                return left;
            } else {
                // 3.4 左右两子树都不为空,最关键代码。要找一个节点来代替它。
                // 从左边找最大值来替代,或者从右边找最小值. 找前驱或后进。
                TreeNode<K, V> *successor = new TreeNode<K, V>(maximum(pNode->left)); // 左边的最大节点
                successor->left = deleteMax(pNode->left); 
                count++;  // 节点挪上来
                successor->right = pNode->right;
                delete (pNode);
                return successor;
            }
        }
        return pNode;
    }

    TreeNode<K, V> *deleteMax(TreeNode<K, V> *pNode) { // 删除最大值
        if (pNode->right == NULL) {
            TreeNode<K, V> *left = pNode->left;
            delete (pNode);
            count--;
            return left;
        }
        pNode->right = deleteMax(pNode->right);
        return pNode;
    }

    // 查找当前树的最大值(不断地往右边找,直到 右边为空就找到了 最大值) 
    // (最小值怎么找?),不断往左边找,
    TreeNode<K, V> *maximum(TreeNode<K, V> *pNode) {
        // 不断的往右边找,直到找到右子树为空节点
        if (pNode->right == NULL) {
            return pNode; // 找到了
        }
        return maximum(pNode->left); // 递归查找
    }

    // 中序遍历:递归
    void inOrderTraverse(TreeNode<K, V> *pNode, void (*pFunction)(K, V)) {
        if (pNode == NULL) { // 0.递归到底了,递归结束
            return;
        }
        inOrderTraverse(pNode->left, pFunction); // 1.遍历左边
        pFunction(pNode->key, pNode->value);    // 2.访问自身
        inOrderTraverse(pNode->right, pFunction); // 3.遍历右边
    }
};
#endif //NDK_DAY44_BST_H
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,386评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,142评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,704评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,702评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,716评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,573评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,314评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,230评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,680评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,873评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,991评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,706评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,329评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,910评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,038评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,158评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,941评论 2 355

推荐阅读更多精彩内容