索引--优化数据结构--平衡二叉树(avl)

在构建第二版搜索引擎时,为了提高数据结构的效率,作者决定对原始的二叉树进行优化,采用平衡二叉树——AVL树。AVL树能确保查找操作的时间复杂度保持在O(logN),避免了二叉树退化为链表后的性能问题。文章提到了AVL树旋转的重要性,并鼓励读者亲自绘制旋转过程以理解其工作原理。作者分享了部分代码,并引用了CSDN上的一篇文章作为参考来源。

天下文章一大抄,最近在做第二版的搜索引擎,比起第一版总要有很大的改进才行。

首先想到的是要对数据结构进行优化,就要把原来“倒排索引--二叉树 http://blog.csdn.net/txgc0/article/details/8697380

这边文章中提到的二叉树进行优化,众所周知,单纯的简单二叉树的坏处就怕退化,退化成一条链表后,这查找速度是相当难以让人接受的。

平衡二叉树的好处就是可以使时间复杂度保持在logN,不至于最坏的情况出现。

当然,越是好东西,越麻烦。

平衡二叉树就最复杂的情况就是树的旋转。这种旋转的过程可以查阅网上的很多文章,说的也比较详细,不过我建议,还是最好自己画画,看看是怎么样一个转换过程。

我算是借鉴一下某位大神的文章得出以下代码:

avl.c

#include "avl.h"

#include "utl.h"

static int Max(int a, int b);
static int Height(struct AVLTree* pNode);

static struct AVLTree* SingleRotateWithLeft(struct AVLTree* pNode);
static struct AVLTree* SingleRotateWithRight(struct AVLTree* pNode);
static struct AVLTree* DoubleRotateWithLeft(struct AVLTree* pNode);
static struct AVLTree* DoubleRotateWithRight(struct AVLTree* pNode);

struct AVLTree* insert_tree(unsigned int nData, struct AVLTree* pNode)
{
    if (NULL == pNode)
    {
        pNode = (struct AVLTree*)xmalloc(sizeof(struct AVLTree));
        pNode->nData = nData;
        pNode->nHeight = 0;
        pNode->pLeft = pNode->pRight = NULL;
    }
    else if (nData < pNode->nData)    
    {
        pNode->pLeft = insert_tree(nData, pNode->pLeft);
        if (Height(pNode->pLeft) - Height(pNode->pRight) == 2)   
        {
            if (nData < pNode->pLeft->nData)
            {
                pNode = SingleRotateWithLeft(pNode);
            }
            else
            {
                pNode = DoubleRotateWithLeft(pNode);
            }
        }
    }
    else if (nData > pNode->nData)   
    {
        pNode->pRight = insert_tree(nData, pNode->pRight);
        if (Height(pNode->pRight) - Height(pNode->pLeft) == 2)   
        {
            if (nData > pNode->pRight->nData)
            {
                pNode = SingleRotateWithRight(pNode);
            }
            else
            {
                pNode = DoubleRotateWithRight(pNode);
            }
        }
    }

    pNode->nHeight = Max(Height(pNode->pLeft), Height(pNode->pRight)) + 1;

    return pNode;
}



void delete_tree(struct AVLTree** ppRoot)
{
    if (NULL == ppRoot || NULL == *ppRoot)
        return;

    delete_tree(&((*ppRoot)->pLeft));
    delete_tree(&((*ppRoot)->pRight));
    xfree(*ppRoot);
    *ppRoot = NULL;
}

void print_tree(struct AVLTree* pRoot)
{
	static int n = 0;
    if (NULL == pRoot)
        return;
    
    print_tree(pRoot->pLeft);
    printf("[%d]nData = %u\n", ++n, pRoot->nData);
    print_tree(pRoot->pRight);
}

