总论

算法与数据结构是程序员一项十分重要的技能,对于python而言,其数据类型强大但却不够丰富,虽然我们能够通过列表等结构模拟或者通过类进行数据结构的新建,但在某些场合却显得麻烦一些,比如在进行力扣比赛的过程中,下面通过几个库的介绍,展示python中库里构建的极具魔力的数据结构,能够让你在刷题的过程中事半功倍

collections

collections.Counter()

这个可能是大家比较熟悉的,他会对可迭代对象其中的内容进行计数,然后返回一个字典,这个功能我们常用,假如要对一个列表元素进行计数,我们有几种写法:

##不调用库的写法
color = ['red', 'blue', 'red', 'green', 'blue', 'blue']
count = {}
for i in color:
    count[i] = count.get(i,0) + 1
print(count)
# out:{'red': 2, 'blue': 3, 'green': 1}
-----------------------------------------------------
##调用库
from collections import Counter
color = ['red', 'blue', 'red', 'green', 'blue', 'blue']
print(Counter(color))
# out:Counter({'blue': 3, 'red': 2, 'green': 1})
-----------------------------------------------------
## 对象的其他方法elements()
from collections import Counter
color = ['red', 'blue', 'red', 'green', 'blue', 'blue']
print(list(Counter(color).elements()))
## out: ['red', 'red', 'blue', 'blue', 'blue', 'green']
## 我们调用elements()方法返回一个可迭代的对象,而且作为 dict 的子类,
##Counter 继承了记住插入顺序的功能,但结果这样我们基本也就能够反推counter
#类的实现了

-----------------------------------------------------
## most_common方法
Counter('abracadabra').most_common(3)
# out:[('a', 5), ('b', 2), ('r', 2)]
-----------------------------------------------------
## counter还支持__add__等魔法方法:
c = Counter(a=3, b=1)
d = Counter(a=1, b=2)
c + d                       
#out:Counter({'a': 4, 'b': 3})
c - d                     
#out:Counter({'a': 2})
c & d                     
#out: Counter({'a': 1, 'b': 1})

c | d                     
#out:Counter({'a': 3, 'b': 2}
collections.OrderedDict()

这个可能并不是常用的,由于内置的 dict 类获得了记住插入顺序的能力,这个可能不是那么重要了,但是其仍旧有一些特性类似栈和双端队列,这让我们想对映射对象采用这种数据结构时,发挥一定的作用,下面将其方法进行简单叙述:

popitem(last=True)

有序字典的 popitem() 方法移除并返回一个 (key, value) 键值对。 如果 last 值为真,则按 LIFO 后进先出的顺序返回键值对,否则就按 FIFO 先进先出的顺序返回键值对。

move_to_end(key, last=True)

将现有 key 移动到有序字典的任一端。 如果 last 为真值(默认)则将元素移至末尾;如果 last 为假值则将元素移至开头。如果 key 不存在则会触发 KeyError:
collections.deque

双端队列,这个就经常用到了,虽然我们可以直接用python的列表的pop(),和pop(0),进行一定程度的模拟,但熟悉python列表实现的可能会了解,pop(0)的开销是很大的,而deque对象,实现了开销为O(1)的方法,除此以外,deque还有一些很有趣的方法,在我们做题的过程中十分重要,甚至能够帮我们直接AC,下面将一些方法进行简单叙述:

from collections import deque
c = deque([1,2,3,4,5])
print(c)
c.append(6)
print(c)
c.popleft()
print(c)
c.pop()
print(c)
c.appendleft(1)
print(c)
c.extend([6,7,8])
print(c)
c.extendleft([0,-1])
print(c)
'''
out:
deque([1, 2, 3, 4, 5])
deque([1, 2, 3, 4, 5, 6])
deque([2, 3, 4, 5, 6])
deque([2, 3, 4, 5])
deque([1, 2, 3, 4, 5])
deque([1, 2, 3, 4, 5, 6, 7, 8])
deque([-1, 0, 1, 2, 3, 4, 5, 6, 7, 8])
'''
##其他还有一些方法与列表类似,如,index,reverse, insert这里不再赘述

在python3.5后,其还增加了一个有趣的方法,rotate(n=1)
向右循环移动 n 步。 如果 n 是负数,就向左循环。

如果deque不是空的,向右循环移动一步就等价于 d.appendleft(d.pop()) , 向左循环一步就等价于 d.append(d.popleft()) 。

那如果像是这个力扣题目

python django 数据库树形菜单的设计 python数据结构库_python


用上这个那岂不是直接AC

collections.namedtuple

这个对象并不是很常用,其作用是方便我们创建一个元组子类,通过属性名直接访问元组值,直接把官网上给的demo粘贴在这里,有需要的自查

# Basic example
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(11, y=22)     # instantiate with positional or keyword arguments
>>> p[0] + p[1]             # indexable like the plain tuple (11, 22)
33
>>> x, y = p                # unpack like a regular tuple
>>> x, y
(11, 22)
>>> p.x + p.y               # fields also accessible by name
33
>>> p                       # readable __repr__ with a name=value style
Point(x=11, y=22)

heapq

优先队列,那简直是力扣刷题的必备利器,废话不多说,我们直接看他的使用

