二叉查找树

来源:互联网 发布:中国制裁朝鲜 知乎 编辑:程序博客网 时间:2024/05/29 11:05

复习一下二叉查找树, 采用C++来编写。

将节点结构将其作为二叉查找树特用的,定义在类的内部里。

(贴代码的时候我是按照顺序贴的)

template<typename Key, typename Value>class BSTree{public:  typedef struct _TagNode  {    Key _Key;    Value _Value;    struct _TagNode* _pLeft,* _pRight;    //子树    size_t _n;                //以该节点为根的子树节点总数(包含自己)    _TagNode(const Key& keyData, const Value& valueData, size_t nNumber)      : _Key(keyData), _Value(valueData), _n(nNumber), _pLeft(nullptr), _pRight(nullptr)    {    }    _TagNode()      : _Key(Key()), _Value(Value()), _n(0), _pLeft(nullptr), _pRight(nullptr)    {    }  }Node;

该类提供如下方法:

public:  BSTree() : _pRoot(nullptr)  {  }  ~BSTree()  {    if(_pRoot)        Destory(_pRoot);    //销毁树  }    //获取根节点  const Node* getRoot()   {    return _pRoot;  }  //获取一个节点  Node* get(const Key& key)  {    return get(_pRoot, key);  }    //添加一个新的节点  void put(const Key& key, const Value& value)  {    put(&_pRoot, key, value);  }  //树的最小值节点  Node* min()  {    if (_pRoot == nullptr)      return nullptr;    return min(_pRoot);  }  //树的最大值节点    Node* max()  {    if (_pRoot == nullptr)      return nullptr;    return max(_pRoot);  }  //找到相同的键值获取(向下取)  Node* floor(const Key& key)  {    return floor(_pRoot, key);  }  //向上取  Node* ceiling(const Key& key)  {    return ceiling(_pRoot, key);  }  void deleteMin()  {    deleteMin(&_pRoot);  }  void deleteNodeByKey(const Key& key)  {    deleteNodeByKey(&_pRoot, key);  }  //某个区间内的所有节点  vector<Node*> getNodesByKey(const Key& keyLo, const Key& keyHi)  {    vector<Node*> vet;    getNodesByKey(_pRoot, vet, keyLo, keyHi);    return vet;  }




- 实现的代码都是私有的并且都是静态函数还将用到二级指针

private:  //实现    static void Destory(Node* pNode)    {       if(pNode == nullptr){           return;       }       Destory(pNode->_pLeft);       Destory(pNode->_pRight);       delete pNode;    }  static void getNodesByKey(Node* pNode, vector<Node*>& vet, const Key& keyLo, const Key& keyHi)  {    if (pNode == nullptr)      return;    int nLo = keyLo - pNode->_Key, nHi = keyHi - pNode->_Key;    if (nLo <= 0 && nHi >= 0) {      vet.push_back(pNode);     }    if (nLo < 0) getNodesByKey(pNode->_pLeft, vet, keyLo, keyHi); //说明键值还可以更小,需要继续往小的找    if(nHi > 0) getNodesByKey(pNode->_pRight, vet, keyLo, keyHi);//说明键值还可以更大  }  static void deleteMin(Node** ppNode)  {    vector<Node*> arrEachNode;        //之前遍历的节点 用于更新节点值    while (*ppNode) {      if ((*ppNode)->_pLeft == nullptr) { //没有左节点 说明该节点为最小        Node* pTmp = (*ppNode)->_pRight;        delete (*ppNode);                 //删除节点        *ppNode = pTmp;        //在这里遍历方向并不是重点        for (auto it = arrEachNode.rbegin(); it != arrEachNode.rend(); ++it) {          --((*it)->_n);        }        break;      }      arrEachNode.push_back(*ppNode);     //走过的节点      ppNode = &((*ppNode)->_pLeft);    }  }  //弹出一个最小的node  static Node* popMinNode(Node** ppNode)  {    vector<Node*> arrEachNode;        //之前遍历的节点 用于更新节点值    while (*ppNode) {      if ((*ppNode)->_pLeft == nullptr) { //没有左节点 说明该节点为最小        Node* pTmp = *ppNode;             //保存弹出的节点        *ppNode = (*ppNode)->_pRight;        //在这里遍历方向并不是重点        for (auto it = arrEachNode.rbegin(); it != arrEachNode.rend(); ++it) {          --((*it)->_n);        }        pTmp->_pLeft = pTmp->_pRight = nullptr;        pTmp->_n = 1;        return pTmp;      }      arrEachNode.push_back(*ppNode);     //走过的节点      ppNode = &((*ppNode)->_pLeft);    }    return nullptr;  }  /*  //删除一个节点,需要遍历走过的节点,重新计算值  static void deleteNode(Node** ppNode, vector<Node*>& arr)  {  }  */  static void deleteNodeByKey(Node** ppNode, const Key& key)  {    vector<Node*> arrEachNode;        //之前遍历的节点 用于更新节点值    while (1) {      if (*ppNode == nullptr)         //找不到就走人        return;      arrEachNode.push_back(*ppNode); //记录      int nNum = key - (*ppNode)->_Key;      if (nNum < 0) ppNode = &((*ppNode)->_pLeft);      else if (nNum > 0) ppNode = &((*ppNode)->_pRight);      else {  //找到了        Node* pTmp = nullptr;        //之前走过的路都要减1        for (auto it = arrEachNode.rbegin(); it != arrEachNode.rend(); ++it) {          --((*it)->_n);        }        int nSwitch = 0;    //用于判断是否有孩子节点为空 如果有为空 直接将另外的孩子赋值到该节点上即可        if ((*ppNode)->_pLeft == nullptr) nSwitch = 1;        else if((*ppNode)->_pRight == nullptr) nSwitch = 2;        if (nSwitch != 0) {          if (nSwitch == 1) pTmp = (*ppNode)->_pRight;  //没有左孩子 可以直接将右孩子赋予节点          else if (nSwitch == 2) pTmp = (*ppNode)->_pLeft;          //else assert(0 && "nSwitch");          delete (*ppNode);                 //删除节点          //在这里并不需要重新计算该节点的值,因为孩子节点的值已经确定了下来,另外的孩子节点是null 所以并不需要更新          *ppNode = pTmp;          return;        }        pTmp = popMinNode(&((*ppNode)->_pRight));        pTmp->_pRight = (*ppNode)->_pRight;        pTmp->_pLeft = (*ppNode)->_pLeft;        delete (*ppNode);        pTmp->_n = 1;     //重新计算节点的值,因为2个孩子的值并不确定所以需要更新。        if (pTmp->_pLeft) pTmp->_n += pTmp->_pLeft->_n;        if (pTmp->_pRight) pTmp->_n += pTmp->_pRight->_n;        *ppNode = pTmp;        return;      }    }  }  static Node* min(Node* pNode)  {    while (pNode->_pLeft) {      pNode = pNode->_pLeft;    }    return pNode;  }  static Node* max(Node* pNode)  {    while (pNode->_pRight) {      pNode = pNode->_pRight;    }    return pNode;  }  static Node* ceiling(Node* pNode, const Key& key)  {    while (pNode) {      int nNum = key - pNode->_Key;      if (nNum > 0) pNode = pNode->_pRight;    //给定的key大于当前根节点 只能往右找大值了。      else if (nNum == 0) break;              //找到break                                              //key小于当前根节点 说明 只能往左找 找接近于key的值 如果找不到说明就是这个值了(向上取)      else {        Node* pTmp = floor(pNode->_pLeft, key);        if (pTmp)          pNode = pTmp;        break;      }    }    return pNode;  }  static Node* floor(Node* pNode, const Key& key)  {    while (pNode) {      int nNum = key - pNode->_Key;      if (nNum < 0) pNode = pNode->_pLeft;    //给定的key小于当前根节点 只能往左找小值了。      else if (nNum == 0) break;              //找到break      //key大于当前根节点 说明 只能往右找 找接近于key的值 如果找不到说明就是这个值了(向下取)      else {        Node* pTmp = floor(pNode->_pRight, key);        if (pTmp)          pNode = pTmp;        break;      }    }    return pNode;  }  static void put(Node** ppNode, const Key& key, const Value& value)  {    vector<Node*> arrEachNode;        //之前遍历的节点 用于更新节点值    while (1) {      if (*ppNode == nullptr) {        *ppNode = new Node(key, value, 1);        //在这里遍历方向并不是重点        for (auto it = arrEachNode.rbegin(); it != arrEachNode.rend(); ++it) {          ++((*it)->_n);        }        return;      }      arrEachNode.push_back(*ppNode);      int nNum = key - (*ppNode)->_Key;      if (nNum < 0) ppNode = &((*ppNode)->_pLeft);      else if (nNum > 0) ppNode = &((*ppNode)->_pRight);      else {        (*ppNode)->_Value = value;        return;      }    }  }  static Node* get(Node* pNode, const Key& key)  {    while (pNode) {      int nNum = key - pNode->_Key;      if (nNum < 0) pNode = pNode->_pLeft;      else if (nNum > 0) pNode = pNode->_pRight;      else break;    }    return pNode;  }

类的属性只有一个

private:  Node* _pRoot; };

总结: 删除节点的实现,要注意细节,三种遍历方式需要熟悉。

0 0
原创粉丝点击