8.23

a.特征向量和距离度量:

1.特征向量:特征向量包含足够信息来完美地进行分类的情况是非常罕见的。多数机器学习实际应用无法构造出具有完美识别能力的特征向量集合。

2.距离度量:

余弦相似度:体现的是两个向量在方向上的差别,而不是在大小上的差别,多用于高维向量。

欧氏距离:对应于p=2的闵可夫斯基距离。

曼哈顿距离:对应于p=1的闵可夫斯基距离。

b.kmeans聚类的理解:给用户打标签,比如以消费金额、消费频次、最近一次消费时间等等来评判,这个用户是忠实用户,还是流失用户,在推送或其他营销活动的时候,可以采取针对性的措施,比如文案、推广产品、活动时间等等。

编写需要的函数:

#计算欧氏距离
def calc_dist(x,y): #x、y为序列
dist=np.sum((x-y)**2)
return dist
#寻找样本与当前均值向量的距离最小的,并归为该类
def find_label(x,centroids): #x为单个样本,centroids为中心集合
min_dist=99999
label=[]
for j in range(k):
dist=calc_dist(x,centroids[j]) #计算与各中心的距离
if dist
label=j
min_dist=dist
return label
#计算新的中心
def cal_new_cent(data_labels):
new_cents=[] #初始化新的中心
label=data_labels['分类'].unique() #当前分类
for i in label:
newdata=data_labels[data_labels['分类']==i]
new_cent=[newdata['密度'].sum()/len(newdata),newdata['含糖率'].sum()/len(newdata),i] #新的中心和类别
new_cents.append(new_cent)
new_cents=pd.DataFrame(new_cents,columns=['密度','含糖率','分类']) #转换成Dataframe格式
return new_cents
开始聚类:
#开始聚类
data=np.array(ini_data[['密度','含糖率']]) #选择相关字段,并将数据转为array
ini_cent_loc=np.random.permutation(range(m))[:k] #生成0-29的3个随机数,即初始中心位置
cents=data[ini_cent_loc]
new_cents=pd.DataFrame([[0,0],[0,0],[0,0]],columns=['密度','含糖率'])
labels_=pd.DataFrame()
for i in range(999):
#如果新的均值向量与之前的均值向量相同,则停止迭代
cents_=pd.DataFrame(cents,columns=['密度','含糖率'])
if len(pd.concat([cents_,new_cents]).drop_duplicates())==k:
break
new_cents=cents_
#计算各样本与中心的距离并返回分类
labels=[]
for j in range(m):
label=find_label(data[j],cents)
labels.append(label)
data_labels=pd.concat([pd.DataFrame(data),pd.DataFrame(labels)],axis=1)
data_labels.columns=['密度','含糖率','分类']
labels_[i]=labels
#计算新的中心
cents=cal_new_cent(data_labels)
cents=np.array(cents[['密度','含糖率']])
聚类完成之后,看看每一代的聚类结果,可以用画图显示出来:
#画图
import matplotlib.pyplot as plt
#不同类别标上不同的颜色 b r k
for col in labels_.columns:
labels_.loc[:,col]=labels_[col].astype('str')
colors=labels_.replace(['0','1','2'],['b','r','k'])
for i in colors.columns:
plt.scatter(ini_data['密度'],ini_data['含糖率'],marker='*',c=colors[i])
plt.title(i)
plt.rcParams['font.sans-serif']=['Simhei'] #如果不加这个,中文坐标轴名称无法显示
plt.xlabel('密度')
plt.ylabel('含糖率')
 plt.show()
8.20

a.背包问题理解:对于这种背包问题,无法确保使用贪婪算法找出的解是最优解。0/1背包问题可以定义如下。每个物品都可以用一个值对表示;

背包能够容纳的物品总重量不能超过w;

长度为n的向量I表示一个可用的物品集合,向量中的每个元素都代表一个物品;

长度为n的向量V表示物品是否被窃贼带走。如果V[i] = 1,则物品I[i]被带走;如果V[i] = 0,则物品I[i]没有被带走。

