Python 十大数据结构

Python 十大数据结构

1.list

  • 基本用法

  • 使用场景

    list 使用在需要查询,修改的场景,极不擅长需要频繁的插入,删除元素的场景

  • 实现原理

    list 对应数据结构的线性表,列表长度在初始状态无需指定,当插入元素超过初始长度后在启动动态扩容,时间复杂度O(n)

2.tuple

元组是一类不允许添加和删除元素的特殊列表,一旦创建不允许添加和删除修改

  • 基本用法

    元组大量使用在打包和解包处,如函数有多个返回值打包为一个元组,赋值到等号左侧变量时解包

    t = 1,2,3
    type(t)
    tuple
    
  • 使用场景

    相比于list,tuple实例更加节省内存,如果确定你的对象后面不会被修改,可以大胆使用元组。

    # getsizeof 获取对象所占内存
    from sys import getsizeof
    getsizeof(list())#56
    getsizeof(tuple())#40
    

    不同Python 版本得到的值可能不一样,我测试版本为Python3.9

  • 实现原理

3.set

  • 基本用法

    set 是一种里面不能含有重复元素的数据结构,这种特性可以用来列表的去重

    # 使用set 对list 去重
    a = [1,2,3,4,5,1]
    set(a)# {1,2,3,4,5}
    # 使用 set 对set 做交集,并集,差集等操作
    a = {1,2,3}
    b = {3,4,5}
    a.intersection(b) #{3}
    
  • 使用场景

    如果只是想缓存某些元素值,并且要求元素值不能重复时,可以使用此结构,并且set内部允许增删元素,且效率很高

  • 实现原理

    set 在内部将值哈希为索引,然后按照索引去获取数据,因此删除,增加,查询元素效率都很高

4.dict

  • 基本用法

    # 创建字典
    d = {'a':1,'b':2}
    # 列表生成式
    d = {a:b for a,b in zip(['a','b'],[1,2])}
    d #{'a':1,'b':2}
    
  • 使用场景

    字典适合在查询较多的场景,时间复杂度O(1),Python类中属性值等信息也是缓存在__dict__这个字典型数据结构中

    from sys import getsizeof
    getsizeof(dict()) #232
    

    dict占用字节数是list,tuple 的三四倍,对内存要求苛刻的场景谨慎使用字典

  • 实现原理

    字典是一种哈希表,同时保存了键值对

5.deque

deque 双端队列,基于list 优化了列表两端的增删数据的操作

  • 基本用法

    from collections import deque
    d = deque([3,2,4,0])
    # 左侧移除元素 O(1) 时间复杂度
    d.popleft() #3
    # 左侧添加元素O(1)时间复杂度
    d.appendleft(3) #3
    d #deque([3,2,4,0])
    
  • 使用场景

    list 左侧添加删除元素的时间复杂度都为O(n),所以在Python中模拟队列是不要使用list,deque双端队列非常适合频繁在列表两端操作的场景,但是deque占用字节数特别大

    In [15]: from sys import getsizeof
    In [16]: from collections import deque
    In [17]: getsizeof(deque)
    Out[17]: 408
    
  • 实现原理

    cpython 实现deque使用默认长度64的数组,每次从左侧移除一个元素,leftindex 加1,如果超过64就释放原来的内存块,在重新申请64长度的数组,并使用双端链表block管理内存块。

6.Counter

Counter 一种继承于dict用于统计元素个数的数据结构,也被称为bag或multiset

  • 基本用法

    In [18]: from collections import Counter
    In [19]: c = Counter([1,2,3,4,5,1,2,3])
    In [20]: c
    Out[20]: Counter({1: 2, 2: 2, 3: 2, 4: 1, 5: 1})
    # 统计第一最常见的项,返回元素及其次数的元组
    In [21]: c.most_common(1)
    Out[21]: [(1, 2)]
    
  • 使用场景

    基本的dict能解决的问题就不要用Counter,但是遇到统计元素出现频次的场景,果断使用Counter

  • 实现原理

    Counter实现基于dict,它将元素存储于keys上,出现次数为values

