算法导论

【算法导论】第4章 分而治之 (3)

谁都会走 提交于 2020-01-17 00:19:54
Introduction to Algorithms - Third Edition Part I. Foundations Chapter 4. Divide-and-Conquer ★ \bigstar ★ 4.6 主定理的证明 4.6.1 取正合幂时的证明 假设 n n n 是 b > 1 b>1 b > 1 的正合幂,其中 b b b 不必是整数,分析主方法中的递归式 (4.20) T ( n ) = a T ( n / b ) + f ( n ) T(n) = aT(n/b) + f(n) T ( n ) = a T ( n / b ) + f ( n ) 。 将分析分成 3 个引理来说明。 第1个引理,将求解主递归式的问题,归约为对包含总和的表达式求值的问题。 第2个引理,确定这个总和的界限。 第3个引理,将前两个结合一起,证明:在 n n n 是 b b b 的正合幂的情况下,主定理成立。 引理 4.2 设 a ≥ 1 a \ge 1 a ≥ 1 和 b > 1 b > 1 b > 1 是常数,设 f ( n ) f(n) f ( n ) 是定义在 b b b 的正合幂上的非负函数。在 b b b 的正合幂上定义 T ( n ) T(n) T ( n ) : T ( n ) = { Θ ( 1 ) if n = 1 a T ( n / b ) + f ( n ) if

麻省理工公开课算法导论(二):Insertion Sort and Merge Sort

放肆的年华 提交于 2020-01-16 07:13:22
文章目录 Introduction Insertion Sort and Merge Sort Why Sorting? Insertion Sort Binary Insertion Sort Merge Sort Summary Introduction 本篇来自于笔者学习MIT的公开课算法导论的学习笔记,仅仅是我个人接受课程教育后,进行的学习笔记,可能理解并不到位,仅供参考。 课程视频地址: Lecture 3: Insertion Sort and Merge Sort Insertion Sort and Merge Sort Why Sorting? 首先让我们思考一个问题,为什么我们需要排序? 在日常生活中的很多场景,例如管理MP3的歌曲列表、维护手机通讯录等等,针对这些场景,排序可以将问题变得更加的简单。 Insertion Sort 接下来我们介绍一种排序算法,叫做 插入排序(Insertion Sort) 。 假定给定有序数组A[1…j-1],我们希望将元素A[j]插入有序数组数组中,如下图: 当然,这是非常理想的情况,我们只需要遍历数组,通过前后元素大小比较,找到A[j]应该插入到的位置,在该种情况下,时间复杂度为 O(n) 。 但是情况往往不可能会这么好,假定给定数组A[1…j-1],其中元素是乱序,我们希望将元素A[j]插入有序数组数组中,如下图:

专栏简介

落花浮王杯 提交于 2020-01-13 07:16:17
前言 本专栏创建于2020年1月9日,在刚刚过去的2019年里,我觉得我做出的最大改变就是开始尝试用文字来记录自己的学习历程了,虽然很多时候记录还是一团糟,但相比于曾经现学现忘的我来讲,也可算是一个不小的进步了。在新的一年里,我决定开始尝试用博客来记录一些所学所想。 本专栏主要用来记录MIT的《算法导论》一课中的主要内容。《算法导论》课其实早在一个来月前就已经看到过第五课了,然而恰逢期(无)末(心)备(学)考(习),所以也就把这事给搁置了。现如今,新年伊始,小伙伴们都开启了新年计划了,那我也是时候把旧债还一还了(o(╥﹏╥)o)。当然,出于鄙人比较菜,若有复述有误的地方,还望各位看官老爷们不吝指正。最后为大伙附上原课程的链接 《算法导论》 。 来源: CSDN 作者: L_Mingmin 链接: https://blog.csdn.net/L_Mingmin/article/details/103914954

【算法导论】第4章 分而治之 (1)

蹲街弑〆低调 提交于 2020-01-11 22:49:19
Introduction to Algorithms - Third Edition Part I. Foundations Chapter 4. Divide-and-Conquer 当子问题足够大以进行递归求解时,称其为 递归情况 (recursive case)。一旦子问题变得很小,以至不再递归的程度,就说递归“结束(bottom out)”了,已经回到了 基本情况 (base case)。 递归式 递归式与分治法范式提供了一种自然的方式来表征分治算法的运行时间。 递归式 (recurrence)是一组等式或不等式,其描述的函数是用在更小的输入下该函数的值来定义的。 本章介绍三种解递归式的方法,即找出解的渐近 Θ \Theta Θ 或 O O O 界的方法。 代换法 (substitution method):先猜测一个界,再使用数学归纳法证明猜测的正确性。 递归树方法 (recursion-tree method):将递归式转化为树,树中的结点代表不同递归层次付出的代价。使用边界求和的技巧来解递归。 主方法 (master method):给出递归形式 T ( n ) = a T ( n / b ) + f ( n ) T(n) = aT(n/b) + f(n) T ( n ) = a T ( n / b ) + f ( n )       (4.2) 的界,其中 a ≥

算法导论笔记(一):复杂度,分治,随机

做~自己de王妃 提交于 2020-01-07 18:59:15
示例与概念 插入排序 归并排序 最坏情况分析与平均情况分析 函数增长的渐进记号 (O(n)) 表示函数增长的上界。即,花费时间不会高于线性增长。 (Theta(n)) 同时表示上界和下界。即,花费时间一定是这个线性增长的。 (Omega(n)) 表示增长的下界。 (o(n)) 表示不渐进紧确的上界。如, (2n =O(n^2)) , (n^2=O(n^2)) , (2n=O(n^2)) ,但 (n^2neq o(n^2)) (omega(n)) 与 (o(n)) 类似,表示不紧确的下界。 此外,常用 (T(n)) 表示所需的实际时间的函数。 分析分治算法,以归并排序为例 归并排序最坏运行时间的递归式: [ T(n)=begin{cases}Theta(1)&text{若} n=1,\ 2T(n/2)+Theta(n)&text{若} n>1. end{cases} ] 除使用主定理外,还可以这样理解递归式的值:将递归过程看做一个二叉树。递归调用中的每一层的总代价均为 (cn) ,其中 (c) 为常数。而二叉树的层数应为 (log_2n+1) 。故,整个算法的代价期望为 (Theta(nlog_2n)) 。 分治法 分治法求最大和的子数组 分解。将数组划分为两个子数组。此时,只存在三种子数组: 全部位于中点左侧的子数组 全部位于中点右侧的子数组 跨越中点的子数组 解决

算法导论——最小生成树:Kruskal算法(利用了并查集)

醉酒当歌 提交于 2020-01-07 15:11:19
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> package org.loda.graph; import org.loda.structure.MinQ; import org.loda.structure.Queue; import org.loda.util.In; /** * * @ClassName: KruskalMST * @Description:Kruskal最小生成树算法 * @author minjun * @date 2015年5月25日 下午10:50:01 * */ public class KruskalMST { private Queue<Edge> mst; private double weight; public KruskalMST(WeightGraph g){ int v=g.v(); mst=new Queue<Edge>(); MinQ<Edge> q=new MinQ<Edge>(); UF uf=new UF(v); //将所有边添加到优先队列中 for(Edge edge:g.edges()){ q.offer(edge); } while(!q.isEmpty()){ Edge edge=q.poll(); int a=edge.oneSide(); int b=edge.otherSide(a);

算法导论6-3习题解答(Young氏矩阵)

荒凉一梦 提交于 2020-01-06 01:09:17
CLRS 6-3 :Young氏矩阵( 杨氏矩阵) 解答: (a)2 4 9 12 3 5 14 Max 8 16 Max Max Max Max Max Max (b)Y[1, 1]为Max的话,那么按照Young氏矩阵定义,矩阵中其他数值必然大于等于它,所以Y为空。 若Y[m, n] < Max的话,由其他元素都小于等于Y[m, n]可知此矩阵是满的。 (c)算法思想: 1)A[0][0]必然是最小值,将其取出,然后将矩阵的最后一个元素A[m-1[n-1]补到第一位来,并将A[m-1[n-1]设置为Max 2)将A[0][0]与A[0][1]和A[1][0]二者之间的最小值进行交换, 3)若交换的是A[0][1],则在下一步对m*(n-1)矩阵的第一个元素重复2, 若交换的是A[1][0],则在下一步对(m-1)*n矩阵的第一个元素重复2 总之每次总是将第一个元素与其周边元素进行比较而已。 #include < iostream > using namespace std; // 假设MAX为无穷大 #define MAX 1000000 int extract_min( int ** a, int m, int n); void young_matrixify( int ** a, int i, int j, int m, int n); int main() { int a

算法导论笔记(一):复杂度,分治,随机

落爺英雄遲暮 提交于 2020-01-04 00:10:49
示例与概念 插入排序 归并排序 最坏情况分析与平均情况分析 函数增长的渐进记号 (O(n)) 表示函数增长的上界。即,花费时间不会高于线性增长。 (Theta(n)) 同时表示上界和下界。即,花费时间一定是这个线性增长的。 (Omega(n)) 表示增长的下界。 (o(n)) 表示不渐进紧确的上界。如, (2n =O(n^2)) , (n^2=O(n^2)) , (2n=O(n^2)) ,但 (n^2neq o(n^2)) (omega(n)) 与 (o(n)) 类似,表示不紧确的下界。 此外,常用 (T(n)) 表示所需的实际时间的函数。 分析分治算法,以归并排序为例 归并排序最坏运行时间的递归式: [ T(n)=begin{cases}Theta(1)&text{若} n=1,\ 2T(n/2)+Theta(n)&text{若} n>1. end{cases} ] 除使用主定理外,还可以这样理解递归式的值:将递归过程看做一个二叉树。递归调用中的每一层的总代价均为 (cn) ,其中 (c) 为常数。而二叉树的层数应为 (log_2n+1) 。故,整个算法的代价期望为 (Theta(nlog_2n)) 。 分治法 分治法求最大和的子数组 分解。将数组划分为两个子数组。此时,只存在三种子数组: 全部位于中点左侧的子数组 全部位于中点右侧的子数组 跨越中点的子数组 解决

算法导论学习之——堆排序

血红的双手。 提交于 2019-12-31 02:36:34
在这一篇文章中,首先介绍一下堆的属性和性质。然后讲解一下建堆的过程,最后讲解堆排序。 1、堆的介绍 堆的物理存储结构就是一个一维的数组,其数据结构就是一个完全的二叉树。需要注意的是堆中的每个结点不需要后继指针,其父节点和左右孩子结点都可以通过计算得到。假设要计算结点i(i为数组的下标)的父节点和左右孩子结点,可以使用以下公式计算: 在此计算的都是结点的数组下标, 由于堆的数据结构是一个完全二叉树,设该完全二叉树有n个结点。则其内部结点下标分别为:1,2,。。。 故其叶子结点下标分别为: 堆高度:就是从根节点到最长叶子结点的距离。包含N个结点的堆高为: 其次是最大堆和最小堆问题,最大堆就是对任意的父节点的值总是大于或等于孩子节点的值,这样的话就能保证根节点保存堆中的最大元素。 即:A[parent(i)] >=A[i] (最大堆) 同样,最小堆就是对任意的父节点的值小于或等于孩子结点的值,这样就能保证根节点的值最小。 即:A[parent(i)] <=A[i] (最小堆) 一般情况下,最大堆用于堆排序中,最小堆用于优先队列中。 2、建堆 根据堆的性质,我们最终要得到堆的根节点是一个最值,因而,我们需要自底向上进行建堆,若自顶向下建堆的话则不能保证根节点是最值。在此仅讨论建立最大堆的情况。 首先我们可以认为每个叶子结点已经是一个最大堆,然后从最末一个非叶子结点 开始进行对调整

算法导论-堆排序

北慕城南 提交于 2019-12-31 02:36:19
堆排序的时间复杂度是 ,具有空间原址性,即任何时候都只需要常数个额外的元素空间存储临时数据。 一、堆 二叉堆是一个数组,可看成一个近似的完全二叉树,树上的每个结点对应数组中的一个元素。除了最底层外,该树是完全充满的,而且是从左到右填充。 二叉堆可以分为两种形式:最大堆和最小堆。在最大堆中除根节点外所有结点i都要满足: ,即某个结点的值至多与其父结点一样大。在最小堆中除根节点外所有 结点i都要满足: 。 说明: 堆排序中,我们使用最大堆,最小堆通常用于构造优先队列。 二、维护堆的性质 函数MAX-HEAPIFY的输入为一个数组A和下标i,假定根节点为LEFT(i)和RIGHT(i)的二叉树都是最大堆,通过让A[i]的值在最大堆中逐级下降,从而使得以下标i为根结点的子树为最大堆。 函数MAX-HEAPIFY的时间代价包括:调整A[i]、A[LEFT[i]]和A[RIGHT[i]]关系的时间代价 ,加上以一颗i的一个孩子为根结点的子树上运行MAX-HEAPIFY的时间代价(假设递归调用会发生)。 下面首先证明每个子树的大小至多为2n/3。 证明: 设堆的高度为h,最后一层结点个数为m,则整个堆的结点总数为: 。 根结点的左子树结点总数为: , 根结点的右子树结点总数为: ,其中 。 当最底层恰好半满的时候, ,则 , 。 解出: , 。 因此,每个子树的大小至多为2n/3