首页 > 代码库 > Python用两个list模拟有序字典

Python用两个list模拟有序字典

python语言中的dict(字典)类型是无序的。但是,实际中,我们有时会用到有序字典这种结构,也就是在一个有序的结构中存储一系列键值对。这里介绍的是,如何用两个list来实现这个结构。

1、bisect模块

1.1 介绍

python中的bisect模块可以实现向有序列表中插入元素,同时维护列表的顺序。bisect的实现也比较简单,大致的原理是首先使用二分查找,查找应该插入的位置,然后用list的insert方法将元素插入到指定的位置。bisect模块的代码不多,总共不到100行,而且非常简单易读。

从代码可以看出,bisect模块中,主要实现了四个函数,功能如下:

  • bisect.bisect_left(a,x, lo=0, hi=len(a)):查找在有序列表a中插入x的index。lo和hi用于指定列表的区间,默认是使用整个列表。如果x已经存在,在其左边插入。返回值为index。
  • bisect.bisect_right(a,x, lo=0, hi=len(a))与bisect.bisect(a, x,lo=0, hi=len(a))和bisect_left类似,但如果x已经存在,在其右边插入。返回值同样为index
  • bisect.insort_left(a,x, lo=0, hi=len(a)):在有序列表a中插入x,相当于a.insert(bisect.bisect_left(a,x, lo, hi), x)。该函数默认没有返回值。
  • bisect.insort_right(a,x, lo=0, hi=len(a))与bisect.insort(a, x,lo=0, hi=len(a))和insort_left类似,但如果x已经存在,在其右边插入。同样,这两个函数也没有返回值。
其实,由于简单bisect里面的这四个函数,既容易理解,也容易记忆。bisect_*的函数主要是用来查找插入的位置,insort_*函数是直接将元素放入相应的位置,完成插入。从bisect模块的实现可以看出,bisect模块中insort函数的插入实现实际上用的就是bisect函数返回的index。所以,在实际中,bisect函数返回的index,也可以直接用在list的insert函数中作为插入位置参数。

1.2 例子

下面是在python交互模式下使用bisect模块的几个例子:

>>> import bisect
>>> a = []
>>> bisect.bisect(a, 3)
0
>>> bisect.insort(a,3)
>>> print a
[3]
>>> bisect.insort(a,5)
>>> bisect.insort(a,1)
>>> print a           
[1, 3, 5]
>>> bisect.bisect(a, 4)
2
>>> bisect.insort(a, 4)      
>>> print a
[1, 3, 4, 5]
>>> 
2、用两个数组来模拟有序字典

这里采用的是最简单的方式,就是用两个数组一个存key、另一个寸value。下面的代码中,还实现了size的设定,维护结构中的总的元素个数,不能超过5,也就是说最多存5个元素(当然,如果你的代码中不需要,可以将size限定的代码去掉)。代码如下:

import bisect
def add_to_list(key_list, value_list, k, v): 
    ''' 
    The parameter key_list and value_list should be [] or [some elements that positioned in an ascending order].
    This function add k,v pair to the key_list and value_list respectively, keeping the orginal order.
    Return value: the position that the k,v pair is inserted. The position is where the new-inserted element located after insertion.
    '''
    if len(value_list) < 5:
        #find the insertion postion
        position = bisect.bisect(value_list,v)
        key_list.insert(position,k)
        value_list.insert(position, v)
    else:
        if v > value_list[0]:
            #find the insertion postion
            position = bisect.bisect(value_list,v)
            key_list.insert(position,k)
            value_list.insert(position, v)
            del(value_list[0])
            del(key_list[0])
    return position

if __name__ == "__main__":
    lk1 = ["zz"]
    lv1 = [2626]
    lk = ["bb","ee","cc","aa","dd"]
    lv = [22,55,33,11,44]
    for i in range(0,5):
        position = add_to_list(lk1,lv1,lk[i],lv[i])
        print '%3d  %3d' % (lv[i],position),lv1, lk1 
    print "Over!"
这段代码的运行结果如下:

$ python test.py
 22    0 [22, 2626] ['bb', 'zz']
 55    1 [22, 55, 2626] ['bb', 'ee', 'zz']
 33    1 [22, 33, 55, 2626] ['bb', 'cc', 'ee', 'zz']
 11    0 [11, 22, 33, 55, 2626] ['aa', 'bb', 'cc', 'ee', 'zz']
 44    3 [22, 33, 44, 55, 2626] ['bb', 'cc', 'dd', 'ee', 'zz']
Over!
好了,就到这里了。可以看出,python的好处就是不用费尽心思去写二分查找这类的代码,减少重复工作。程序员只需要focus在自己要解决的问题上,这样工作量就小了。^_^

Python用两个list模拟有序字典