b.图最优化问题理解:最短路径:对于两个节点n1和n2,找到边(源节点和目标节点)的最短序列,使得:第一条边的源节点是n1;

最后一条边的目标节点是n2;

对于序列中任意的边e1和e2,如果e2在序列中紧跟在e1后面,那么e2的源节点是e1的目标节点。最短加权路径:与最短路径非常相似,但它的目标不是找出连接两个节点的最短的边的序列。对于序列中边的权重,我们会定义某种函数(比如权重的和),并使这个函数的值最小化。Google Maps计算两点之间的最短驾驶距离时,就是在解决这种问题。

最大团:团是一个节点集合,集合中每两个节点之间都有一条边。①最大团是一个图中规模最大的团。

最小割:在一个图中,给定两个节点集合,割就是一个边的集合。去掉这组边之后,一个节点集合中的每个节点和另一个节点集合中的每个节点之间都不存在任何相连的路径。最小割就是这样一个最小的边的集合。

c.动态规划的理解:用MS[i]表示最大子数组的结束下标为i的情形,则对于i-1,有:

这样就有了一个子结构,对于初始情形,MS[1]=A[1].遍历i, 就能得到MS这个数组,其最大者即可最大子数组的和。

8.15

对于视频中的做错题目的总结:

import matplotlib.pyplot as plt
labels='frogs','hogs','dogs','logs'
sizes=15,20,45,10
colors='yellowgreen','gold','lightskyblue','lightcoral'
explode=0,0.1,0,0
plt.pie(sizes,explode=explode,labels=labels,colors=colors,autopct='%1.1f%%',shadow=True,startangle=50)
plt.axis('equal')
plt.show()
matplotlib图标正常显示中文
为了在图表中能够显示中文和负号等,需要下面一段设置:
import matplotlib.pyplot as plt
plt.rcParams['font.sas-serig']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
matplotlib inline和pylab inline
可以使用ipython --pylab打开ipython命名窗口。
%matplotlib inline #notebook模式下
%pylab inline #ipython模式下
8.13

a.显著性和P值的理解:

1.检验显著性:定义一个原假设和一个备择假设;理解待评价样本的统计学假设;计算相关的检验统计量;在原假设成立的情况下,推导出检验统计量的概率;确定这个概率是否足够小到可以使你放心地认为原假设是错的,即拒绝原假设。

2.P值:P-值的含义很容易被误解,它经常被认为是原假设为真的概率,但实际上不是。如果P-值很小,就意味着在原假设为真的情况下,得到特定样本的可能性很小。得到一个较小的P-值可能确实因为原假设是错的,也可能仅仅因为样本不能代表其来自的总体,也就是说,证据是误导人的。

b.条件概率和贝叶斯定理:

1.条件概率:条件概率定义:已知事件A发生的条件下,另一个事件B发生的概率成为条件概率,即为P(B|A)

如图A∩B那一部分的发生的概率即为P(AB),

P(AB)=发生A的概率*发生A之后发生B的概率=发生B的概率*发生B之后发生A的概率

即:

P(AB)=P(A)*P(B|A)=P(B)*P(A|B)

所以条件概率公式:

P(B|A)=P(AB)/P(A)=P(B)*P(A|B)/P(A)

2.贝叶斯定理:贝叶斯定理不同的是,他是已知一个事件在整个样本中发生的概率之后,然后求另一个时间发生的概率

比如在A时间发生的情况下,它属于Bi子样本空间的概率P(Bi|A),那么我们就可以根据条件概率公式来求

发生a事件概率*发生a事件且a时间发生在Bi子样本的概率=发生Bi的概率*发生Bi之后发生a的概率

