语法细节,数据结构,使用时容易出错的和忽略的地方
之python篇

了解 熟悉 ==掌握== 精通

if len(heap) < k:
    heapq.heappush(heap, x)
else:
    heapq.heappushpop(heap, x)

return heap[0]

# 1. 插入:[list].insert  

是插入原list,而不是返回新list 
有两个参数,[list].insert([值], [位置])   


# 2. str|list 通用|有区别的参数
in str和list都可以用。

find 和 index:
① find 只可以用在 str,不存在会返回-1;
② index可用在str和list,不存在会error;


# 3. 判断list是否相等
① 必须位置、值全相等才算相等
② 可以使用 operator

import operator
operator.eq(a, b)

对象创建后hash值在生命周期里不可变
可hash:不可变的数据结构 str tuple object
不可hash:可变的数据结构 list dict set  

使用hash算法的数据结构叫hash表,也叫散列表。


# 4. 相等
is:值和地址都相等
==:只有值相等
__eq__:和==一样。即引用相等。

__hash__:返回一个int值:hash(id(self)),为这个对象设定一个唯一hash值

set 去重
① 当两个变量hash值不同,就认为两个变量不同
② 当两个变量hash值一样时,调用__eq__方法,true去重,false不去。


# 5. 时间开销
默认长度皆为n。k代表随机。x是随便一个字符。

LIST:
.append()   O(1)
.pop()      O(1)  
.pop[k]     O(k)
.insert()   O(n)
.extend()   O(k)
.index()    O(n)   # 返回alsit里【第一个】astr的序列号
[x] in      O(n)
min()/max() O(n)
len()       O(1)

SET/DICT:
in  平均 1 | 最差 n
get 平均 1 | 最差 n
set 平均 1 | 最差 n
del 平均 1 | 最差 n

* 最坏是因为摊销 *
* ep: dic[N],删除N-1个元素,会重新为N个元素调整大小 *


# 6. 删除
LIST:
.pop(索引)
.remove(值)
del list[索引]

DICT:
.pop(key)  O(1)
.popitem() 【随机】
del dict[key]
.clear()  【删所有】

SET:
.pop() 【随机】 O(1) 
.remove(值) O(1)
.discard(值) 

其中,
list的.remove(值)为删除首个该值;
dict的 del dict[key]没有返回值,.pop(key)有返回值。


# 7. random
.randint(i, j) # [i, j] 范围内整数。**注意是闭区间**
.random() # 0-1间浮点数
.uniform(i, j) # [i, j] 范围内浮点数
.choice(str)
.randrange(i, j, gap)
.shuffle() # 打乱原函数


# 8. 堆
import heapq # 默认是小顶堆/最小堆 min_heap,也就是堆顶元素始终是堆中最小的元素

大顶堆就是根最大。小顶堆就是根最小。

import heapq # 它是小顶堆/最小堆 min_heap,也就是堆顶元素始终是堆中最小的元素
1. 创建:
	heap = []
	for n in data:
	    heapq.heappush(heap, n) # heap要提前创建个list
	或者:
	heapq.heapify(data) # data本身就变成堆

2. 弹出:
	heapq.heapify(data)
	for i in range(2):
		smallest = heapq.heappop(data)

3. 删除并替换成新值
	heapq.heapify(data)
	for n in [0, 13]:
	    smallest = heapq.heapreplace(data, n)

	# 在一个操作中将num添加到堆并从heap中删除最小项
	heapq.heappushpop(heap, num)

4. 找范围
	heapq.nlargest(3, data) # 最大的前3个 按从大到小
	heapq.nsmallest(3, data) # 最小的前3个 按从小到大

5. 找第k
	找第k大的元素,用小顶堆。因为当 len(list)>=k时,再进去值时,被替换出来的是堆顶=【最小的值】。
	所以当循环完了之后,里面剩的是最大的k个值,且第k个是堆里最小的。

	找第k小的元素,用大顶堆。pushpop出的是堆定=最大的值。完之后剩的是最小的k个值

	模板:
		if len(heap) < k:
			heapq.heappush(heap, x)
		else:
			heapq.heappushpop(heap, x)

		return heap[0]

