提高链表随机访问效率的一种方案

来源:互联网 发布:好的日记软件 编辑:程序博客网 时间:2024/05/16 23:36
一、问题的描述

    链表由于各个元素之间是通过指针方式连接在一起,所以增加删除都非常方便,但是在随机访问却远不如数组。数组的下标是可以通过算法直接定位的,但链表却不行。

二、问题的方案
    我们定义一种组织方式,以链表为基础,但是将相连的若干元素组成一个簇,和一个节点相关联。这个节点只负责管理链表元素的指针头部,和这个簇的所有元素的数量。当链表增加删除元素时,可以通过改变节点所记录的簇的头部和簇的数量来重新管理簇。如果这个节点没有簇元素,那么将这个节点删除,如果这个节点记录的簇元素数量超出最高限度,那么将进行分裂。当簇中元素作为链表的元素删除时,只需要减少节点记录簇元素的数量。
    我们通过树来管理这些节点,将这些节点作为树的叶子。树的节点可以支持N个分支,对于每个分支,只记录分支下所有的簇元素数量。
    我们这个方案的核心方案是通过树的方式来组织每个元素的下标,利用树的节点访问速度来拉近链表和数组之间的下标访问效率,同时保持链表增删元素的灵活性。我们打个比方,1个1K个节点的链表,如果要访问第500个节点,必须遍历500次,如果有个中间节点记录第500个节点的位置,那么我们只要遍历一次。

三、问题的分析
    现在我们来计算添加树管理下标所需要的节点访问次数。包括树高度和叶子节点的数量,如果叶子节点只有一个,那这个树就退化成二叉树了,所以叶子节点包含的链表节点数是个很关键的问题。实际访问次数等于树的层高加上叶子的链表节点数。

一、链表元素结构
    typedef struct _elem_st elem_t
    struct _elem_st{
           elem_t *prev ;
           elem_t *next;
           int len ;
           char *buf ;
    } ;

    这是个双向链表,在增加删除时要方便多了。

二、索引结构
    1、叶子结构
    typedef struct _leaf_st leaf_t ;
    struct _leaf_st{
           elem_t *header ;
           int count ;
    } ;

    2、节点结构
    typedef struct _node_st node_t
    struct _node_st{
          leaf_t *leafs[1024] ;
          int count ;
    } ;

    3、树结构
    typedef struct _tree_st tree_t ;
    struct _tree_st{
           node_t *nodes[1024] ;
           int count ;
    } ;

    上面定义的结构很笨,但是很容易说明思路。我们现在来模拟增加删除一个元素,看这个过程。

一、定位元素
    elem_t *find_elem(int index) ;
    1、顺序遍历tree->nodes数组,直到count
    2、累计node->count,直到index在两个node之间
    3、找到对应的leaf_t,很容易返回。

二、删除元素
    1、判断下标小于数的总节点数
    2、定位元素下标
    3、从树的顶层开始,到该元素的每个路经的节点,计数器减1。
    4、删除链表中该元素。

三、增加元素
    2、定位元素下标
    3、从树的顶层开始,到该元素的每个路经的节点,计数器加1。
    4、在链表中添加该元素。

我们访问的方式比数组多很多,但是链表要少很多。



原创粉丝点击