即为:**P(Bi|A)*P(A)=P(Bi)*P(A|Bi)**
然后根据全概率公式:
所以:
P(Bi/A)=P(Bi)*P(A|Bi)/P(A)
把P(A)带入上面的式子,可得贝叶斯公式:
class Bayes(object):
def __init__(self):
self._container = dict()
def Set(self,hypothis,prob):
self._container[hypothis]=prob
def Mult(self,hypothis,prob):
old_prob = self._container[hypothis]
self._container[hypothis] = old_prob*prob
def Normalize(self):
count = 0
for hypothis in self._container.values():
count=count+hypothis
for hypothis,prob in self._container.items():
self._container[hypothis]=self._container[hypothis]/count
def Prob(self,hypothis):
Prob = self._container[hypothis]
return Prob
8.10
a.常见概率分布:
套路:
1.伯努利分布
例:抛硬币实验
抛硬币实验1次,正面朝上记作1,翻面朝上记作0。
#导入包
import scipy.stats as stats
import numpy as np
import matplotlib.pyplot as plt
#定义随机变量
X=np.arange(0,2,1)
#求各随机变量的概率
p=0.5
pList=stats.bernoulli.pmf(X,p)
#伯努利分布概率图
plt.plot(X,pList,marker='o',linestyle='None')
plt.vlines(X,0,pList)
plt.xlabel('随机变量:抛硬币1次')
plt.ylabel('概率')
plt.title('伯努利分布:p=%.2f'% p)
plt.show()
2.二项分布
例:5次抛硬币,正面朝上的次数。
#定义随机变量
n=5#抛硬币的次数
p=0.5#正面朝上的概率
X=np.arange(0,6,1)
#求各随机变量的概率
pList=stats.binom.pmf(X,n,p)
#绘图
plt.plot(X,pList,marker='o',linestyle='None')
plt.vlines(X,0,pList)
plt.xlabel('随机变量:抛硬币正面朝上次数')
plt.ylabel('概率')
plt.title('二项分布:n=%i,p=%.2f'% (n,p))
plt.show()
3.几何分布
例:首次表白成功的概率
#定义随机变量
k=5
p=0.6
X=np.arange(1,k+1,1)
#计算各随机变量的概率
pList=stats.geom.pmf(X,p)
#绘图
plt.plot(X,pList,marker='o',linestyle='None')
plt.vlines(X,0,pList)
plt.xlabel('随机变量:表白第k次才首次成功')
plt.ylabel('概率')
plt.title('几何分布:p=%.2f'% p)
plt.show()

4.泊松分布

例:已知一天内某路口平均每天发生2次事故。求该路口一天内发生4次事故的概率。

#定义随机变量
mu=2
k=4#次数,想知道一天内发生4次事故的概率,包含了发生0次,1次,2次,3次,4次
X=np.arange(0,k+1,1)
#计算概率
pList=stats.poisson.pmf(X,mu)
#绘图
plt.plot(X,pList,marker='o',linestyle='None')
plt.vlines(X,0,pList)
plt.xlabel('随机变量:某路口发生k次事故')
plt.ylabel('概率')
plt.title('泊松分布:平均值mu=%.2f'% mu)
plt.show()

b.中心极限定理和置信区间的理解:

1.中心极限定理:假设我们可以从一个总体中多次抽取样本,那么各个样本均值的差异性可以使用从同一总体中抽取的单个样本进行估计,这样做的根据就是中心极限定理。样本平均值约等于总体平均值;不管总体是什么分布,任意一个总体的样本平均值都会围绕在总体的平均值周围,并呈正态分布。

2.置信区间:如果从一个庞大的总体中抽取了一个(任意大小的)独立样本,那么总体均值的最好估计值就是样本的均值。对于某个规定的置信水平,置信区间宽度的估计要更复杂一些,它部分依赖于样本大小。

置信区间是指由样本统计量所构造的总体参数的估计区间。在统计学中,一个概率样本的置信区间(Confidence interval)是对这个样本的某个总体参数的区间估计。置信区间展现的是这个参数的真实值有一定概率落在测量结果的周围的程度。置信区间给出的是被测量参数的测量值的可信程度。

样本均值和总体均值是不同的。一般来说,我们想知道一个总体平均,但我们只能估算出一个样本的平均值。那么我们就希望使用样本均值来估计总体均值。我们使用置信区间这一指标,试图确定我们的样本均值是如何准确地估计总体均值的。

我们知道正态分布的常用的置信区间,如,95%置信水平的置信区间为距离两个标准差的区间范围。但有时候我们需要知道任一置信水平的区间,这时用python的scipy包可以实现:

