Chinaunix首页 | 论坛 | 博客
  • 博客访问: 97539
  • 博文数量: 21
  • 博客积分: 145
  • 博客等级: 入伍新兵
  • 技术积分: 250
  • 用 户 组: 普通用户
  • 注册时间: 2012-12-22 17:37
文章分类

全部博文(21)

文章存档

2013年(16)

2012年(5)

我的朋友

分类: C/C++

2012-12-31 13:57:56

chapter8:二叉查找树
chapter9:AVL树

这两个就一起看了。因为AVL树是二叉查找树的一个升级版本,所以我就选择直接实现AVL树的基本功能,主要是find、erase、insert。

树节点:

点击(此处)折叠或打开

  1. struct Node {
  2. T item;
  3. int height;
  4. Node *parent;
  5. Node *left;
  6. Node *right;
  7. Node(): height(0), parent(NULL), left(NULL), right(NULL) {}
  8. Node(const T& x):
  9. item(x), height(0),parent(NULL), left(NULL), right(NULL) {}
  10. };

AVL树除了要满足二叉查找树的要求外,还要求树上的任意节点N:
|height(N->left) - height(N->right)| <= 1,
即两个子树的高度差不能超过1,其中height(NULL) == -1。

基本思路:
1)find和二叉查找树一样,没有什么好说的。
2)insert
感觉书上讲得有点乱,没仔细看,找了《数据结构》(C语言版)和《数据结构和算法分析》C++来看了一下,
真是相当清楚,四种情况,一目了然,证明也是犀利。
LL: 在左子树的左子树插入并引起不平衡
LR:在左子树的右子树插入。。。
RL:在右子树的左子树插入。。。
RR:在右子树的右子树插入。。。
平衡失衡可以通过左右旋转搞定,并且神奇的是只要搞定插入路径上高度最低的不平衡点,其它个点
不会有影响。(具体大家看书去吧,我只是瞎扯扯)
为了偷懒,我实现的是递归版本,并且树节点中有一个高度字段,其实没有必要递归。

点击(此处)折叠或打开

  1. template <class T, class Compare>
  2. void AVLTree<T, Compare>::insertNode(Node *parent, Node * &tree, const T& item) {
  3.     if (tree == NULL) {
  4.         tree = new Node(item);
  5.         tree->parent = parent;
  6.         adjustMinMaxInsert(tree);
  7.         nodeCount++;
  8.         return;
  9.     }
  10.     if (compare(item, tree->item) < 0) {
  11.         insertNode(tree, tree->left, item);
  12.         if (getHeight(tree->left) - getHeight(tree->right) == 2) {
  13.             Node *child = tree->left;
  14.             if (getHeight(child->left) > getHeight(child->right))
  15.                 leftRotation(tree); // LL
  16.             else
  17.                 rlRotation(tree); // LR
  18.         }
  19.     } else if (compare(item, tree->item) > 0) {
  20.         insertNode(tree, tree->right, item);
  21.         if (getHeight(tree->left) - getHeight(tree->right) == -2) {
  22.             Node *child = tree->right;
  23.             if (getHeight(child->left) < getHeight(child->right))
  24.                 rightRotation(tree); // RR
  25.             else
  26.                 lrRotation(tree); // RL
  27.         }
  28.     } else
  29.         std::cout << "Item: " << item << " exists!" << std::endl;
  30.     tree->height = maxHeight(tree->left, tree->right) + 1; // important
  31. }
这里用指针引用Node * &tree,是个小技巧,不然在连接树的新节点时候要多写些代码,呵呵。

3)erase
基本书上没有给出解答,差不多都留作课后习题了。
我的思路和二叉查找树的erase类似,假设要删除的节点是N,
1. N至多只有一棵子树,删除N,从N的父亲节点开始平衡可能被破坏。
2. N有两棵子树,那么找N的后记节点(必定存在的,因为右子树不为空啊),将后继节点内容copy到当前节点,下面的任务改为删除后继节点。
从删除节点的父亲开始,不断查看是否需要左右旋转来调整平衡,直到根节点,(出现上面四种情况之一,就要需要旋转,这一点插入和删除是一致的)。
当然,要记得查看root指向的节点是否更换,父亲和儿子节点是否相互连接,不然会出奇怪的错误的。

点击(此处)折叠或打开

  1. template <class T, class Compare>
  2. bool AVLTree<T, Compare>::erase(const T& item) {
  3.     Iterator itr = find(item);
  4.     if (!(itr != end()))
  5.         return false; // Can't find such item.
  6.     Node *tree = itr.position;
  7.     // If both subtree is not empty, then find the successor.
  8.     while (tree->left != NULL && tree->right != NULL) {
  9.         Node *succ = successor(tree);
  10.         tree->item = succ->item;
  11.         tree = succ;
  12.     }
  13.     Node *parent = tree->parent;
  14.     Node *child = tree->left ? tree->left : tree->right;
  15.     adjustMinMaxErase(tree);

  16.     if (child != NULL)
  17.         child->parent = parent;
  18.     if (parent != header) {
  19.         if (parent->left == tree)
  20.             parent->left = child;
  21.         else
  22.             parent->right = child;
  23.         parent->height = maxHeight(parent->left, parent->right) + 1;
  24.         adjustBalance(parent);
  25.     } else
  26.         root = child; // adjust root
  27.     delete tree;
  28.     nodeCount--;
  29.     return true;
  30. }
调整平衡。

