AVL树的创建与旋转

AVL树写的不耐烦了,索性一次性代码贴上。。。

/**
   2  * AVL树(C语言): C语言实现的AVL树。
   3  *
   4  * @author skywang
   5  * @date 2013/11/07
  6  */

 #include <stdio.h>
 #include <stdlib.h>

#define HEIGHT(p)    ( (p==NULL) ? -1 : (((Node *)(p))->height) )
 #define MAX(a, b)    ( (a) > (b) ? (a) : (b) )
typedef int Type;

typedef struct AVLTreeNode{
    Type key;                    // 关键字(键值)
    int height;
    struct AVLTreeNode *left;    // 左孩子
    struct AVLTreeNode *right;    // 右孩子
}Node, *AVLTree;
 /*
   16  * 获取AVL树的高度
   17  */
 int avltree_height(AVLTree tree)
 {
        return HEIGHT(tree);
    }

/*
   24  * 前序遍历"AVL树"
   25  */
 void preorder_avltree(AVLTree tree)
 {
        if(tree != NULL)
   {
           printf("%d ", tree->key);
           preorder_avltree(tree->left);
           preorder_avltree(tree->right);
       }
    }

/*
   38  * 中序遍历"AVL树"
   39  */
 void inorder_avltree(AVLTree tree)
 {
        if(tree != NULL)
        {
                inorder_avltree(tree->left);
                printf("%d ", tree->key);
                inorder_avltree(tree->right);
            }
    }

 /*
   51  * 后序遍历"AVL树"
   52  */
 void postorder_avltree(AVLTree tree)
 {
      if(tree != NULL)
          {
                 postorder_avltree(tree->left);
                 postorder_avltree(tree->right);
                 printf("%d ", tree->key);
             }
    }

/*
   64  * (递归实现)查找"AVL树x"中键值为key的节点
   65  */
Node* avltree_search(AVLTree x, Type key)
{
      if (x==NULL || x->key==key)
          return x;

      if (key < x->key)
            return avltree_search(x->left, key);
        else
                return avltree_search(x->right, key);
        }

 /*
     * (非递归实现)查找"AVL树x"中键值为key的节点
     */
 Node* iterative_avltree_search(AVLTree x, Type key)
{
   while ((x!=NULL) && (x->key!=key))
        {
           if (key < x->key)
                   x = x->left;
               else
                       x = x->right;
               }

       return x;
   }

 /*
    * 查找最小结点:返回tree为根结点的AVL树的最小结点。
    */
 Node* avltree_minimum(AVLTree tree)
 {
     if (tree == NULL)
           return NULL;

      while(tree->left != NULL)
          tree = tree->left;
      return tree;
  }

 /*
   * 查找最大结点:返回tree为根结点的AVL树的最大结点。
   */
 Node* avltree_maximum(AVLTree tree)
 {
    if (tree == NULL)
            return NULL;

    while(tree->right != NULL)
            tree = tree->right;
        return tree;
   }

 /*
     * LL:左左对应的情况(左单旋转)。
     *
     * 返回值:旋转后的根节点
     */
 static Node* left_left_rotation(AVLTree k2)
 {
       AVLTree 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), k2->height) + 1;

       return k1;
   }

 /*
     * RR:右右对应的情况(右单旋转)。
     *
     * 返回值:旋转后的根节点
     */
 static Node* right_right_rotation(AVLTree k1)
 {
    AVLTree 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->right), k1->height) + 1;

      return k2;
  }

 /*
      * LR:左右对应的情况(左双旋转)。
      *
      * 返回值:旋转后的根节点
      */
 static Node* left_right_rotation(AVLTree k3)
 {
       k3->left = right_right_rotation(k3->left);

       return left_left_rotation(k3);
   }

 /*
    170  * RL:右左对应的情况(右双旋转)。
    171  *
    172  * 返回值:旋转后的根节点
    173  */
 static Node* right_left_rotation(AVLTree k1)
 {
       k1->right = left_left_rotation(k1->right);

       return right_right_rotation(k1);
   }

/*
     * 创建AVL树结点。
     *
     * 参数说明:
     *     key 是键值。
     *     left 是左孩子。
     *     right 是右孩子。
     */