**创建大顶堆和大顶堆排序不一样。**
大顶堆排序 = 创建大顶堆 + 不断交换 n[0] 和 n[-1],并重复创建剩下的数为大顶堆。
创建大顶堆关键:找出最后一个有子树的i = len(n) // 2 - 1


# 9. 队列 queue
四种队列
queue.Queue | 面向多生产/多消费线程的队列
asyncio.Queue | 面向多生产/多消费协程的队列
multiprocessing.Queue | 面向多生产/多消费进程的队列
collections.deque | 在数据结构层面实现队列,无应用场景的基础数据结构

① collections.deque
一般做数据结构就用这种

from collections import deque

# 初始化
queue = deque(maxlen=10)

queue可原地初始化
q = queue(alist) | queue('astring')

添加:O(1)
.append(元素) | .appendleft(元素)
.extend(数组) | .extendleft(数组)

插入:O(n)
insert(index, 值)

弹出:O(1)
.pop() | .popleft()

往后挪k个:
.rotate(k) # k为正值为顺时针旋转,k为负值为逆时针旋转

可以使用 in

**线程安全**
以上都是原子操作,是GIL保护下的线程安全方法

② queue.Queue VS asyncio.Queue
共性:
都支持多生产者、多消费者的队列
基于collections.deque
都提供了Queue(FIFO队列),PriorityQueue(优先级队列),LiftQueue(LIFO队列)

区别:
queue.Queue 适用多线程场景
asyncio.Queue 适用协程场景下的通信,返回协程对象

|      | queue.Queue | asyncio.Queue |
| ---- | ---- | ---- | 
| 线程安全 | ✔︎    | ✘   | 
| 超时机制 | timeout | asyncio.wait.for() |
| qsize() | 预估的队列长度(可能被其它线程修改) | 准确的队列长度(单线程,不会被其它线程修改)|
| put()/set() | put(item, block=true,timeout=None) | put()返回协程对象,so无block/timeout。非阻塞方法:put_nowait   | 

③ multiprocessing.Queue
三种队列:Queue . simpleQueue . JoinableQueue

线程安全 & 进程安全
支持put/get 操作
底层结构是multiprocessing Pipe
不支持join()和task_done操作


# 10. 树
完全二叉树:中间没有空的,按顺序排列

平衡二叉树:左右子树深不超过1

二叉搜索树 = 二叉排序树:左 < 中 < 右

满二叉树:这样行满了的完全二叉树。深度为k,且有2^k-1个结点。

字典树:
① 根节点不包含字符
② 子 = 父 + 路径
③ 子节点各不相同
④ 是现实,会在节点中是一个flag,标记该节点处是否构成一个单词

# 11. 读写
❗️ 读时最好用逐行方式,否则容易撑爆内存。
# 逐行读
with open("your_file.txt", "r") as file:
    for line in file:
        print(line, end="")

# 一次性读
with open("your_file.txt", "r") as file:
    content = file.read()
print(content)

# 一次性写
file = open("your_file.txt", "w")
file.write("Hello, World!")
file.close()

# 逐行写
lines = ["Hello, World!\n", "Welcome to Python programming.\n"]
with open("your_file.txt", "w") as file:
	# file.writelines(lines)  # 此行为一次性写
    for line in lines:
        file.write(line)

# 12. 位运算
左移:<< | 相当于 ×2
    高位舍掉,低位补0
右移:>> | 相当于 ÷2
    有符号数,符号为随同移动。+,最高位补0;-,最高位补1。这个取决于编译系统。
>>>:无视符号的右移。


# 13. sort 和 operator
**py3的sort取消了cmp,可以用key**

itemgetter

from operator import itemgetter

sort(nums, key=itemgetter(0, 1))
= sort(nums, key=lambda x:(x[0], x[1]))


methodcaller

from operator import methodcaller

# 这里面count是内置函数,这条意思是按元素里'!'的个数排序
sort(messages, key=methodcaller('count', '!'))

cmp_to_key

sort(nums, key=cmp_to_key(func_compare))

func_compare(a, b) #如果a在b前面返回-1,后面返回1,相等返回0


# ord() 转ascii码
a的码:95;A的码:65

str转int 可使用:ord('c') - ord('0') # 'c'是当前想改的字母

# 14. 3.10字符串新特性
name = "Alice"
age = 25
s = f"{name} is {age} years old."
# 格式:f"{} xxx"