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

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

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

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

二、动态连通性问题

开启有效算法的流程

①建立数学问题模型

②找出解决问题的算法

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

④循环以上,直至满意

并查集问题

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的数,这种算法是很快速的。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 一些概念 数据结构就是研究数据的逻辑结构和物理结构以及它们之间相互关系,并对这种结构定义相应的运算,而且确保经过这...
    Winterfell_Z阅读 11,426评论 0 13
  • 前言 其实读完斯坦福的这本《互联网大规模数据挖掘》,让我感觉到,什么是人工智能?人工智能就是更高层次的数据挖掘。机...
    我偏笑_NSNirvana阅读 14,410评论 1 23
  • 1)这本书为什么值得看: Python语言描述,如果学的Python用这本书学数据结构更合适 2016年出版,内容...
    孙怀阔阅读 14,339评论 0 15
  • ·1· 和菜头说他每年都会呼吁大家拿起笔或者键盘写点什么东西,他说人们不去写作是背负着怕自己写不好的心理压力,和菜...
    郭睿之阅读 3,777评论 0 0
  • 吃过晚饭,躺在床上,信手翻开书,竟是徐志摩的《再别康桥》: “轻轻的我走了, 正如我...
    祁连山人阅读 3,456评论 0 3

友情链接更多精彩内容