static Node* avltree_create_node(Type key, Node *left, Node* right)
 {
        Node* p;

   if ((p = (Node *)malloc(sizeof(Node))) == NULL)
          return NULL;
   p->key = key;
   p->height = 0;
   p->left = left;
   p->right = right;

     return p;
 }

 /*
    * 将结点插入到AVL树中,并返回根节点
    *
    * 参数说明:
    *     tree AVL树的根结点
    *     key 插入的结点的键值
    * 返回值:
    *     根节点
    */
 Node* avltree_insert(AVLTree tree, Type key)
 {
    if (tree == NULL)
        {
         // 新建节点
         tree = avltree_create_node(key, NULL, NULL);
         if (tree==NULL)
             {
                     printf("ERROR: create avltree node failed!\n");
                     return NULL;
                 }
               }
     else if (key < tree->key) // 应该将key插入到"tree的左子树"的情况
         {
               tree->left = avltree_insert(tree->left, key);
               // 插入节点后,若AVL树失去平衡,则进行相应的调节。
               if (HEIGHT(tree->left) - HEIGHT(tree->right) == 2)
                   {
                    if (key < tree->left->key)
                            tree = left_left_rotation(tree);
                        else
                                tree = left_right_rotation(tree);
                        }
                }
        else if (key > tree->key) // 应该将key插入到"tree的右子树"的情况
           {
               tree->right = avltree_insert(tree->right, key);
               // 插入节点后,若AVL树失去平衡,则进行相应的调节。
               if (HEIGHT(tree->right) - HEIGHT(tree->left) == 2)
                   {
                      if (key > tree->right->key)
                              tree = right_right_rotation(tree);
                          else
                                  tree = right_left_rotation(tree);
                          }
                }
         else //key == tree->key)
        {
                 printf("添加失败:不允许添加相同的节点!\n");
            }

      tree->height = MAX( HEIGHT(tree->left), HEIGHT(tree->right)) + 1;

      return tree;
  }

 /*
      * 删除结点(z),返回根节点
      *
      * 参数说明:
      *     ptree AVL树的根结点
      *     z 待删除的结点
      * 返回值:
      *     根节点
      */
 static Node* delete_node(AVLTree tree, Node *z)
 {
    // 根为空 或者 没有要删除的节点,直接返回NULL。
    if (tree==NULL || z==NULL)
           return NULL;

    if (z->key < tree->key)        // 待删除的节点在"tree的左子树"中
       {
              tree->left = delete_node(tree->left, z);
              // 删除节点后,若AVL树失去平衡,则进行相应的调节。
              if (HEIGHT(tree->right) - HEIGHT(tree->left) == 2)
                  {
           Node *r =  tree->right;
                     if (HEIGHT(r->left) > HEIGHT(r->right))
                             tree = right_left_rotation(tree);
                         else
                                 tree = right_right_rotation(tree);
                         }
                }
     else if (z->key > tree->key)// 待删除的节点在"tree的右子树"中
         {
               tree->right = delete_node(tree->right, z);
               // 删除节点后,若AVL树失去平衡,则进行相应的调节。
               if (HEIGHT(tree->left) - HEIGHT(tree->right) == 2)
                   {
                        Node *l =  tree->left;
                        if (HEIGHT(l->right) > HEIGHT(l->left))
                                tree = left_right_rotation(tree);
                            else
                                   tree = left_left_rotation(tree);
                      }
                }
   else    // tree是对应要删除的节点。
       {
                // tree的左右孩子都非空
                if ((tree->left) && (tree->right))
                    {
          if (HEIGHT(tree->left) > HEIGHT(tree->right))
              {
                      // 如果tree的左子树比右子树高;
                      // 则(01)找出tree的左子树中的最大节点
                      //   (02)将该最大节点的值赋值给tree。
                      //   (03)删除该最大节点。
                      // 这类似于用"tree的左子树中最大节点"做"tree"的替身;
                      // 采用这种方式的好处是:删除"tree的左子树中最大节点"之后,AVL树仍然是平衡的。
                      Node *max = avltree_maximum(tree->left);
                      tree->key = max->key;
                      tree->left = delete_node(tree->left, max);
                  }
          else
              {
                      // 如果tree的左子树不比右子树高(即它们相等,或右子树比左子树高1)
                      // 则(01)找出tree的右子树中的最小节点
                      //   (02)将该最小节点的值赋值给tree。
                      //   (03)删除该最小节点。
                      // 这类似于用"tree的右子树中最小节点"做"tree"的替身;
                      // 采用这种方式的好处是:删除"tree的右子树中最小节点"之后,AVL树仍然是平衡的。
                      Node *min = avltree_maximum(tree->right);
                      tree->key = min->key;
                      tree->right = delete_node(tree->right, min);
                  }
                      }
             else
                  {
                          Node *tmp = tree;
                          tree = tree->left ? tree->left : tree->right;
                          free(tmp);
                    }
                 }

         return tree;
     }

 /*
    * 删除结点(key是节点值),返回根节点
    *
    * 参数说明:
    *     tree AVL树的根结点
    *     key 待删除的结点的键值
    * 返回值:
    *     根节点
    */
 Node* avltree_delete(AVLTree tree, Type key)
{
 Node *z; 

 if ((z = avltree_search(tree, key)) != NULL)
         tree = delete_node(tree, z);
     return tree;
   }

 /*
  359  * 销毁AVL树
  360  */
 void destroy_avltree(AVLTree tree)
 {
         if (tree==NULL)
              return ;

         if (tree->left != NULL)
         destroy_avltree(tree->left);
     if (tree->right != NULL)
             destroy_avltree(tree->right);

         free(tree);
     }
 /*
  * 打印"AVL树"
  *
  * tree       -- AVL树的节点
  * key        -- 节点的键值
  * direction  --  0,表示该节点是根节点;
  *               -1,表示该节点是它的父结点的左孩子;
  *                1,表示该节点是它的父结点的右孩子。
  */
 void print_avltree(AVLTree tree, Type key, int direction)
 {
   if(tree != NULL)
       {
         if(direction==0)    // tree是根节点
                 printf("%2d is root\n", tree->key, key);
             else                // tree是分支节点
                     printf("%2d is %2d's %6s child\n", tree->key, key, direction==1?"right" : "left");

                 print_avltree(tree->left, tree->key, -1);
                 print_avltree(tree->right,tree->key,  1);
             }
     }

// static int arr[]= {3,2,1,4,5,6,7,16,15,14,13,12,11,10,8,9};
// #define TBL_SIZE(a) ( (sizeof(a)) / (sizeof(a[0])) )

 int main()
 {
      int i,ilen;
     int arr[100];
      AVLTree root=NULL;

     printf("输入插入的节点个数为");
     scanf("%d",&ilen);

      for(i=0; i<ilen; i++)
   {
           scanf("%d",&arr[i]);
           root = avltree_insert(root, arr[i]);
       }

      printf("\n== 前序遍历: ");
      preorder_avltree(root);

      printf("\n== 中序遍历: ");
      inorder_avltree(root);
      printf("\n== 后序遍历: ");
      postorder_avltree(root);
      printf("\n");
      printf("== 高度: %d\n", avltree_height(root));

      printf("== 树的详细信息: \n");
      print_avltree(root, root->key, 0);
      i = 8;
      printf("\n== 删除根节点: %d", i);
      root = avltree_delete(root, i);
      printf("\n== 高度: %d", avltree_height(root));
      printf("\n== 中序遍历: ");
      inorder_avltree(root);
      printf("\n== 树的详细信息: \n");
      print_avltree(root, root->key, 0);

      // 销毁二叉树
     destroy_avltree(root);
     return 0;
  }

好的博客

http://www.cnblogs.com/skywang12345/p/3576969.html

时间: 2024-10-10 23:03:48

AVL树的创建与旋转的相关文章

PTA Root of AVL Tree (AVL树模板+四种旋转+指针)

关于AVL树(平衡二叉搜索树,高度为lgn)的讲解,双手呈上某大佬博客:https://www.cnblogs.com/zhuwbox/p/3636783.html 我从这题get到一个新的结构体写法(姿势): typedef struct treeNode { int val; treeNode *left; treeNode *right; int height; }node, *tree;//node 是treeNode结构体,*tree是结构体指针 我对AVL树的理解: 按照插入节点时旋

数据结构--Avl树的创建,插入的递归版本和非递归版本,删除等操作

AVL树本质上还是一棵二叉搜索树,它的特点是: 1.本身首先是一棵二叉搜索树. 2.带有平衡条件:每个结点的左右子树的高度之差的绝对值最多为1(空树的高度为-1). 也就是说,AVL树,本质上是带了平衡功能的二叉查找树(二叉排序树,二叉搜索树). 对Avl树进行相关的操作最重要的是要保持Avl树的平衡条件.即对Avl树进行相关的操作后,要进行相应的旋转操作来恢复Avl树的平衡条件. 对Avl树的插入和删除都可以用递归实现,文中也给出了插入的非递归版本,关键在于要用到栈. 代码如下: #inclu

从AVL树的定义出发,一步步推导出旋转的方案。

