参考:《用python解决数据结构和算法》
O(f(n))提供了计算过程中实际步数的近似值。函数 f(n)是原始函数 T(n)中主导部分的简化表示。【T(N)是赋值语句数量】
T(n) = 5n²+27n+1005 当 n 越来越大时,我们就可以忽略其余项,只关注用 5n²来代表 T(n)的近似值了。同样,系数 5 的作用也会越来
越小,也可以忽略。我们就会说函数 T(n)的数量级 f(n) = n²,即 O(n²)
修改列表:这个“append”操作是 O(1)。然而,串联运算符+是 O(k),这里 k是指正在被连接的列表的大小
当 pop 操作每次从列表的最后一位删除元素时复杂度为 O(1),而将列表的第一个元素或中间任意一个位置的元素删除时,复杂度则为 O(n).这种执行方式会让 index 索引
操作的复杂度降为 O(1)
字典:条目的访问和赋值都是 O(1)的时间复杂度。字典的另一个重要的操作是所谓的“包含”。检查一个键是否存在于字典中也只需 O(1)的时间。
动态规划问题中:可以通过记录中间出现过的结果来减少工作量
================
栈: 添加项和移除项都发生在同一“端”。这一端通常被称为“顶”。另一端的顶部被称为“底”。
队列: 新元素的加入在队列的一端,这一端叫做“队尾”(rear),已有元素的移除发生在队列的另一端,叫做“队首”(front)
双端队列 : 元素可以在队首插入或删除,也可以在队尾插入或删除
链表的节点:
考虑一个有 n 个节点的链表, isEmpty 方法复杂度是 O(1),因为它只需要检查链表的头指针是否为 None。对于方法 size,
则总需要 n 个步骤,因为除了遍历整个链表以外,没有办法知道链表的节点数。因此, size 方法的复杂度是 O(n)。
无序列表的 add 方法的复杂度是 O(1),因为我们永远只需要在链表的头部简单地添加一个新的节点。
search、 remove 和在有序列表中的 add 方法,需要遍历。尽管在平均情况下,它们可能只需要遍历一半的节点,但这些方法的复杂度都是 O(n),
=============
二分法:结束于一个只有一项的列表 ,n/2^i=1 ,解得i=log(n) 因此,二分搜索的复杂度是O(log(n))。
散列: 它仅能在每一个数据项在散列表中占有不同的槽的情况下才能正常运作
散列函数:
1 折叠法创建散列函数的基本步骤是:首先将数据分成相同长度的片段(最后一个片段长度可能不等)。接着将这些片段相加,再求余得到其散列值。例如,如果我们有一串电话号码436-
555-4601,我们可以两个一组将这个号码分成5段(43,64,55,46,01)。然后相加得到。如果我们假设散列表有11个槽,我们就需要将和进行求余。 219%11 = 10
2 平方取中法。我们首先将数据取平方,然后取平方数的某一部分。例如数据项是44,我们首先计算。接着取出中间的两位数93, 然后再进行求余运算
解决冲突: 1) 再散列:rehash(pos)=(pos+skip)%sizeoftable 2)允许每一个槽都能填充一串而不是一个数据
冒泡排序:如果在整个排序过程中没有交换,我们就可断定列表已经排好。因此可改良冒泡排序
归并排序函数需要额外的空间来存放被拆分出来的两个部分。如果列表很大的话,这额外空间将是一个很重要的因素,可能使得这种排序被运用在大数据集合时出现错误。
快速排序用了和归并排序一样分而治之的方法来获得同样的优势,但同时不需要使用额外的存储空间。
分区过程由设置两个位置标记开始——让我们叫它们左标记和右标记——在列表的第一项和最后一项。
分区过程的目标是把相对于中值在错误的一边的数据放到正确的一边,同时找到分割点。
二分查找
def er_fen(data,item):
first = 0 # 第一个元素的坐标
last = len(data)-1 #最后一个元素的坐标
while first <= last: #等于也可以
mid = (first+last)//2
if data[mid] == item:
return True
elif data[mid] > item:
last = mid-1
else:
first = mid+1
return False
动态规划:找零
change = 17
min_count = [0]*(change+1)
used_value = [0]*(change+1)
value_lst = [1,5,10,21,25]
def change_money(value_lst, change, min_count, used_value):
for son_coin in range(change+1):
min_num = son_coin
used_coin = 1
for coin in [c for c in value_lst if c <= son_coin]:
new_min = min_count[son_coin - coin] + 1
if new_min < min_num:
min_num = new_min
used_coin = coin
min_count[son_coin] = min_num
used_value[son_coin] = used_coin
递归:任意进制转换
def to_string(num, base):
cover2str ='0123456789ABCDEF'
if num < base:
return cover2str[num]
else:
return to_string(num//base, base) + cover2str[num%base]
二分查找的时间复杂度是log2(n)
冒泡排序
def mao_pao(data):
for i in range(len(data)-1,0,-1): #每次比较到哪个位置
for j in range(i):
if data[j] > data[j+1]:
data[j], data[j+1] = data[j+1], data[j]
选择排序
def xuan_ze(data):
for i in range(len(data)-1,0,-1): #每次比较到哪个位置
max_pos = 0
for j in range(1,i+1):
if data[max_pos] < data[j]:
max_pos = j
data[max_pos], data[i] = data[i], data[max_pos]
插入排序
def cha_ru(data):
for i in range(1,len(data)):
cur_value = data[i]
pos = i
while pos >0 and cur_value < data[pos-1]:
data[pos] = data[pos-1]
pos = pos - 1
data[pos] = cur_value
快速排序
def kuai_pai(data,left_pos,right_pos):
if left_pos < right_pos:
mid_pos = partion(data,left_pos,right_pos)
kuai_pai(data ,left_pos, mid_pos-1)
kuai_pai(data , mid_pos + 1, right_pos)
def partion(data,left_pos,right_pos):
cur_value = data[left_pos]
flag_pos = left_pos
while True:
while left_pos <= right_pos and data[left_pos] <= cur_value:
left_pos = left_pos + 1
while left_pos <= right_pos and data[right_pos] >= cur_value:
right_pos = right_pos - 1
if left_pos > right_pos:
data[flag_pos] = data[right_pos]
data[right_pos] = cur_value
return right_pos
else:
data[left_pos] ,data[right_pos] = data[right_pos], data[left_pos]
骑士周游(深度搜索)
class NODE(object):
def __init__(self, id):
self.id = id
self.neiber = {}
self.parent = None
self.color = 'white'
self.distance = sys.maxsize
def add_neiber(self, node, weight=0):
self.neiber[node] = weight
def get_neiber(self):
return self.neiber.keys()
class GRAPH(object):
def __init__(self):
self.size = 0
self.members = {}
def add_member(self, id):
self.size = self.size +1
if id not in self.members:
node = NODE(id)
self.members[id] = node
def get_member(self, id):
return self.members.get(id, None)
def add_edge(self,id1,id2,weight=0):
if id1 not in self.members:
self.members[id1] = NODE(id1)
self.size = self.size +1
if id2 not in self.members:
self.members[id2] = NODE(id2)
self.size = self.size +1
self.members[id1].add_neiber(self.members[id2], weight)
def gen_id(x,y,size):
return x*size + y
def valide(new_x, new_y, size):
if 0<=new_x < size and 0<= new_y< size:
return True
else:
return False
def lin_ju(x,y,size):
step = [
(1,2),(-1,2),(1,-2),(-1,-2),
(2,1),(-2,1),(2,-1),(-2,-1)
]
ret = []
for s in step:
new_x = x+s[0]
new_y = y+s[1]
if valide(new_x, new_y, size):
ret.append((new_x, new_y))
return ret
def build(size):
g = GRAPH()
for i in range(size):
for j in range(size):
id = gen_id(i,j,size)
#node = NODE(id)
neibors = lin_ju(i,j,size)
for n in neibors:
n_id = gen_id(n[0],n[1], size)
print(n_id, '***')
g.add_edge(id,n_id)
#node.add_neiber(NODE(n_id))
return g
def zhou_you(limit,path,u,n):
u.color = 'gray'
path.append(u)
if n == limit:
return True
done =False
for nei in u.get_neiber():
if nei.color =='white':
done = zhou_you(limit,path,nei,n+1)
if done:
return True
u.color='white'
path.pop()
return done
g = build(5)
node = g.get_member(12)
path = []
zhou_you(25,path,node,1)
for p in path:
print(p.id)
优先队列
import heapq
class YouXianQueue(object):
def __init__(self):
self._lst=[]
self._index=0
def push(self,item,prime):
heapq.heappush(self._lst,(prime,self._index,item))
self._index +=1
def show(self):
print(self._lst)
def __contains__(self, item):
temp=[data[2] for data in self._lst]
return item in temp
def len(self):
return len(self._lst)
def change(self,item,priority):
try:
temp=None
for num,i in enumerate(self._lst):
if i[-1] is item:
temp=num
break
temp_v=self._lst[temp]
del self._lst[temp]
heapq.heappush(self._lst,(priority,temp_v[1],temp_v[2]))
except Exception as ex:
print(ex)
def pop(self):
return heapq.heappop(self._lst)[-1]
# 最短路径
class NODE(object):
def __init__(self,value):
self._value=value
self.connections={}
self._parent=None
self._dis=sys.maxsize
def getWeight(self,item):
return self.connections.get(item,0)
def addNeibor(self,item,weight=1):
self.connections[item]=weight
@property
def value(self):
return self._value
@value.setter
def value(self,value):
self._value=value
@property
def parent(self):
return self._parent
@parent.setter
def parent(self,item):
self._parent=item
def getNeibor(self):
return self.connections.keys()
def setParent(self,item):
self.parent=item
@property
def dis(self):
return self._dis
@dis.setter
def dis(self,value):
self._dis=value
class GRAPH(object):
def __init__(self):
self.sons={}
self.size=0
def addSon(self,value):
self.sons[value]=NODE(value)
self.size +=1
def getSon(self,value):
return self.sons.get(value,None)
def getall(self):
return self.sons.values()
def addEdge(self,value1,value2,weight=1):
if value1 not in self.sons:
self.addSon(value1)
if value2 not in self.sons:
self.addSon(value2)
self.sons[value1].addNeibor(self.sons[value2],weight)
def genData(datas):
g=GRAPH()
for data in datas:
g.addEdge(data[0],data[1],data[2])
return g
def minPath(g,start):
path=YouXianQueue()
first=g.getSon(start)
first.dis=0
first.parent=None
for son in g.getall():
path.push(son,son.dis)
while path.len()>0:
current=path.pop()
for son in current.getNeibor():
newdis=current.dis+ current.getWeight(son)
if son.dis > newdis:
son.dis=newdis
son.parent=current
path.change(son,newdis)
def showPah(g,dest):
item=g.getSon(dest)
print(item.value)
while item.parent:
item=item.parent
print(item.value)
def main():
datas=[('u','v',2),('u','w',5),('u','x',1),('v','u',2),('v','w',3),('v','x',2),
('w','v',3),('w','u',5),('w','x',3),('w','y',1),('w','z',5),('z','w',5),('z','y',1),
('y','z',1),('y','w',1),('y','x',1),('x','y',1),('x','w',3),('x','v',2),('x','u',1)]
g=genData(datas)
minPath(g,"u")
showPah(g,'w')
# 词梯
def genCiTi(datas):
bkt={}
g=GRAPH()
for data in datas:
for i in range(len(data)):
flag=data[:i]+'_'+data[i+1:]
bkt.setdefault(flag,[]).append(data)
for _,data in bkt.items():
for word1 in data:
for word2 in data:
if word1 != word2:
g.addEdge(word1,word2,1)
return g
def main_citi():
datas=['fool', 'foul', 'foil', 'fail', 'poll', 'pall', 'pole', 'fall', 'page', 'sage', 'sale', 'pale', 'pope', 'cool', 'pool']
g=genCiTi(datas)
minPath(g,"fool")
showPah(g,'sage')
==============《大话数据结构》
逻辑结构:集合(元素属于同一集合),线性结构(一对一),树形结构(一对多),图(多对多)
物理结构:顺序存储和链式存储
算法是解决特定问题求解步骤的描述
: