浅谈基础算法之AVL tree和splay tree(三)

开发 架构 算法
平衡二叉树:上文我们只实现了单旋,但是实际中为了达到平衡很多是要做双旋操作的。先来看一张双旋后的一张图,明显右边的图查询的时候会更便捷。

承接上文,我们继续聊这个话题。

平衡二叉树:AVL Tree(1962)

上文我们只实现了单旋,但是实际中为了达到平衡很多是要做双旋操作的。

先来看一张双旋后的一张图,明显右边的图查询的时候会更便捷。

  整个过程

  下面我们就进行代码实践。

#include <stdio.h> 
#include <stdlib.h> 
 
#define max(a,b)    (((a) > (b)) ? (a) : (b))  
 
typedef struct AvlNode{ 
    int data; 
    struct AvlNode *left_child, *right_child; 
} AvlNode; 
 
AvlNode *root; 
 
/*    旋转动作开始        */ 
AvlNode *rotate_LL(AvlNode *parent){ 
    AvlNode *child = parent->left_child; 
    parent->left_child = child->right_child; 
    child->right_child = parent; 
    return child; 

 
AvlNode *rotate_RR(AvlNode *parent){ 
    AvlNode *child = parent->right_child; 
    parent->right_child = child->left_child; 
    child->left_child = parent; 
    return child; 

 
AvlNode *rotate_RL(AvlNode *parent){ 
    AvlNode *child = parent->right_child; 
    parent->right_child = rotate_LL(child); 
    return rotate_RR(parent); 

 
AvlNode *rotate_LR(AvlNode *parent){ 
    AvlNode *child = parent->left_child; 
    parent->left_child = rotate_RR(child); 
    return rotate_LL(parent); 

/*    旋转动作结束    */ 
 
int get_height(AvlNode *node){ 
    int height = 0; 
    if(node != NULL){ 
        height = 1 + max(get_height(node->left_child), get_height(node->right_child)); 
    } 
    return height; 

 
int get_balance(AvlNode *node){ 
    if(node == NULL) return 0; 
    return get_height(node->left_child) - get_height(node->right_child); 

 
/*    平衡二叉树    */ 
AvlNode *balance_tree(AvlNode **node){ 
    int height_diff = get_balance(*node); /* 平衡因子在-1到1之间*/ 
 
    if(height_diff > 1){ 
        if(get_balance((*node)->left_child) > 0){ 
            *node = rotate_LL(*node); 
        }else
            *node = rotate_LR(*node); 
        } 
    }else if(height_diff < -1){ 
        if(get_balance((*node)->right_child) < 0){ 
            *node = rotate_RR(*node); 
        }else
            *node = rotate_RL(*node); 
        } 
    } 
    return *node; 

 
AvlNode *avl_add(AvlNode **root, int key){ 
    if(*root == NULL){ 
        *root = (AvlNode *)malloc(sizeof(AvlNode)); 
        if(*root == NULL){ 
            printf("内存分配失败!\n"); 
            exit(-1); 
        } 
 
        (*root)->data = key; 
        (*root)->left_child = (*root)->right_child = NULL; 
    }else if(key < (*root)->data){ 
        (*root)->left_child = avl_add(&((*root)->left_child), key); 
        //balance_tree(root); 
    }else if(key > (*root)->data){ 
        (*root)->right_child = avl_add(&((*root)->right_child), key); 
        //balance_tree(root); 
    }else
        printf("复制%d失败!\n", key); 
        exit(-1); 
    } 
 
    return *root; 

 
AvlNode *avl_print(AvlNode *node){ 
    if(node == NULL) return NULL; 
 
    printf("%d->", node->data); 
 
    avl_print(node->left_child); 
    avl_print(node->right_child); 
    return node; 

 
int main(){ 
    avl_add(&root, 24); 
    avl_add(&root, 17); 
    avl_add(&root, 40); 
    avl_add(&root, 8); 
    avl_add(&root, 22); 
    avl_add(&root, 18); 
    avl_add(&root, 23); 
 
    printf("打印二叉树\n"); 
    avl_print(root); 
    printf("\n"); 
 
    balance_tree(&root); 
    printf("打印二叉树\n"); 
    avl_print(root); 
    printf("\n"); 
    return 0; 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.

 

                   

让我们看看伸展树!     

伸展树(Splay Tree,1985)

伸展树的基本原理:

   

 举例

我抽取一部分lighttpd-1.4.31.tar.gz中的代码,来讲解 

想看具体的代码实践的,可以到如下位置观看

我的代码结构:

代码部分

/*~ splaytree.h~*/ 
typedef struct tree_node{ 
    struct tree_node *left, *right; 
    int key;    /*  关键字  */ 
    int size;   /*  结点数目    */ 
    void *data; 
} splay_tree; 
/*我现在只写这两个方法*/ 
splay_tree * splaytree_insert(splay_tree *t, int key, void *data); 
splay_tree * splaytree_splay(splay_tree *t, int key); 
#define node_size(x) (((x)==NULL) ? 0 : ((x)->size)) 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

这个没有必要多讲,看注释和方法名称自然就知道干吗的了!

/* splaytree.c */ 
#include "splaytree.h" 
#include <stdio.h> 
#include <stdlib.h> 
#include <assert.h> 
#define compare(i,j) ((i) - (j)) 
splay_tree * splaytree_insert(splay_tree *t, int key, void *data){ 
    splay_tree * new
 
    if (t != NULL) { 
        t = splaytree_splay(t, key); 
        if(compare(key, t->key) == 0){ /*   该结点已存在    */ 
            return t; 
        } 
    } 
    new = (splay_tree *) malloc (sizeof (splay_tree)); 
    assert(new); 
    if (t == NULL) { 
        new->left = new->right = NULL; 
    } else if (compare(key, t->key) < 0) { 
        new->left = t->left; 
        new->right = t; 
        t->left = NULL; 
        t->size = 1 + node_size(t->right); 
    } else { 
        new->right = t->right; 
        new->left = t; 
        t->right = NULL; 
        t->size = 1 + node_size(t->left); 
    } 
    new->key = key; 
    new->data = data; 
new->size = 1 + node_size(new->left) + node_size(new->right); 
    return new

splay_tree * splaytree_splay(splay_tree *t, int key){ 
    splay_tree N, *l, *r, *child; /*    临时变量用于装配*t使用  */ 
    int cmp, l_size, r_size; 
    if (t == NULL) return t; 
    N.left = N.right = NULL; 
    l = r = &N; 
    l_size = r_size = 0; 
    for (;;) { 
        cmp = compare(key, t->key); 
 
        if (cmp < 0) { 
            if(t->left == NULL) break
            if (compare(key, t->left->key) < 0) { 
                child = t->left;                        /*  右旋    */ 
                t->left = child->right; 
                child->right = t; 
                t->size = 1 + node_size(t->left) + node_size(t->right); 
                t = child; 
                if(t->left == NULL) break
            } 
            r->left = t;                                /*  右链    */ 
            r = t; 
            t = t->left; 
            r_size += 1 + node_size(r->right); 
        } else if (cmp > 0) { 
            if(t->right == NULL) break
 
            if (compare(key, t->right->key) > 0) { 
                child =  t->right; 
                t->right = child->left; 
                child->left = t; 
                t->size = 1 + node_size(t->left) + node_size(t->right); 
                t = child; 
                if(t->right == NULL) break
            } 
            l->right = t; 
            l = t; 
            t = t->right; 
            l_size += 1 + node_size(l->left); 
        } else { 
            break
        } 
    } 
    l_size += node_size(t->left); 
    r_size += node_size(t->right); 
    t->size = 1 + l_size + r_size; 
 
    l->right = r->left = NULL; 
 
    /*  校验size数据    */ 
    /*右孩子的左结点不计算在内*/ 
    for(child = N.right; child != NULL; child = child->right){ 
        child->size = l_size; 
        l_size -= 1 + node_size(child->left); 
    } 
    for(child = N.left; child != NULL; child = child->left){ 
        child->size = r_size; 
 r_size -= 1 +node_size(child->right); 
    } 
    /*  装配数据    */ 
    l->right = t->left; 
    r->left = t->right; 
    t->left = N.right; 
    t->right = N.left; 
    return t; 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.

看到上面一坨代码估计大家不知所云了?

我就针对性的讲解一下。

>> 重点讲讲讲核心算法splaytree_splay()方法吧!

这个if讲通,那么另一个else if也好理解。

if (cmp < 0) { 
            if(t->left == NULL) break
 
            if (compare(key, t->left->key) < 0) { 
                child = t->left;                        /*  右旋    */ 
                t->left = child->right; 
                child->right = t; 
                t->size = 1 + node_size(t->left) + node_size(t->right); 
                t = child; 
 
                if(t->left == NULL) break
            } 
            r->left = t;                                /*  右链    */ 
            r = t; 
            t = t->left; 
            r_size += 1 + node_size(r->right); 
        } 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

这是一个右旋的过程。

  child = t->left

t->left = child->right; child->right = t;

 最后:t = child

这是一个右链的过程

 r->left = t;r=t;

 t = t->left

3>main.c

#include <stdio.h> 
#include "splaytree.h" 
splay_tree * splaytree_print(splay_tree *t){ 
    if(t != NULL){ 
        printf("t->data:%d\t t->key:%d t->size:%d\n", *((int *)t->data), t->key, t->size); 
        splaytree_print(t->left); 
        splaytree_print(t->right); 
    } 

int main(){ 
    splay_tree *root; 
    root = NULL; 
    int data1 = 1000; 
    root = splaytree_insert(root, 20, &data1); 
    int data2 = 200; 
    root = splaytree_insert(root, 5, &data2); 
    int data3 = 300; 
    root = splaytree_insert(root, 3, &data3); 
    int data4 = 100; 
    root = splaytree_insert(root, 10, &data4); 
    printf("打印结果*************\n"); 
    splaytree_print(root); 
 
 
    //这里应该有个数据查询过程,但是我没有写。注意在调用的时候调用一下splay方法, 
    //那么热数据自然就跑到顶端了。 
    printf("查询方法中调用这个伸展函数之后,打印结果*************\n"); 
    root = splaytree_splay(root, 3); 
    splaytree_print(root); 
    return 0; 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.

这里我没有把查询伸展树的过程写下来,只是强调一下,在查询的过程中,只要调用这个核心方法,那么自然热数据就跑到顶端了。

看一下过程

 

 

原文链接:http://www.cnblogs.com/baochuan/archive/2012/10/16/2716641.html 

【编辑推荐】

  1. 大型网站后台构建实践
  2. 图片存储架构学习:缓存,架构师的美丽小三
  3. 浅谈大型网站的算法和架构(二)
  4. 浅谈大型网站的算法和架构
  5. 企业应用架构模式之工作单元模式
责任编辑:张伟 来源: 川山甲的博客
相关推荐

2022-10-30 10:03:20

B+数据库数据

2024-02-27 07:35:55

B-TreeB+TreeMySQL

2019-11-26 15:12:08

数据存储B+树

2022-06-01 12:04:02

项目Webpack

2017-07-18 16:25:31

机器学习算法决策树

2022-09-26 07:56:53

AVL算法二叉树

2009-09-09 17:08:27

LINQ Expres

2023-10-10 11:02:00

LSM Tree数据库

2011-08-16 09:13:45

tree中文man

2009-09-09 17:02:05

LINQ Expres

2023-01-04 08:33:31

Linuxtree命令

2022-10-29 08:44:39

分布式数据库存储

2010-10-12 16:50:14

MySQL Hash索

2011-11-24 21:12:35

ibmdw

2020-02-13 17:27:31

CAPPaxos 共识算法

2021-06-28 07:01:50

Webpack 前端Tree shakin

2017-07-20 15:59:45

LinuxDevice Tree

2023-01-26 00:59:39

B-Treegolang度量衡

2022-02-10 14:23:16

WebpackJavaScript

2020-06-28 09:03:26

Linuxtree命令目录
点赞
收藏

51CTO技术栈公众号