int find_tree(unsigned int data, struct AVLTree* pRoot)
{
    static int k=1;   
    if (NULL == pRoot)
    {
        printf("not find %d times\n", k);
        return 0;
    }

    if(data == pRoot->nData)
    {
        printf("find:%d times\n", k);
        return 1;
    }
    else if(data < pRoot->nData)
    {
        ++k;
        return find_tree(data, pRoot->pLeft);
    }
    else if(data > pRoot->nData)
    {
        ++k;
        return find_tree(data, pRoot->pRight);
    }
	return 0;
}

static int Max(int a, int b)
{
    return (a > b ? a : b);
}

static int Height(struct AVLTree* pNode)
{
    if (NULL == pNode)
        return -1;

    return pNode->nHeight;
}

/********************************************************************
      pNode pNode->pLeft
      / \
  pNode->pLeft ==> pNode
      \     /
  pNode->pLeft->pRight pNode->pLeft->pRight
 *********************************************************************/
static struct AVLTree* SingleRotateWithLeft(struct AVLTree* pNode)
{
    struct AVLTree* pNode1;

    pNode1 = pNode->pLeft;
    pNode->pLeft = pNode1->pRight;
    pNode1->pRight = pNode;

    pNode->nHeight = Max(Height(pNode->pLeft), Height(pNode->pRight)) + 1;
    pNode1->nHeight = Max(Height(pNode1->pLeft), pNode->nHeight) + 1;

    return pNode1;
}

/********************************************************************
  pNode pNode->pRight
  \ /
  pNode->pRight ==> pNode
  / \
  pNode->pRight->pLeft pNode->pRight->pLeft
 *********************************************************************/
static struct AVLTree* SingleRotateWithRight(struct AVLTree* pNode)
{
    struct AVLTree* pNode1;

    pNode1 = pNode->pRight;
    pNode->pRight = pNode1->pLeft;
    pNode1->pLeft = pNode;

    pNode->nHeight = Max(Height(pNode->pLeft), Height(pNode->pRight)) + 1;
    pNode1->nHeight = Max(Height(pNode1->pRight), pNode->nHeight) + 1;

    return pNode1;
}

static struct AVLTree* DoubleRotateWithLeft(struct AVLTree* pNode)
{
    pNode->pLeft = SingleRotateWithRight(pNode->pLeft);

    return SingleRotateWithLeft(pNode);
}

static struct AVLTree* DoubleRotateWithRight(struct AVLTree* pNode)
{
    pNode->pRight = SingleRotateWithLeft(pNode->pRight);

    return SingleRotateWithRight(pNode);
}


avl.h

#ifndef __AVL_H__
#define __AVL_H__



struct AVLTree
{
    unsigned int nData;    
    struct AVLTree* pLeft;   
    struct AVLTree* pRight;   
    int nHeight;   
};

struct AVLTree* insert_tree(unsigned int nData, struct AVLTree* pNode);

extern int find_tree(unsigned int data, struct AVLTree* pRoot);

void delete_tree(struct AVLTree** ppRoot);

extern void print_tree(struct AVLTree* pRoot);

#endif


main.c

#include <time.h>

#include "avl.h"
#include "utl.h"

int main()
{
    int i,j;
    struct AVLTree* pRoot = NULL;

    srand((unsigned int)time(NULL));
    
    for (i = 0; i < 10; ++i)
    {
            j = rand();
            printf("%d\n", j);
			pRoot = insert_tree(j, pRoot);
    }

//    PrintTree(pRoot);

 //   DeleteTree(&pRoot);

    return 0;
}


utl.h

#ifndef __UTL_H__
#define __UTL_H__

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

inline void *xmalloc(int size)
{
    void *p;
    p = (void *)malloc(size);

    if(p == NULL)
    {
        printf("alloc error\n");
        exit(1);
    }
    return p;
}
#define xfree(p) free(p)

#endif


我得尊重作者的劳动成果,不知道是不是这位大神手写的,但是我是从这里看到的,所以我要注明来处的链接:

http://blog.csdn.net/w397090770/article/details/8119616

说实话,他写的真好。。。。增加一下人品。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值