本文从AVL树的定义出发,一步步地推导出AVL树旋转的方案,这个推导是在已经清楚地知道AVL树的定义这个前提下进行的.文章注重思考的过程,并不会直接给出AVL树是怎样旋转的,用来提醒自己以后在学习的时候要注重推导的过程.在此,我要特别感谢下我的数据结构老师,是他让我意识到思考的重要性. 一.从AVL树的定义开始 1. 二叉查找树的问题 二叉查找树的出现,虽然使查找的平均时间降到了logN,但是,在多次删除或者插入操作后,可能会出现根节点的左子树比右子树高很多,或者右子树比左子树高很多的情况.如图

[转载]AVL树(一)之 图文解析 和 C语言的实现

概要 本章介绍AVL树.和前面介绍"二叉查找树"的流程一样,本章先对AVL树的理论知识进行简单介绍,然后给出C语言的实现.本篇实现的二叉查找树是C语言版的,后面章节再分别给出C++和Java版本的实现. 建议:若您对"二叉查找树"不熟悉,建议先学完"二叉查找树"再来学习AVL树. 目录 1. AVL树的介绍 2. AVL树的C实现3. AVL树的C实现(完整源码) 4. AVL树的C测试程序 转载请注明出处:http://www.cnblogs.

浅谈AVL树,红黑树,B树,B+树原理及应用

背景:这几天在看<高性能Mysql>,在看到创建高性能的索引,书上说mysql的存储引擎InnoDB采用的索引类型是B+Tree,那么,大家有没有产生这样一个疑问,对于数据索引,为什么要使用B+Tree这种数据结构,和其它树相比,它能体现的优点在哪里? 看完这篇文章你就会了解到这些数据结构的原理以及它们各自的应用场景. 二叉查找树 简介 二叉查找树也称为有序二叉查找树,满足二叉查找树的一般性质,是指一棵空树具有如下性质: 任意节点左子树不为空,则左子树的值均小于根节点的值. 任意节点右子树不为

深度解析(七)AVL树

AVL树(一)之 图文解析 和 C语言的实现 概要 本章介绍AVL树.和前面介绍"二叉查找树"的流程一样,本章先对AVL树的理论知识进行简单介绍,然后给出C语言的实现.本篇实现的二叉查找树是C语言版的,后面章节再分别给出C++和Java版本的实现.建议:若您对"二叉查找树"不熟悉,建议先学完"二叉查找树"再来学习AVL树. 目录 1. AVL树的介绍2. AVL树的C实现3. AVL树的C实现(完整源码)4. AVL树的C测试程序 转载请注明出处

平衡二叉搜索树(AVL树)的原理及实现源代码(有图文详解和C++、Java实现代码)

一.AVL树(平衡二叉搜索树)是什么? AVL树是根据它的发明者G.M. Adelson-Velsky和E.M. Landis命名的.AVL树本质上还是一棵二叉搜索树,它的特点是: 1.本身首先是一棵二叉搜索树. 2.带有平衡条件:每个非叶子结点的左右子树的高度之差的绝对值(平衡因子)最多为1. 例如: 5             5 / \            /  \ 2   6         2   6 / \    \         / \ 1  4   7       1  4

AVL树、红黑树以及B树介绍

简介 首先,说一下在数据结构中为什么要引入树这种结构,在我们上篇文章中介绍的数组与链表中,可以发现,数组适合查询这种静态操作(O(1)),不合适删除与插入这种动态操作(O(n)),而链表则是适合删除与插入,而查询效率则就比较慢了,本文要分享学习的树就是为了平衡这种静态操作与动态操作的差距. 一.二叉查找树 简介 满足下面条件就是二叉查找树 任意节点左子树不为空,则左子树的值均小于根节点的值. 任意节点右子树不为空,则右子树的值均大于于根节点的值. 任意节点的左右子树也分别是二叉查找树. 没有键值

AVL树平衡旋转详解

AVL树平衡旋转详解 概述 AVL树又叫做平衡二叉树.前言部分我也有说到,AVL树的前提是二叉排序树(BST或叫做二叉查找树).由于在生成BST树的过程中可能会出现线型树结构,比如插入的顺序是:1, 2, 3, 4, 5, 6, 7..., n.在BST树中,比较理想的状况是每个子树的左子树和右子树的高度相等,此时搜索的时间复杂度是log(N).可是,一旦这棵树演化成了线型树的时候,这个理想的情况就不存在了,此时搜索的时间复杂度是O(N),在数据量很大的情况下,我们并不愿意看到这样的结果. 现在