特殊数据结构

 

AVL树

节点定义

  template<class T>
  class AVLTreeNode{
    public:
      T key;
      int height;
      AVLTreeNode *left;
      AVLTreeNode *right;
      AVLTreeNode(T value, AVLTreeNode *l, AVLTreeNode *r): key(value), left(l), right(r){}
  }

树的类

  template<class T>
  class AVLTree{
    private:
      AVLTreeNode<T>* root;
    public:

      AVLTree();
      ~AVLTree();

      int height();
      int max(int a, int b);

      void preOrder();
      void inOrder();
      void postOrder();

      AVLTreeNode<T>* search(T key);
      AVLTreeNode<T>* iterativeSearch(T key);
      T minimum();
      T maximum();
      void insert(T key);
      void remove(T key);
      void destroy();
      void print();
    private:
      // 内部接口 
      // 获取树的高度
      int height(AVLTreeNode<T> *tree);
          
      // 前序遍历
      void preOrder(AVLTreeNode<T> *tree) const;
          // 中序遍历
      void inOrder(AVLTreeNode<T> *tree) const;
          // 后序遍历
      void postOrder(AVLTreeNode<T> *tree) const;
          
      // (递归实现)查找AVL树中键值为key的结点
      AVLTreeNode<T>* search(AVLTreeNode<T> *x, T key) const;
      // (非递归实现)查找AVL树中键值为key的结点
      AVLTreeNode<T>* iterativeSearch(AVLTreeNode<T> *x, T key) const;

      // 返回最小结点 
      AVLTreeNode<T>* minimum(AVLTreeNode<T> *tree);
      // 返回最大结点 
      AVLTreeNode<T>* maximum(AVLTreeNode<T> *tree);
          
      // 将结点插入到AVL树中
      AVLTreeNode<T>* insert(AVLTreeNode<T>* &tree, T key);
      // 删除结点,并返回被删除的结点 
      AVLTreeNode<T>* remove(AVLTreeNode<T>* &tree, AVLTreeNode<T> *z);
          
      // 销毁AVL树
      void destroy(AVLTreeNode<T>* &tree);
          
      // 打印AVL树
      void print(AVLTreeNode<T> *tree,T key,int direction);
          
      // LL:左左对应的情况(左单旋转)
      AVLTreeNode<T>* leftLeftRotation(AVLTreeNode<T> *k2);
      // RR:右右对应的情况(右单旋转)
      AVLTreeNode<T>* rightRightRotation(AVLTreeNode<T> *k1);
      // LR:左右对应的情况(左双旋转)
      AVLTreeNode<T>* leftRightRotation(AVLTreeNode<T> *k3);
      // RL:右左对应的情况(右双旋转)
      AVLTreeNode<T>* rightLeftRotation(AVLTreeNode<T> *k1);    
  };

树高度的实现

  template<class T>
  int AVLTree<T>::height(AVLTreeNode<T> *tree){
    // 不为null,返回树最大长度
    if(tree != nullptr){
      return tree->height;
    }
    // 为空树,则返回0
    return 0;
  }

  template<class T>
  int AVLTree<T>::height(){
    return height(root);
  }

旋转的实现

LL的单旋转

当插入或删除节点后,左子树仍然还有左节点,并导致AVL不平衡

  template<class T>
  AVLTreeNode<T>* leftLeftRotation(AVLTreeNode<T> *k2){
    AVLTreeNode<T> * k1;
    k1 = k2->left;
    k2->left = k1->right;
    k1->right = k2;
    k2->height = max(height(k2->left), height(k2->right)) + 1;
    k1->height = max(height(k1->left), height(k1->right)) + 1;
  }

RR的单旋转

当插入或删除节点后,右子树仍然还有右节点,并导致AVL不平衡

  template<class T>
  AVLTreeNode<T>* rightRightRotation(AVLTreeNode<T> *k1){
    AVLTreeNode<T>* k2;
    k2 = k1->right;
    k1->right = k2->left;
    k2->left = k1;

    k1->height = max(height(k1->left), height(k1->right)) + 1;
    k2->height = max(height(k2->left), height(k2->right)) + 1;
  }

LR的双旋转

当插入或删除节点后,左子树仍然还有右节点,并导致AVL不平衡

  template<class T>
  AVLTreeNode<T>* leftRightRotation(AVLTreeNode<T> *k3){
    k3->left = rightRightRotation(k3->left);
    return leftLeftRotation(k3);
  }