7.OrderedDict

  • 基本用法

    继承于dict,能确保keys值按照顺序取出来的数据结构

    In [22]: from collections import OrderedDict
    
    In [23]: od = OrderedDict({'c':3,'a':1,'b':2})
    
    In [24]: for k,v in od.items():
        ...:     print(k,v)
        ...:
    c 3
    a 1
    b 2
    
  • 使用场景

    基本的dict无法保证顺序,keys映射为哈希值,而此值不是按照顺序存储在散列表中,所以遇到要确保字典keys有序场景,就要使用OrderedDict

  • 实现原理

    你一定会好奇OrderedDict如何确保keys顺序的,翻看cpython看到它里面维护着一个
    双向链表self.__root ,它维护着keys的顺序。既然使用双向链表,细心的读者可能会有疑
    问:删除键值对如何保证O(1)时间完成?
    cpython使用空间换取时间的做法,内部维护一个self.__map 字典,键为key,值为指向双向链
    表节点的link . 这样在删除某个键值对时,通过__map在O(1)内找到link,然后O(1)内从双向链
    表__root中摘除。

8.heapq

基于list优化的一个数据结构:堆队列,也称为优先队列。堆队列特点在于最小的元素
总是在根结点

  • 基本用法

    In [25]: import heapq
    In [26]: a = [2,3,4,15,1]
    # 对 a 建堆,建堆完成后对a就地排序
    In [27]: heapq.heapify(a)
    # 排序好的 a
    In [28]: a
    Out[28]: [1, 2, 4, 15, 3]
    In [29]: a[0]
    Out[29]: 1
    # 最大的前两个元素
    In [30]: heapq.nlargest(2,a)
    Out[30]: [15, 4]
    # 最小的前三个元素
    In [31]: heapq.nsmallest(3,a)
    Out[31]: [1, 2, 3]
    
  • 使用场景

    如果要想要统计list中前几个最小(大)元素,使用heapq很方便,同时它还提供合并多个有序小list为大list的功能

  • 实现原理

    堆是一个二叉树,它的每个父节点的值都只会小于或大于所有的孩子节点的值

9.defaultdict

  • 基本用法

    In [34]: words=['book','nice','great','book']
    In [35]: d ={}
    In [36]: for i,word in enumerate(words):
        ...:     if word in d:
        ...:         d[word].append(i)
        ...:     else:
        ...:         d[word] =[i]
        ...:
    
    In [37]: d
    Out[37]: {'book': [0, 3], 'nice': [1], 'great': [2]}
    
    # 使用defaultdict
    In [38]: from collections import defaultdict
    In [39]: d = defaultdict(list)
    In [40]: for i,word in enumerate(words):
        ...:     d[word]=i
        ...:
    In [41]: d
    Out[41]: defaultdict(list, {'book': 3, 'nice': 1, 'great': 2})
    
  • 使用场景

    适用于键的值必须指定一个默认值的场景,如键的值为list,set,dict

  • 实现原理

    调用工厂函数去提供确实的键的值

10.ChainMap

  • 基本用法

    如果有多个dict 想要合并成一个大的dict,那么ChainMap是你的选择,它的方便性体现在同步更改。

    In [42]: from collections import ChainMap
    
    In [43]: d1 = {'a':1,'b':2,'c':3}
    
    In [44]: d2 = {'d':4,'e':5,'f':6}
    # 使用 ChainMap合并 d1 d2
    In [45]: dm = ChainMap(d1,d2)
    In [46]: dm
    Out[46]: ChainMap({'a': 1, 'b': 2, 'c': 3}, {'d': 4, 'e': 5, 'f': 6})
    In [48]: dm.maps
    Out[48]: [{'a': 1, 'b': 2, 'c': 3}, {'d': 4, 'e': 5, 'f': 6}]
    # 增加元素,体现在d1上
    In [49]: dm.maps[0][2]=9
    In [50]: dm.maps
    Out[50]: [{'a': 1, 'b': 2, 'c': 3, 2: 9}, {'d': 4, 'e': 5, 'f': 6}]
    In [51]: d1
    Out[51]: {'a': 1, 'b': 2, 'c': 3, 2: 9}
    # 修改元素,体现在d1上
    In [52]: dm.maps[0]['c']=9
    In [53]: dm
    Out[53]: ChainMap({'a': 1, 'b': 2, 'c': 9, 2: 9}, {'d': 4, 'e': 5, 'f': 6})
    In [54]: d1
    Out[54]: {'a': 1, 'b': 2, 'c': 9, 2: 9}
    
  • 使用场景

    具体使用场景是我们有多个字典或者映射,想把他们合并成为一个单独的映射

    使用update进行合并,会新建一个内存结构,除了浪费空间外,还有一个缺点,就是我们对新字典的更改不会同步到源字典上

  • 实现原理

    通过maps便能观察出ChainMap联合多个小dict装入list中,实际确实也是这样实现的,内部维护一个lis实例,其元素为小dict.

你可能感兴趣的:(Python,python,数据结构,开发语言)