2019-02-23 普林斯顿大学 数据结构课程笔记

2019-02-23  本文已影响8人  七月那个阿瓜呀

一、 数据结构:基本数据结构:栈、队列、背包、优先队列

排序:排序、归并排序、堆排序、基数排序

查找:二叉查找树、红黑树、哈希表(散列表)

二、动态连通性问题

开启有效算法的流程

①建立数学问题模型

②找出解决问题的算法

③若出现问题(算法不够快,或者存储空间不足),找到问题的源头,提出新算法

④循环以上,直至满意

并查集问题

image 1

有N个对象,编号0~N-1,利用 find 判断两元素是否通过已有路径连通(union),上图中,0,1,2,5,6,7中任两元素连通,3,4,8,9任两元素连通,但是这两个集合之间元素并不是连通的。如若集合元素很多,不能很快判断元素相连情况,目前问题是:两元素间能否找到一条路径?使用高效的并查集。

image 2

1. 分析connected 性质:

①对称性(p连接到q 等价于q连接到p )

②传递性(p连接到q,q连接到r 等价于p连接到r)

2. 建立连通分量概念

image 3

性质:①连通分量中任意两对象是相连的

②连通分量中对象不与连通分量之外的对象相连

3. 命令

Find 查找 :检查两个对象是否在相同的元素中

Union 合并:将包含两个对象的分量替换为其并集

4. 编程思想Java

创建类UF,包含两个命令Find和Union,需要对象的数量

public static void main(String[] args)
{
int N = StdIn.readInt(); #读取数据
UF uf = new UF(N)
while (!StdIn.isEmpty())
{
int p = StdIn.readInt(); #客户端从输入读取两个整数
int q = StdIn.readInt();
if (!uf.connected(p,q)) #如果没有相连,则将其相连,并输出
{
uf.union(p,q);
StdOut.println(p + " " + q);
}
}
}

2019-02-03

观看普林斯顿大学数据结构课程至 2-3 快速合并 Quick-Union

  1. 快速查找 Quick-Find(贪心算法)

① 查找:p和q是否有相同的id,相同id代表p和q在相同的连通分量中(即连接)

② 合并:要合并两个给定对象的两个分量,要将所有与给定对象之一相同id对应的项变为另一给定对象对应的项,将所有和id[p]相同ID值的数组成员的值,全部转换为id[q] 的ID值。

image

代码,原文是Java,我改成了Python

class  QuickFind:

def  QuickFind(N):

id = []

for i in  range(N):

id.append(i) #对每一个对象署上id,构造器

def  shifou_connected(p,q):

return  id[p] == id[q] #判断p和q是否连接,即两者id是否相同

def  Union(p,q):

pid = id[p]

qid = id[q]

for i in  range(id.length):

if (id[i == pid]):

id[i] = qid #所有和id[p]相同ID值的数组成员的值,全部转换为id[q] 的ID值

效率问题:对 N 个元素执行 N 次 union 操作,数组访问次数就是 N^2 次,当N变得很大的时候,效率会很差。下面讲到的快速合并会解决这个问题。

  1. 快速合并 Quick-Union

数据结构同快速查找,连通的元素按照树的结构相连,每个树都有根节点

①查找: 看p和q的根节点是否相同

②合并: 将p的根节点移到q的根节点下

image

代码,Python

class  QuickUnion:

def  QuickUnion(N):

id = []

for i in  range(N):

id.append(i) #对每一个对象署上id

def  root(i): # 根节点

while(i != id[i]):

i = id[i]

return i

def  shifou_connected(p,q):

return root[p] == root[q] #判断p和q是否连接,即两者id是否相同

def  Union(p,q):

i = root(p)

j = root(q)

id[i] = j # 将p的根节点移到q的根节点下

效率问题:当树很瘦长时,查找的时间会长,找一片“叶子”要回溯整棵树。花费N次时间查找(快速查找中只话1次时间),下面看改进。

2019-02-09

改进1:带权快速合并算法

在快速合并的基础上,对树进行加权操作。

①查找: 看p和q的根节点是否相同

②合并: 检查树的大小,将小树的根节点连接到大树的根节点上,主要做法,改变id记录值,改变数组的大小

python 代码

def  shifou_connected(p,q):

return root[p] == root[q] # 判断p和q是否连接,即两者id是否相同

def  Union(p,q):

i = root(p)

j = root(q)

if (i == j):

return

if (sz[i]<sz[j]):

id[i] = j # 将树小的根节点安置在树大的根节点下

sz[j] += sz[i] # 更新sz矩阵

效率问题:

任意节点深度<=log2(N)

证明:

  1. 只有当T2的尺寸>=T1的尺寸的时候,T1才会加到T2的根节点下,此时T1里面的x的深度才会增加。同时,T1和T2合并为一个集合,这个集合的尺寸至少是T1的2倍,在这种情况下,我们粗略估计,x的深度每增加1,则x所在集合的尺寸就会变为原来的2倍(粗略估计),但是,整个集合的元素个数为N,也就是,x所在集合的尺寸最大只能为N,从刚开始x所在集合的尺寸为1,到x所在集合的尺寸为N,需要翻倍的次数为log2(N),也就是需要翻倍log2(N)次,而假设每次翻倍深度都会增加1,所以x的深度就是log2(N)。

表1. 三种算法效率比较

image

改进2:回溯一次路径找到根节点,再回溯一次将树展平

python

def  root(i): # 根节点

while(i != id[i]):

{

id[i] = id[id[i]]] # 只加这一行

i = id[i]

}

return i

image ​
效率
N个对象,M个查找与合并操作,需要访问数组最多c(N+Mlg(N))次,实际生活中,lg(N)可以认为是小于5的数,这种算法是很快速的。
上一篇下一篇

猜你喜欢

热点阅读