使用C++实现一个AVL树(泛型AVL类)

实现AVL树的构建、插入结点、删除结点、AVL树的销毁等操作,已通过100条样例测试。

代码如下:

#include <algorithm>
#include <cstdio>
#include <iostream>
#include <string>

template <typename T>
struct AVLTreeNode {
  AVLTreeNode(T value, AVLTreeNode<T>* l = nullptr, AVLTreeNode<T>* r = nullptr)
      : key(value), lchild(l), rchild(r) {}

  T key;
  int height;
  AVLTreeNode<T>* lchild;
  AVLTreeNode<T>* rchild;
};

template <typename T>
class AVLTree {
 public:
  AVLTree() = default;
  ~AVLTree() { destory(root); }

  void print(const std::string& op) {
    if (!root) {
      std::cout << "EMPTY" << std::endl;
      return;
    }
    if (op == "PRE") {
      preOrder(root);
    } else if (op == "IN") {
      InOrder(root);
    } else if (op == "POST") {
      postOrder(root);
    }
    std::cout << std::endl;
  }

  void insert(T key) { root = insert(root, key); }
  void remove(T key) { root = remove(root, key); }

 private:
  AVLTreeNode<T>* insert(AVLTreeNode<T>* subRoot, T k) {
    if (subRoot == nullptr) {
      return new AVLTreeNode<T>(k);
    }

    if (subRoot->key == k) {
      return subRoot;
    }

    if (k >= subRoot->key) {
      subRoot->rchild = insert(subRoot->rchild, k);
    } else {
      subRoot->lchild = insert(subRoot->lchild, k);
    }

    subRoot = balance(subRoot);
    return subRoot;
  }

  AVLTreeNode<T>* remove(AVLTreeNode<T>* subRoot, T k) {
    if (subRoot == nullptr) {
      return nullptr;
    }
    if (subRoot->key == k) {
      if (subRoot->lchild == nullptr && subRoot->rchild == nullptr) {
        delete subRoot;
        return nullptr;
      } else if (subRoot->lchild == nullptr) {
        AVLTreeNode<T>* temp = subRoot->rchild;
        delete subRoot;
        return temp;
      } else if (subRoot->rchild == nullptr) {
        AVLTreeNode<T>* temp = subRoot->lchild;
        delete subRoot;
        return temp;
      } else {
        AVLTreeNode<T>* maxNode = treeMax(subRoot->lchild);
        T temp = subRoot->key;
        subRoot->key = maxNode->key;
        maxNode->key = temp;
        subRoot->lchild = remove(subRoot->lchild, k);
      }
    } else if (subRoot->key < k) {
      subRoot->rchild = remove(subRoot->rchild, k);
    } else {
      subRoot->lchild = remove(subRoot->lchild, k);
    }
    subRoot = balance(subRoot);
    return subRoot;
  }

  AVLTreeNode<T>* search(T k) {
    AVLTreeNode<T>* p = root;
    while (p) {
      if (p->key == k) {
        break;
      } else if (p->key < k) {
        p = p->lchild;
      } else {
        p = p->rchild;
      }
    }
    return p;
  }

  AVLTreeNode<T>* treeMax(AVLTreeNode<T>* subTree) {
    if (subTree == nullptr) {
      return nullptr;
    }
    while (subTree->rchild) {
      subTree = subTree->rchild;
    }
    return subTree;
  }
  AVLTreeNode<T>* treeMin(AVLTreeNode<T>* subTree) {
    if (subTree == nullptr) {
      return nullptr;
    }
    while (subTree->lchild) {
      subTree = subTree->lchild;
    }
    return subTree;
  }

  AVLTreeNode<T>* llRotation(AVLTreeNode<T>* subRoot) {
    AVLTreeNode<T>* temp = subRoot->lchild;
    subRoot->lchild = temp->rchild;
    temp->rchild = subRoot;
    return temp;
  }

  AVLTreeNode<T>* rrRotation(AVLTreeNode<T>* subRoot) {
    AVLTreeNode<T>* temp = subRoot->rchild;
    subRoot->rchild = temp->lchild;
    temp->lchild = subRoot;
    return temp;
  }