点击(此处)折叠或打开

  1. template <class T, class Compare>
  2. void AVLTree<T, Compare>::adjustBalance(Node * tree) {
  3.     while (tree != NULL && tree != header) {
  4.         tree->height = maxHeight(tree->left, tree->right) + 1;
  5.         char flag = 'M';
  6.         if (tree->parent != header)
  7.             flag = tree->parent->left == tree ? 'L' : 'R';

  8.         if (getHeight(tree->left) - getHeight(tree->right) == 2) {
  9.             Node *child = tree->left;
  10.             if (getHeight(child->left) >= getHeight(child->right))
  11.                 leftRotation(tree); // LL
  12.             else
  13.                 rlRotation(tree); // LR

  14.         } else if (getHeight(tree->left) - getHeight(tree->right) == -2) {
  15.             Node *child = tree->right;
  16.             if (getHeight(child->left) <= getHeight(child->right))
  17.                 rightRotation(tree); // RR
  18.             else
  19.                 lrRotation(tree); // RR
  20.         }
  21.         
  22.         if (flag == 'L') // Concatenate parent and child.
  23.             tree->parent->left = tree;
  24.         else if (flag == 'R')
  25.             tree->parent->right = tree;
  26.         else {
  27.             if (getHeight(root) < getHeight(tree))
  28.                 root = tree; // adjust root
  29.         }
  30.         tree = tree->parent;
  31.     }
  32. }
4)Iterator
迭代器功能,我又偷懒了,只实现了++itr, *itr, itr1 != itr2
在AVLTree里面加了个header字段,header->left指向第一个节点,header->right指向最后一个节点(其实这个没有必要,因为我没有实现--itr),header->parent = NULL。根节点root->parent = header,这都是为了方便,不然++itr就找不到header了,因为header是作为最后一个节点之后的节点的,即end()的返回值。

遇到的问题:
1)按书上的做法,我也用了function object,其实这就是标准的策略模式。
一开始,两个地方的模板声明都用了,结果出现shadows template parm ‘class T’的错误。
这个必须把其中一个T换成别的名字。
2)犯了一些傻错误
AVLTree>avlTree;  //error: >>不能相连,相连就是个运算符
friend class AVLTree; // class 不能落下
void AVLTree:: ... // 不能忘记写

附上源码: avlTree.zip   

完整的类定义:

点击(此处)折叠或打开

  1. template <class T, class Compare>
  2. class AVLTree {
  3. private:
  4.     struct Node {
  5.         T item;
  6.         int height;
  7.         Node *parent;
  8.         Node *left;
  9.         Node *right;
  10.         
  11.         Node(): height(0), parent(NULL), left(NULL), right(NULL) {}
  12.         Node(const T& x):
  13.             item(x), height(0),parent(NULL), left(NULL), right(NULL) {}
  14.     };

  15.     /* header: point to the node following the last one;
  16.      * header->left: point to the fisrt node (which has
  17.      *    the smallest item);
  18.      * header->right: point to the last node (which has
  19.      *    the largest item);
  20.      */
  21.     Node *header, *root;
  22.     size_t nodeCount;
  23.     Compare compare; // object function

  24.     inline int getHeight(const Node *tree) const;

  25.     /* maxHeight:
  26.      * Return the larger height between the left and right
  27.      * subtree.
  28.      */
  29.     inline int maxHeight(const Node *left, const Node *right) const;

  30.     /* Four different kinds of tree rotations, in order
  31.      * to restore balance.
  32.      */
  33.     void leftRotation(Node * &tree);
  34.     void rightRotation(Node * &tree);
  35.     void lrRotation(Node * &tree);
  36.     void rlRotation(Node * &tree);

  37.     /* Get the successor(predecessor) of *ptr, following
  38.      * the predefined order, s.t. compare.
  39.      */
  40.     Node* successor(Node *ptr) const;
  41.     Node* predecessor(Node *ptr) const;

  42.     /* Adjust header->left and header->right after inserting
  43.      * or erasing nodes.
  44.      */
  45.     void adjustMinMaxInsert(Node *ptr);
  46.     void adjustMinMaxErase(Node *ptr);

  47.     /* Adjust tree balance after erasing nodes.*/
  48.     void adjustBalance(Node * tree);

  49.     /* An auxiliary function of insert with recursive manner.*/
  50.     void insertNode(Node *parent, Node * &tree, const T& item);
  51.     
  52. public:
  53.     class Iterator {
  54.     private:
  55.         friend class AVLTree;
  56.         Node *position;

  57.         Iterator(Node *pos): position(pos) {}
  58.     public:
  59.         Iterator() {};
  60.         Iterator& operator++();
  61.         inline T& operator*() const;
  62.         inline bool operator!=(const Iterator& another) const;
  63.     };

  64.     AVLTree();
  65.     ~AVLTree();

  66.     /* For convenient check, print out the whole tree in
  67.      * layer order.
  68.      */
  69.     void printTree() const;

  70.     /* If insert new node successfully, return the iterator
  71.      * pointing to the new node, otherwise return end().
  72.      */
  73.     Iterator insert(const T& item);

  74.     /* Erasing nodes successfull, return true, otherwise
  75.      * return false.
  76.      */
  77.     bool erase(const T& item);

  78.     /* Return the iterator if find the corresponding item,
  79.      * otherwise return end().
  80.      */
  81.     Iterator find(const T& item) const;

  82.     inline Iterator begin() const;
  83.     inline Iterator end() const;
  84.     inline int treeHeight() { return getHeight(root); }
  85. };

阅读(539) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~