RL的双旋转

当插入或删除节点后,右子树仍然还有左节点,并导致AVL不平衡

  template<class T>
  AVLTreeNode<T>* rightLeftRotation(AVLTreeNode<T> *k3){
    k3->right = leftLeftRotation(k3->right);
    return rightRightRotation(k3);
  }

插入的实现

  template<class T>
  AVLTreeNode<T>* insert(AVLTreeNode<T>* &tree, T key){
    if(tree == nullptr){
      tree = new AVLTreeNode<T>(key, NULL, NULL); 
    }
    else if(key < tree->key){
      tree->left = insert(tree->left, key);
      // 判断是否失去平衡
      if(key < tree->left->key){
        // 比左节点小,成为左节点的左节点
        leftLeftRotation(tree);
      }else{
        // 比左节点大,成为左节点的右节点,需要LR
        leftRightRotation(tree);
      }

    }
    else{
      tree->right = insert(tree->right, key);
      if(key > tree->right->key){
        // 比右节点大,成为右节点的右节点
        rightRightRotation(tree);
      }else{
        // 比右节点小,成为右节点的左节点,需要RL
        rightLeftRotation(tree);
      }
    }
  }

删除的实现

删除节点在叶子节点

删除只有一个左节点或右节点

删除有左右节点

  AVLTreeNode<T>* remove(AVLTreeNode<T>* &tree, AVLTreeNode<T> *z){
    if(tree == nullptr || z == nullptr){
      return nullptr;
    }
    if(z->key < tree->key){
      AVLTreeNode<T>* r = tree->right;
      tree->left = remove(tree->left, z);
      // 需要进行RL旋转
      if(r->left > r->right){
        tree = rightLeftRotation(tree);
      }else {
        tree = rightRightRotation(tree);
      }
    }
    else if(z->key > tree->key){
      AVLTreeNode<T>* l = tree->left;
      tree->right = remove(tree->right, z);
      // 需要进行RL旋转
      if(r->right > r->left){
        tree = keftRightRotation(tree);
      }else {
        tree = leftLeftRotation(tree);
      }
    }
    else{
      // 需要删除的节点
      if(tree->left !=null) && (tree->right != null){
        if(height(tree->left) > height(tree->right)){
          AVLTreeNode<T>* temp = maximum(tree->left);
          tree->key = temp->key;
          remove(tree->left, temp);
        }
        else{
          AVLTreeNode<T>* temp = minimum(tree->right);
          tree->key = temp->key;
          remove(tree->right, temp);
        }
      }
      else{
        AVLTreeNode<T>* temp = tree;
        tree = (tree->left !=null) ? tree->left:tree->right;
        delete temp;
      }
    }
    return tree;
  }

  template<class T>
  void AVLTree<T>::remove(T key)
  {
      AVLTreeNode<T> *z;
      if((z=search(root,key))!=NULL)
          root = remove(root,z);
  }

字典树

  • 根节点不包含字符,除根节点外每一个节点都只包含一个字符。
  • 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
  • 每个节点的所有子节点包含的字符都不相同。

针对单词为:b,abc,abd,bcd,abcd,efg,hii得到的字典树

字典树宏

const int Num = 26;

字典树节点定义

struct TrieNode{
  bool is_word;
  TrieNode* next[Num];
  TrieNode() : is_word(flase){
    memset(next, NULL, sizeof(next));
  }
};

字典树定义

class Trie{
public: 
  Trie(){root = new TrieNode();}
  void insert(string word);
  bool search(string word);
  void deleteTrie(TrieNode* root);

private:
  TrieNode* root;
}

字典树方法

字典树插入方法

void Trie::insert(string word){
  TrieNode* location = root;
  for(int i = 0; i <word.size(); i++){
    if(location->next[word[i]- 'a'] == nullptr){
      TrieNode* temp = new TrieNode();
      location->next[word[i]- 'a'] = temp;
    }
    location = location->next[word[i] - 'a'];
  }
  location->is_word = true;
}

字典树寻找方法

bool Trie::search(string word){
  TrieNode* location = root;
  for(int i = 0 ; i < word.size() && location; i++){
    location = location->next[word[i] - 'a'];
  }
  return (location!= NULL && location->is_word);
}