  AVLTreeNode<T>* rlRotation(AVLTreeNode<T>* subRoot) {
    subRoot->rchild = llRotation(subRoot->rchild);
    return rrRotation(subRoot);
  }

  AVLTreeNode<T>* lrRotation(AVLTreeNode<T>* subRoot) {
    subRoot->lchild = rrRotation(subRoot->lchild);
    return llRotation(subRoot);
  }

  int height(AVLTreeNode<T>* pnode) {
    if (pnode == nullptr) {
      return 0;
    }
    int l = height(pnode->lchild);
    int r = height(pnode->rchild);
    return std::max(l, r) + 1;
  }

  int balanceFactor(AVLTreeNode<T>* p) {
    return height(p->lchild) - height(p->rchild);
  }

  AVLTreeNode<T>* balance(AVLTreeNode<T>* subRoot) {
    int bf = balanceFactor(subRoot);

    if (bf > 1) {
      if (balanceFactor(subRoot->lchild) == 0) {
        subRoot = llRotation(subRoot);
      } else if (balanceFactor(subRoot->lchild) > 0) {
        subRoot = llRotation(subRoot);
      } else {
        subRoot = lrRotation(subRoot);
      }
    } else if (bf < -1) {
      if (balanceFactor(subRoot->rchild) == 0) {
        subRoot = rrRotation(subRoot);
      } else if (balanceFactor(subRoot->rchild) > 0) {
        subRoot = rlRotation(subRoot);
      } else {
        subRoot = rrRotation(subRoot);
      }
    }
    return subRoot;
  }

  void preOrder(AVLTreeNode<T>* p) {
    if (p == nullptr) {
      return;
    }
    std::cout << p->key << " ";
    preOrder(p->lchild);
    preOrder(p->rchild);
  }
  void InOrder(AVLTreeNode<T>* p) {
    if (p == nullptr) {
      return;
    }
    InOrder(p->lchild);
    std::cout << p->key << " ";
    InOrder(p->rchild);
  }
  void postOrder(AVLTreeNode<T>* p) {
    if (p == nullptr) {
      return;
    }
    postOrder(p->lchild);
    postOrder(p->rchild);
    std::cout << p->key << " ";
  }

  void destory(AVLTreeNode<T>* p) {
    if (p == nullptr) {
      return;
    }
    destory(p->lchild);
    destory(p->rchild);
    delete p;
  }

  AVLTreeNode<T>* root{nullptr};
};

上面是实现的AVL类,下面可以对其进行测试,输入输出格式描述如下:

1. 输入格式:

输入是n个用空格分隔的字符串,前n-1个字符串的格式描述如下:

  • Aint(字符A后面跟一个int类型的数字,例如A3)表示将int类型的数插入到AVL树中,A3表示将3插入到AVL树中,如果3已经在树中,则直接返回,不会插入一个相同的数字。
  • Dint(字符D后面跟一个int类型的数字,例如D3)表示将int类型的数从AVL树中删除,D3表示从AVL树中删除,如果3不在AVL树中,则直接返回。

第n个字符串有三种类型:PRE、IN、POST,分别代表最后AVL树以什么顺序输出。

2. 输出格式

输出按照输入说明的输出格式打印AVL树,如果AVL树是空,打印EMPTY。

例如:

# 对于输入:
A1 A2 A3 IN
# 输出:
1 2 3

# 对于输入:
A1 A2 A3 PRE
# 输出
2 1 3

# 对于输入
A1 D1 POST
# 输出
EMPTY

下面是测试代码:

int main() {

  std::string op;
  AVLTree<int> tree;
  while (std::cin >> op) {
    if (op == "IN" || op == "PRE" || op == "POST") {
      tree.print(op);
      break;
    }

    if (op[0] == 'A') {
      tree.insert(std::stoi(op.substr(1)));
    } else if (op[0] == 'D') {
      tree.remove(std::stoi(op.substr(1)));
    }
  }

  return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值