首先导入相关的库:

import numpy as np
import pandas as pd
from scipy import stats
import matplotlib.pyplot as plt
%matplotlib inline
假设某支股票,平均收益为2.6,方差为3.1,试求下其相关概率和参数:
mean=2.6
std=3.1
prob=stats.norm.pdf(0,mean,std) #在0处概率密度值
pre=stats.norm.cdf(0,mean,std) #预测小于0的概率
interval=stats.norm.interval(0.96,mean,std) #96%置信水平的区间
print('随机变量在0处的概率密度是{:.3f},\n小于0的概率是{:.3f},\n96%的置信区间是{}'
可以知道,股票上涨的概率是1-0.201=0.799,有96%的把握认为跌涨幅在 -3.7~8.9 之间。

8.8

对于视频中的做错题目的总结:#简单的把随机步长累积起来并且可以可以使用一个数组表达式来计算。因此,我用 np.random 模块去200次硬币翻转,设置它们为1和-1,并计算累计和:

import matplotlib.pyplot as plt
import numpy as np
nsteps=200
draws=np.random.randint(0,2, size=nsteps)
steps=np.where(draws >0,1,-1)
walk=steps.cumsum()
fig=plt.figure()
ax=fig.add_subplot(111)
ax.plot(walk)
plt.show()一次模拟多个随机游走:
import matplotlib.pyplot as plt
import numpy as np
nwalks=5
nsteps=200
draws=np.random.randint(0,2, size=(nwalks, nsteps))# 0 or 1
steps=np.where(draws >0,1,-1)
walks=steps.cumsum(1)
fig=plt.figure()
ax=fig.add_subplot(111)
for i in range(nwalks):
ax.plot(walks[i])
plt.show()
8.6
对于视频中的做错题目的总结:
import matplotlib.pyplot as plt
labels='frogs','hogs','dogs','logs'
sizes=15,20,45,10
colors='yellowgreen','gold','lightskyblue','lightcoral'
explode=0,0.1,0,0
plt.pie(sizes,explode=explode,labels=labels,colors=colors,autopct='%1.1f%%',shadow=True,startangle=50)
plt.axis('equal')
plt.show()
线条相关属性标记设置:
axex: 设置坐标轴边界和表面的颜色、坐标刻度值大小和网格的显示
backend: 设置目标暑促TkAgg和GTKAgg
figure: 控制dpi、边界颜色、图形大小、和子区( subplot)设置
font: 字体集(font family)、字体大小和样式设置
grid: 设置网格颜色和线性
legend: 设置图例和其中的文本的显示
line: 设置线条(颜色、线型、宽度等)和标记
patch: 是填充2D空间的图形对象,如多边形和圆。控制线宽、颜色和抗锯齿设置等。
savefig: 可以对保存的图形进行单独设置。例如,设置渲染的文件的背景为白色。
verbose: 设置matplotlib在执行期间信息输出,如silent、helpful、debug和debug-annoying。
xticks和yticks: 为x,y轴的主刻度和次刻度设置颜色、大小、方向,以及标签大小。
8.4
Problem 4:
def jumpAndBackpedal(isMyNumber):
'''isMyNumber: Procedure that hides a secret number.It takes as a parameter one number and returns:* -1 if the number is less than the secret number* 0 if the number is equal to the secret number* 1 if the number is greater than the secret numberreturns: integer, the secret number'''
guess = 1
if isMyNumber(guess) == 0:
return guess
foundNumber = False
while not foundNumber and isMyNumber(guess):
sign = isMyNumber(guess)
if sign == -1:
guess *= 2
else:
guess -= 1
return guess
Problem 7:
class Frob(object):
def __init__(self, name):
self.name = name
self.before = None
self.after = None
def setBefore(self, before):
# example: a.setBefore(b) sets b before a
self.before = before
def setAfter(self, after):
# example: a.setAfter(b) sets b after a
self.after = after
def getBefore(self):
return self.before
def getAfter(self):
return self.after
def myName(self):
return self.name
def insert(atMe, newFrob):
"""atMe: a Frob that is part of a doubly linked listnewFrob: a Frob with no linksThis procedure appropriately inserts newFrob into the linked list that atMe is a part of."""
atMe_temp = atMe
if newFrob.name < atMe.name:
while True:
new = atMe.before
if new == None:
break
if new.name < newFrob.name:
break
atMe = atMe.before
if new == None:
newFrob.after = atMe
atMe.before = newFrob
else:
temp = new.after
new.after = newFrob
newFrob.before = new
newFrob.after = temp
temp.before = newFrob
else:
while True:
new = atMe.after
if new == None:
break
if new.name > newFrob.name:
break
atMe = atMe.after
if new == None:
atMe.after = newFrob
newFrob.before = atMe
else:
temp = new.before
temp.after = newFrob
newFrob.before = temp
new.before = newFrob
newFrob.after = new
def findFront(start):
"""start: a Frob that is part of a doubly linked listreturns: the Frob at the beginning of the linked list"""
# Your Code Here
if start.before == None:
return start
else:
return findFront(start.before)
week 6-8.1

a.理解面向对象编程(对比面向过程编程):从对象的意义上来说,所谓的对象,你可以理解为一只我们所创造出来的生物。这只生物天生自带本领,而我们也可以教会这个生物一些本领,让它帮我们做一些我们不想亲自动手去做的事。而这只生物的孩子将学会父亲的本领,并接受我们新交给它的本领。例如,我的同事小李就是一个生物,显然,这个复杂的生物可以为我做许多事情:比如给我钱。(只不过“给我钱”这个功能没有对我开放而已)而他的孩子自然也包含这个功能(只是也没有对我开放而已)。 从对象的本质上来说,你也可以将对象理解为一个函数集合体,它封装着多钟函数,并且我们可以有选择性的让哪个函数执行。而除了我们给予它的功能外,它还含有自身特带的函数(无需设定,但我们可以覆盖),比如“__main__”函数,多态性等。

b.理解继承和封装(主要的还是要自己多写):#继承:

class Car():
"""一次模拟汽车的简单尝试"""
def __init__(self,make,model,year):
"""初始化描述汽车的属性"""
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0
def get_descriptive_name(self):
"""返回整洁的描述性信息"""
long_name = str(self.year) + ' ' + self.make + ' ' +self.model
return long_name.title()
def read_odometer(self):
"""打印一条指出汽车里程的消息"""
print('This car has ' + str(self.odometer_reading) + ' miles on it.')
class Battery():
"""一次模拟电动汽车电瓶的简单尝试"""
def __init__(self,battery_size=70):
"""初始化电瓶的属性"""
self.battery_size = battery_size
def describe_battery(self):
"""打印一条描述电瓶容量的信息"""
print("This car has a " + str(self.battery_size) + "-kwh batter0y.")
class ElectricCar(Car):
"""电动汽车的独特之处"""
def __init__(self,make,model,year):
"""初始化父类的属性"""
super().__init__(make,model,year)
self.battery = Battery()
def fill_gas_tank(self):
"""电动车没有邮箱"""
print('This car does not need a gas tank')
my_tesla = ElectricCar('tesla','model s',2016)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()#封装:
import random
p=[0.85, 0.92, 0.99, 1]
A=[]
for i in range(100):
r= random.random()
if r < p[0]:
x=0
elif r < p[1]:
x=1
elif r < p[2]:
x=2
else:
x=3
A.append(x)
print (A)
#----------------------------------
p=[0.25, 0.5, 0.75, 0.95, 1]
A=[]
for i in range(100):
r= random.random()
if r < p[0]:
x=0
elif r < p[1]:
x=1
elif r < p[2]:
x=2
elif r < p[3]:
x=3
else:
x=4
A.append(x)
print (A)
import bisect
def main2(p, rs):
return [bisect.bisect(p, r) for r in rs]
c.对于视频中的做错题目的总结:#写一个函数将使用凯撒密码将明文转为密文:
def buildCoder(shift):
Caesar_cipher={}
lowercase='abcdefghijklmnopqrstuvwxyz'
uppercase=lowercase.upper()
for i in range(-26,0):
Caesar_cipher[uppercase[i]]=uppercase[i+shift]
Caesar_cipher[lowercase[i]]=lowercase[i+shift]
return Caesar_cipher
1.string.ascii_lowercase、string.ascii_uppercase
2.for i in range(-26,0)

3.python中a=b体现的是is关系,即不仅仅是赋值,而且是将b的唯一id赋予给a,a同b变为同样ID的存在,a即是b,b即是a。

4.\n换行。

5.join() 方法用于将序列中的元素以指定的字符连接生成一个新的字符串。str.join(sequence)

6.字典(Dictionary) get() 函数返回指定键的值,如果值不在字典中返回默认值。dict.get(key, default=None)

week 5-7.29

a.理解一些算法复杂度:

1.常数复杂度:渐近复杂度与输入规模无关。

2.对数复杂度:对于这种函数的复杂度来说,它的增长速度至少是某个输入的对数。

3.线性复杂度:很多处理列表或其他类型序列的程序具有线性复杂度,因为它们对序列中的每个元素都进行常数(大于0)次处理。

4.对数线性复杂度:这种复杂度比前面几种复杂度稍微复杂一点,它是两个项的乘积,每个项都依赖于输入的规模。

5.多项式复杂度:最常见的多项式算法复杂度是平方复杂度,也就是说,算法复杂度按照输入规模的平方增长。

6.指数复杂度:要想彻底解决这些问题,所需的时间要随输入规模的指数而增长。

b.搜索算法和排序算法练习:#为什么在第二个递归调用中,代码使用的不是mid,而是mid + 1?

mid已经比较过了,所以不对。#冒泡排序:

def bubbleSort(alist):
n = len(alist)
exchange = False
for i in range(n-1, 0, -1):
for j in range(0, i):
if alist[j] > alist[j+1]:
alist[j], alist[j+1] = alist[j+1], alist[j]
exchange = True
# 如果发现整个排序过程中没有交换,提前结束
if not exchange:
break
return alist#选择排序
def selectionSort(alist):
n = len(alist)
for i in range(n - 1):
# 寻找[i,n]区间里的最小值
min_index = i
for j in range(i+1, n):
if alist[j] < alist[min_index]:
min_index = j
alist[i], alist[min_index] = alist[min_index], alist[i]
return alist#插入排序
def insertionSort(blist):
n = len(blist)
for i in range(1, n):
# 寻找a[i]合适的插入位置
temp = blist[i]
for j in range(i, 0, -1):
if (temp < blist[j-1]):
blist[j] = blist[j-1]
else:
break
blist[j-1] = temp
return blist#希尔排序
def shellSort(alist):
n = len(alist)
gap = n // 2
while gap > 0:
for i in range(gap):
gapInsetionSort(alist, i, gap)
gap = gap // 2
return alist
# # start子数列开始的起始位置, gap表示间隔
def gapInsetionSort(alist,startpos,gap):
#希尔排序的辅助函数
for i in range(startpos+gap,len(alist),gap):
position=i
currentvalue=alist[i]
while position>startpos and alist[position-gap]>currentvalue:
alist[position]=alist[position-gap]
position=position-gap
alist[position]=currentvalue#归并排序:自顶向下(递归法)方法实现
def mergeSort(alist):
n = len(alist)
__mergeSort(alist, 0, n-1)
return alist
# 对arr[l...r]的范围进行排序
def __mergeSort(alist, start, end):
#当数列的大小比较小的时候,数列近乎有序的概率较大
if (end-start <= 15):
insertionSortHelp(alist, start, end)
return
if start >= end:
return
# 存在风险,start+end可能越界
mid = (start + end) // 2
# mid = start + (end - start) // 2
__mergeSort(alist, start, mid)
__mergeSort(alist, mid + 1, end)
#优化
if alist[mid] > alist[mid+1]:
merge(alist, start, mid, end)
# 合并有序数列alist[start....mid] 和 alist[mid+1...end],使之成为有序数列
def merge(alist, start, mid, end):
# 复制一份
blist = alist[start:end+1]
l = start
k = mid + 1
pos = start
while pos <= end:
if (l > mid):
alist[pos] = blist[k-start]
k += 1
elif (k > end):
alist[pos] = blist[l-start]
l += 1
elif blist[l-start] <= blist[k-start]:
alist[pos] = blist[l-start]
l += 1
else:
alist[pos] = blist[k-start]
k += 1
pos += 1
def insertionSortHelp(alist,l, r):
for i in range(l+1,r+1):
currentvalue=alist[i]
position=i
while alist[position-1]>currentvalue and position>l:
alist[position]=alist[position-1]
position=position-1
alist[position]=currentvalue
return alist#归并排序:自底向上(非递归法)方法
def mergeBU(alist):
n = len(alist)
#表示归并的大小
size = 1
while size <= n:
for i in range(0, n-size, size+size):
merge(alist, i, i+size-1, min(i+size+size-1, n-1))
size += size
return alist
# 合并有序数列alist[start....mid] 和 alist[mid+1...end],使之成为有序数列
def merge(alist, start, mid, end):
# 复制一份
blist = alist[start:end+1]
l = start
k = mid + 1
pos = start
while pos <= end:
if (l > mid):
alist[pos] = blist[k-start]
k += 1
elif (k > end):
alist[pos] = blist[l-start]
l += 1
elif blist[l-start] <= blist[k-start]:
alist[pos] = blist[l-start]
l += 1
else:
alist[pos] = blist[k-start]
k += 1
pos += 1#快速排序:
def __quickSort(alist, l, r):
#当数列的大小比较小的时候,数列近乎有序的概率较大
# if (r - l <= 15):
# insertionSortHelp(alist, l, r)
# return
if l >= r:
return
# p = partition(alist, l, r)
p = partitionQS(alist, l, r)
__quickSort(alist, l, p-1)
__quickSort(alist, p+1, r)
# 在alist[l...r]中寻找j,使得alist[l...j] <= alist[l], alist[j+1...r] >alist[l]
def partition(alist, l, r):
pos = randint(l, r)
alist[pos], alist[l] = alist[l], alist[pos]
v = alist[l]
# v = alist[l]
j = l
i = l + 1
while i <= r:
if alist[i] <= v:
alist[j+1],alist[i] = alist[i],alist[j+1]
j += 1
i += 1
alist[l], alist[j] = alist[j], alist[l]
return j
1.pass:空语句 do nothing。

2.for循环将值匹配也算作一步操作。

3.可以说合并排序是比较复杂的排序,特别是对于不了解分治法基本思想的同学来说可能难以理解。总时间=分解时间+解决问题时间+合并时间。分解时间就是把一个待排序序列分解成两序列,时间为一常数,时间复杂度o(1).解决问题时间是两个递归式,把一个规模为n的问题分成两个规模分别为n/2的子问题,时间为2T(n/2).合并时间复杂度为o(n)。总时间T(n)=2T(n/2)+o(n).这个递归式可以用递归树来解,其解是o(nlogn).此外在最坏、最佳、平均情况下归并排序时间复杂度均为o(nlogn).从合并过程中可以看出合并排序稳定。

用递归树的方法解递归式T(n)=2T(n/2)+o(n):假设解决最后的子问题用时为常数c,则对于n个待排序记录来说整个问题的规模为cn。

从这个递归树可以看出,第一层时间代价为cn,第二层时间代价为cn/2+cn/2=cn.....每一层代价都是cn,总共有logn+1层。所以总的时间代价为cn*(logn+1).时间复杂度是o(nlogn).

4.散列技术是在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使得每个关键字key对应一个存储位置f(key)。

査找时,根据这个确定的对应关系找到给定值key的映射f(key),若査找集合中存在这个记录,则必定在f(key)的位置上。

这里我们把这种对应关系f称为散列函数,又称为哈希(Hash)函数。按这个思想,采用散列技术将记录存储在一块连续的存储空间中,这块连续存储空间称为散列表或哈希表(Hashtable)。那么关键字对应的记录存储位置我们称为散列地址。