import heapq
#初始化1
c = []
heapq.heappush(c,3)
print(c)
##2
c = [4,5,6,8,5,2]
heapq.heappush(c, 3)# 这样并不是正确的,因为我们还没有对列表进行初始化
print(c)
print(heapq.heappop(c))
##3
c = [4,5,6,8,5,2]
heapq.heapify(c)
heapq.heappush(c, 3)
print(c)
print(heapq.heappop(c))

除了这些之外,还有一些合并的集成方法,调用他们是更具有效率的

  • heapq.heappushpop(heap, item): 将 item 放入堆中,然后弹出并返回 heap 的最小元素
  • heapq.heapreplace(heap, item): 弹出并返回 heap 中最小的一项,同时推入新的 item。 堆的大小不变
  • heapq.nlargest(n, iterable, key=None): 从 iterable 所定义的数据集中返回前 n 个最大元素组成的列表
  • heapq.nsmallest(n, iterable, key=None)

array

其功能与列表类似,个人感觉刷题的过程中使用的并不是很普遍,其与列表类似,需要其中元素的类型保持一致,这种设计模式,使得他比列表更加高效

二分查找库 bisect

bisect是针对于有序列表的专用库,二分查找虽然是很简单的算法,但在边界判断上,感觉并不是很清楚,所以我直接把代码搬过来了顺便学习一下

"""Bisection algorithms."""

def insort_right(a, x, lo=0, hi=None):
    """Insert item x in list a, and keep it sorted assuming a is sorted.
    If x is already in a, insert it to the right of the rightmost x.
    Optional args lo (default 0) and hi (default len(a)) bound the
    slice of a to be searched.
    """

    lo = bisect_right(a, x, lo, hi)
    a.insert(lo, x)

def bisect_right(a, x, lo=0, hi=None):
    """Return the index where to insert item x in list a, assuming a is sorted.
    The return value i is such that all e in a[:i] have e <= x, and all e in
    a[i:] have e > x.  So if x already appears in the list, a.insert(x) will
    insert just after the rightmost x already there.
    Optional args lo (default 0) and hi (default len(a)) bound the
    slice of a to be searched.
    """

    if lo < 0:
        raise ValueError('lo must be non-negative')
    if hi is None:
        hi = len(a)
    while lo < hi:
        mid = (lo+hi)//2
        # Use __lt__ to match the logic in list.sort() and in heapq
        if x < a[mid]: hi = mid
        else: lo = mid+1
    return lo

def insort_left(a, x, lo=0, hi=None):
    """Insert item x in list a, and keep it sorted assuming a is sorted.
    If x is already in a, insert it to the left of the leftmost x.
    Optional args lo (default 0) and hi (default len(a)) bound the
    slice of a to be searched.
    """

    lo = bisect_left(a, x, lo, hi)
    a.insert(lo, x)


def bisect_left(a, x, lo=0, hi=None):
    """Return the index where to insert item x in list a, assuming a is sorted.
    The return value i is such that all e in a[:i] have e < x, and all e in
    a[i:] have e >= x.  So if x already appears in the list, a.insert(x) will
    insert just before the leftmost x already there.
    Optional args lo (default 0) and hi (default len(a)) bound the
    slice of a to be searched.
    """

    if lo < 0:
        raise ValueError('lo must be non-negative')
    if hi is None:
        hi = len(a)
    while lo < hi:
        mid = (lo+hi)//2
        # Use __lt__ to match the logic in list.sort() and in heapq
        if a[mid] < x: lo = mid+1
        else: hi = mid
    return lo

# Overwrite above definitions with a fast C implementation
try:
    from _bisect import *
except ImportError:
    pass

# Create aliases
bisect = bisect_right
insort = insort_right

外部库sortedcontainers

第一次见这个库是在力扣题解上看到的其包含三种类型,SortedList,SortedDict,SortedSet下面我们来分别进行介绍:

SortedList
import sortedcontainers
c = [9,8,7,6,5,4,3,2,1]
c = sortedcontainers.SortedList(c)
print(c)
c.add(5.5)
print(c)
c.update([1.5,1.4,1.3,1.2])
print(c)
c.discard(9)
print(c)
c.discard(10)
print(c)
#out:
'''
SortedList([1, 2, 3, 4, 5, 6, 7, 8, 9])
SortedList([1, 2, 3, 4, 5, 5.5, 6, 7, 8, 9])
SortedList([1, 1.2, 1.3, 1.4, 1.5, 2, 3, 4, 5, 5.5, 6, 7, 8, 9])
SortedList([1, 1.2, 1.3, 1.4, 1.5, 2, 3, 4, 5, 5.5, 6, 7, 8])
SortedList([1, 1.2, 1.3, 1.4, 1.5, 2, 3, 4, 5, 5.5, 6, 7, 8])
'''

其还有一些查看值的方法,其函数作用看名字就能看出来,这里不再过多介绍了

python django 数据库树形菜单的设计 python数据结构库_数据结构_02


两个demo

#第一个
sl = SortedList('abcdefghij')
it = sl.islice(2, 6)
list(it)
#out:['c', 'd', 'e', 'f']

------------------------------------
#第二个
sl = SortedList('abcdefghij')
it = sl.irange('c', 'f')
list(it)
out:['c', 'd', 'e', 'f']