算法 & 数据结构——二叉排序树

特性:

  • a. 若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值
  • b. 若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值
  • c. 它的左、右子树也分别为排序二叉树

优点:
因为左子节点总是比父节点小,右子节点总是比父节点大,因此可以使用二分查找提高速度。

算法:

  • 查找,插入,删除,遍历

查找: 已知,查找一个节点key

  • a. 若key小于当前节点,则跟当前节点左子节点比较
  • b. 若key大于当前节点,则跟当前节点右子节点比较
  • c. 若key等于当前节点,则返回当前节点引用
  • d. 若没有找到节点,则返回已查找到最后一个节点的左/右子节点引用(此返回的引用值为nullptr)
  • e. 重复a, b

插入: 已知,插入一个节点key

  • a.查询key
  • c.若返回无效引用,则key替换引用
  • c.若返回有效引用,则忽略本次操作

删除: 已知,删除一个节点key

  • a.查询key
  • b.若返回无效引用,则忽略本次操作
  • c.若返回有效引用,则操作如下:
  • --- a.若引用左/右子节点同时不为空,则以中序优先查询到key的直接前驱,将前驱替换到key的位置,最后删除key
  • --- b.若引用左子节点不为空,则删除引用左子节点
  • --- c.若引用右自己点不为空,则删除引用右子节点
  • --- d.若引用为叶子节点,则直接删除引用

遍历: 二叉树遍历算法即可

配图:

C++实现:

#include <string>
#include <iostream>
#include <functional>

#define SAFE_DELETE(p) delete p; p = nullptr;

template <class Key, class Value>
struct STNode {
    STNode(const Key & k, const Value & v)
        : parent(nullptr), rchild(nullptr)
        , lchild(nullptr), key(k), val(v)
    { }

    ~STNode()
    {
        SAFE_DELETE(lchild);
        SAFE_DELETE(rchild);
    }

    Key key;
    Value val;
    STNode *parent, *rchild, *lchild;
};

template <class Key, class Value>
class STree {
public:
    typedef STNode<Key, Value> Node;

public:
    STree() : _root(nullptr) 
    { }

    ~STree()
    { 
        SAFE_DELETE(_root); 
    }

    void ForEach(const std::function<void (Node *)> & fn) 
    { 
        ForEach(_root, fn); 
    }

    Node * Query(const Key & key) 
    { 
        return Query(_root, key); 
    }

    size_t GetSize() 
    { 
        return GetSize(_root); 
    }

    bool IsEmpty() 
    { 
        return nullptr != _root; 
    }

    bool Insert(const Key & key, const Value & val)
    {
        auto parent = (Node *)nullptr;
        auto &insert = Query(_root, key, &parent);
        if (nullptr == insert)
        {
            insert = new Node(key, val);
            insert->parent = parent;
            return true;
        }
        return false;
    }

    void Remove(const Key & key)
    {
        if (auto &del = Query(_root, key)) { Remove(del); }
    }

private:
    size_t GetSize(Node * node)
    {
        if (nullptr != node)
        {
            auto ln = GetSize(node->lchild);
            auto rn = GetSize(node->rchild);
            return 1 + ln + rn;
        }
        return 0;
    }

    void Remove(Node *& node)
    {
        //  三种情况: 
        //  1,叶子节点, 
        //  2,一个子节点, 
        //  3,两个子节点
        auto del = node;
        if (nullptr != node->lchild && nullptr != node->rchild)
        {
            //  中序遍历,找到直接前驱
            auto pre = node->lchild;
            while (nullptr != pre->rchild)
            {
                pre = pre->rchild;
            }
            if (node->lchild == pre)
            {
                pre->parent = node->parent;
                pre->rchild = node->rchild;
            }
            else
            {
                if (nullptr != pre->lchild)
                {
                    pre->lchild->parent = pre->parent;
                }
                pre->parent->rchild = pre->lchild;
                pre->lchild = node->lchild;
                pre->rchild = node->rchild;
                pre->parent = node->parent;
                node->lchild->parent = pre;
                node->rchild->parent = pre;
            }
            node = pre;
        }
        else if (nullptr != node->lchild)
        {
            node->lchild->parent = node->parent;
            node = node->lchild;
        }
        else if (nullptr != node->rchild)
        {
            node->rchild->parent = node->parent;
            node = node->rchild;
        }
        else
        {
            node = nullptr;
        }
        del->lchild = nullptr;
        del->rchild = nullptr;
        SAFE_DELETE(del);
    }

    Node *& Query(Node *& node, const Key & key, Node ** parent = nullptr)
    {
        if (nullptr != node && node->key != key)
        {
            if (nullptr != parent) 
                *parent = node;
            return Query(node->key > key
                ? node->lchild
                : node->rchild, key, parent);
        }
        return node;
    }

    void ForEach(Node * node, const std::function<void(Node *)> & fn)
    {
        if (nullptr != node)
        {
            ForEach(node->lchild, fn);
            ForEach(node->rchild, fn);
            fn(node);
        }
    }

private:
    Node *_root;
};

int main()
{
    STree<int, std::string> tree;
    tree.Insert(50, "val 50");
    tree.Insert(60, "val 50");
    tree.Insert(40, "val 40");
    tree.Insert(70, "val 70");
    tree.Insert(30, "val 30");
    std::cout << tree.GetSize() << std::endl;
    tree.ForEach([&](STNode<int, std::string> * node) {
        std::cout << node->key << ": " << node->val << std::endl;
        tree.Remove(node->key);
    });
    std::cout << tree.GetSize() << std::endl;
    return 0;
}

结束语:

本博文只讲述二叉排序树的原理以及C++简单实现

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

推荐阅读更多精彩内容