字典树删除方法

  void Trie::deleteTrie(TrieNode* root){
    for(int i = 0 ; i < Num; i++){
      if(root->next[i] != NULL){
        deleteTrie(root->next);
      }
    }
    delete root;
  }

234树

红黑树

红黑树宏

enum Colour{
  RED,
  BLACK
} Color;

节点定义

template<typename Type>
struct RBTNode{
  Color color;
  Type key;
  RBTNode* left;
  RBTNode* right;
  RBTNode* parent;
};

红黑树定义

template<typename Type>
class RBTree{

public:
  RBTree(){
    Nil = BuyNode();
    root = Nil;
    Nil->color = BLACK;
  }

  ~RBTree(){
    destroy(root);
    delete Nil;
    Nil = NULL;
  }
  void InOrder(){InOrder(root);}
  bool Insert(const Type& value);
  void Remove(Type key);
  void InOrderPrint(InOrderPrint(root);)

protected:
  RBTNode<Type>* BuyNode(const Type& x = Type());
  void InOrder(RBTNode<Type>* root);
  void LeftRotate(RBTNode<Type>* z);
  void RightRotate(RBTNode<Type>* z);
  void Insert_fixup(RBTNode<Type>* s);
  RBTNode<Type>* search(RBTNode<Type>* root, Type key) const;

private:
  RBTNode<Type>* root;
  RBTNode<Type>* Nil;
}

红黑树实现

红黑树插入



B-Tree

特点

  • 所有的叶子都在同一层
  • B树由一个最小度t定义,t的值依赖于磁盘块的大小
  • 所有的树节点除了根节点最少需要有t-1个关键字,根节点至少有一个关键字
  • 所有的节点包括根节点都至多包含2t-1个关键字
  • 节点的孩子数等于其关键字数+1
  • 所有节点内的数字增序排列。在关键字K1和K2之间的所有子树上的节点关键字值都在K1和K2之间
  • B树的生长和收缩都是从根开始的,这点不同于其他的搜索树,其他的搜素树都是从底部开始生长和收缩的
  • 像其他平衡的二叉搜索树一样,搜索插入和删除的时间复杂度是O(logn)

结点定义

class BTreeNode{
  int* keys;      // 关键字数组
  int t;          // 最小度
  BTreeNode** C;  // 对应孩子节点的数组指针
  int n;          // 节点当前关键字数量
  bool leaf;      // 是否是叶子节点

public:
  BTreeNode(int _t, bool _leaf);  // 构造函数
  void insertNonFull(int k);
  void traverse();  //遍历所有以该节点为根的子树的关键字
  void splitChild(int i, BTreeNode* y);
  BTreeNode* search(int k); //查询一个关键词在以该节点为根的子树

friend class BTree; //使其可以访问私有成员
};

BTree定义

class BTree{
  BTreeNode* root;
  int t;

public:
  BTree(int _t){
    root = NULL; t = _t;
  }
  void traverse(){
    if(root != NULL) root->traverse();
  }
  BTreeNode* search(int k)
    {  return (root == NULL)? NULL : root->search(k); }

  void insert(int k);
};

BTree方法

构造方法

void BTreeNode::BTreeNode(int _t, bool _leaf){
  t = _t;
  leaf = _leaf;
  
  keys = new int [2*t -1];
  C = new BTreeNode[2*t];

  n = 0;
}

遍历与查找方法

void BTreeNode::traverse(){
  int i;
  for(i = 0; i < n; i++){
    if(leaf == false)
      C[i] = ->traverse();
    cout << " " << keys[i];
  }
  if(leaf == false)
    C[i]->traverse();
}

BTreeNode* BTreeNode::search(int k){
  int i = 0;
  while(i < n && k >keys[i]){
    i++;
  }
  if(key[i] == k){
    return this;
  }
  if(leaf == true){
    return NULL;
  }
  return C[i]->search(k);
}

插入

void BTree::insert(int k){
  if(root == NULL){
    root = new BTreeNode(t, true);
    root->keys[0] = k;
    root->n = 1;
  }
  else {
    if(root->n == 2*t -1){

    }
    else
    root->insertNonFull(k);
  }
}

void BTreeNode::insertNonFull(int k){
  int i = n-1;
  if(leaf == true){

  }
}

B+Tree

LRU

#