算法导论

算法导论:堆排序

拜拜、爱过 提交于 2019-12-31 02:36:09
堆 堆是一个数组,它可以被看成一个近似的完全二叉树,树上的每一个结点对应数组中的一个元素。除去最底层外,该树是完全充满的,而且从左到右填充。 用数组A表示堆,从数组第1个元素开始,数组中第i(1<=i <=n)个元素,其父结点,左孩子,右孩子的下标如下 // 父结点 public int parent( int i){ return i/2; } // 左孩子 public int left(int i){ return 2*i; } // 右孩子 public int right(int i){ return 2*i+1; } 当数组起始下标是0的时候,其父结点,左右孩子结点如下 // 父结点 public int parent( int i){ return (i-1)/2; } // 左孩子 public int left(int i){ return 2*i+1; } // 右孩子 public int right(int i){ return 2*i+2; } 堆可以分为大顶堆和小顶堆 大顶堆:结点 i 的值 都大于其左右孩子结点的值 小顶堆:结点 i 的值 都小于其左右孩子结点的值 二叉树的形式与数组形式表达堆之间元素的关系 练习1,高度为h的堆,元素最少和最多是多少? 最多:这个完全二叉树第h层元素填满:2^h - 1 最少:第h-1层填满,第h层只有一个元素:2^

堆排序(摘自算法导论)

筅森魡賤 提交于 2019-12-31 02:35:58
(二叉)堆是一个数组,他可以被看成一个近似的完全二叉树。树上的每一个节点对应数组中的一个元素,除了最底层之外,该树是完全填满的,而且是从左向右填充。表示堆的数组A包括两个属性,A.length给出数组元素的个数,A.heap-size表示有多少个堆元素存储在该数组中。也就是说,虽然A[1..A.length]可能都有数据,但只有A[1..A.heap-size]中存放的是堆的有效元素。0<=A.heap-size<=A.length。树的根节点是A[1],这样给定一个节点的下标i,我们很容易计算得到它的父节点、左孩子和右孩子的下标。 PARENT(i) return[i/2] LEFT(i) return 2i RIGHT(i) return 2i+1 二叉堆可以分为两种形式:最大堆和最小堆。 在最大堆中,最大堆是指除了根节点之外的所有节点i都要满足 A[PARENT(i)]>=A[i] 也就是说,某个节点的最大值至多与根节点一样大。因此,堆中最大的元素存在根节点中;并且,在任一子树中,该子树所包含的所有节点的值都不大于该子树根节点的值。最小堆的组织方式正好相反 最小堆性质市值除了根节点之外的所有节点i都有 A[PARENT[i]]<=A[i] 在堆排序算法中,我们使用的是最大堆,最小堆通常用于构造优先队列。 如果把堆看成一棵树

算法导论:比较排序算法笔记

女生的网名这么多〃 提交于 2019-12-31 02:35:43
好几天没看《算法导论》,今天看了一天的排序算法,印象第一的是基数算法,因为居然违反我的一个常识,它采用的是最低有效位进行排序的。 插入排序、归并排序、堆排序、快速排序,这些都是比较排序算法:它们都是通过对元素进行比较操作来确定输入数组的有序次序,这些算法可以用决策树模型分析,可以证明任意比较排序算法排序n个元素的最坏情况运行时间的下界为Omega(nlgn),其中堆排序和归并排序是渐进最优的比较排序算法。 算法 最坏情况运行时间 平均情况 / 期望运行时间 插入排序(原址) Theta ( n^2 ) Theta ( n^2 ) 归并排序 Theta ( nlgn ) Theta ( nlgn ) 堆排序(原址) Theta ( nlgn ) -------- 快速排序(原址) Theta ( n^2 ) Theta ( nlgn )期望) 堆排序 堆排序的时间复杂度和归并排序一样,都是O(nlgn),另外它具有插入排序的空间原址性优点,即任何时候都只需要常数个额外的空间元素存储临时数据。 堆排序中主要是引入了一种称为“堆”的数据结构来进行信息管理。这里的(二叉)堆可以看作是一个近似的完全二叉树。树上的每一个结点对应数组中的一个元素,如图1所示。 二叉堆可以分为两种形式:最大堆和最小堆。因为在堆排序中应用的是最大堆,所以这里只说最大堆,最大堆中是指除根以外的所有结点i都要满足: A

麻省理工算法导论学习笔记(1)----算法介绍

ぃ、小莉子 提交于 2019-12-29 18:25:31
  我决定啃几个大块头,今天开始跟着公开课学习,一是巩固自己对算法理解,二是可以分享学习心得。   普林斯顿大学的算法课好像也讲完了,只有讲义,好像还没视频,下面我先学麻省理工的算法导论课。    我是一个懒孩子,希望大家监督我。没有监督,俺继续不下去,呃哈哈 。谢谢。    为什么学习算法?   (1)什么比性能更重要?正确性,简洁,可维护性,成本开销,功能性,模块化,安全,可扩展性,用户体验等。   (2)如果算法和性能不重要,为啥关注呢?为什么学习?性能与体验关联,实时性,性能是其他的基础,性能就像货币,你用java来代替c,损失三倍性能,为的是其他方面的优越性,比如对象化,exception机制等。    排序问题    (1)插入排序(Insert Sort)    插入排序分析:      运行时间依赖于输入,比如输入的个数,输入的排序情况。移动、比较的次数可作为衡量时间复杂性的标准。   最大时间(最坏情况,是一个承诺,一个保证):输入逆序。    比较次数:(n+2)(n-1)/2 移动次数:(n+4)(n-1)/2   平均时间(时间的期望值):n+假设的输入分布,比如均匀分布。      最少时间(最好情况):输入正序。   比较次数:n-1   移动次数:0   插入排序快不快?当n很小的时候,挺快,当n很大,就会很慢,通常n<=8。    (2)归并排序

重读算法导论之算法基础

本小妞迷上赌 提交于 2019-12-27 14:51:32
重读算法导论之算法基础 插入排序 ​ 对于少量数据的一种有效算法。原理: 整个过程中将数组中的元素分为两部分,已排序部分A和未排序部分B 插入过程中,从未排序部分B取一个值插入已排序的部分A 插入的过程采用的方式为: 依次从A中下标最大的元素开始和B中取出的元素进行对比,如果此时该元素与B中取出来的元素大小关系与期望不符,则将A中元素依次向右移动 ​ 具体代码如下: public static void insertionSort(int[] arr) { // 数组为空或者只有一个元素的时候不需要排序 if (arr == null || arr.length <= 1) { return; } // 开始插入排序,先假设元素组第一个元素属于已经排好序的A部分,依次从B部分取出元素,进行比较插入 for (int j = 1; j < arr.length; j++) { int key = arr[j]; int i = j - 1; for (; i >= 0; i--) { if (arr[i] > key) { arr[i + 1] = arr[i]; } else { break; } } arr[i+1] = key; } } ​ 易错点为,最后应该是设置arr[i + 1] = key。 可以设想假设A中所有元素都比B中选出来的数小的时候

《算法导论》第15章 动态规划总结

青春壹個敷衍的年華 提交于 2019-12-27 02:22:23
1、基本概念   动态规划是通过组合子问题的解而解决整个问题的,通过将问题分解为相互不独立(各个子问题包含有公共的子问题,也叫重叠子问题)的子问题,对每个子问题求解一次,将其结果保存到一张辅助表中,避免每次遇到各个子问题时重新计算。动态规划通常用于解决最优化问题,其设计步骤如下: (1)描述最优解的结构。 (2)递归定义最优解的值。 (3)按自底向上的方式计算最优解的值。 (4)由计算出的结果构造出一个最优解。   第一步是选择问题的在什么时候会出现最优解,通过分析子问题的最优解而达到整个问题的最优解。在第二步,根据第一步得到的最优解描述,将整个问题分成小问题,直到问题不可再分为止,层层选择最优,构成整个问题的最优解,给出最优解的递归公式。第三步根据第二步给的递归公式,采用自底向上的策略,计算每个问题的最优解,并将结果保存到辅助表中。第四步骤是根据第三步中的最优解,借助保存在表中的值,给出最优解的构造过程。 动态规划与分治法之间的区别: (1) 分治法是指将问题分成一些独立的子问题,递归的求解各子问题。 (2) 动态规划适用于这些子问题不是独立的情况,也就是各子问题包含公共子问题。 2、动态规划基础   什么时候可以使用动态规范方法解决问题呢?这个问题需要讨论一下,书中给出了采用动态规范方法的最优化问题中的两个要素:最优子结构和重叠子结构。 1)最优子结构  

matlab练习程序(二值图像连通区域标记法,两步法)

送分小仙女□ 提交于 2019-12-24 15:39:17
  我几乎完全就是照着 WIKI百科 上的算法实现的,不过是用Matlab而已。使用了两步法进行标记,一步法我还没怎么看。两步法中第二步是比较麻烦的,其中用到了不相交集合的一些理论,尤其是不相交集合森林,我这里的find_set函数就是参考《算法导论》311页的算法写的。如果用c++写,也许需要自己构造数据结构。   好吧,下面是我理解的算法过程:   1.首先要确定是标记8邻域连通还是4邻域连通,如果是8邻域连通,就用 的模板,如果是4邻域连通,就用 的模板。我这里用了是8连通。   2.用模板变量图像,类似卷积,不过不计算,只比较。比较当前像素和邻域4个或2个像素,如果都不相等,那么标记号加一,并且把这个标记号赋值给另一个标记空间中相同位置的像素,因为不能破坏当前图像的像素。如果有一个相等,那么就把这4个或2个像素中非背景像素中的最小值赋给另一个标记空间相同位置的像素,并且把这4个或2个像素同有相同当前位置像素值的集合取并集(ps:这个真的好难解释--!!)。遍历完会得到标记图像和有标记号那么多个的标记集合。   3.遍历标记图像,按标记图像的像素值索引标记集合,找到标记集合中代表当前集合最小的值赋值给原图像当前位置的像素(ps:这里最好看《算法导论》或 这里 )。   还是看代码吧,运行一下更好:   main.m clear all; close all; clc; img

算法导论 第7章 课后习题

早过忘川 提交于 2019-12-10 04:30:48
7.2-4 银行经常按照交易时间,来记录有关某一账户的交易情况,但是,很多人喜欢按照票据号来收到其银行对账单。因此,如何将按交易时间排序转换成按支票编号来排序,就成为一个对几乎排好序的输入进行排序的问题。证明在这个问题上,过程INSERT-SORT的性能往往优于过程QUIKSORT。 问题解析: 对于QUIKSORT来说,输入一个已排序的数组属于最坏的情况,则每次区间划分都是最大程度的不对称。其算法运行的递归时间为T(n) = T(n-1) + Θ(n), 算法时间复杂度为Θ(n^2); 而对INSERT-SORT来说,输入一个已排序的数组却属于最佳的情况,算法时间复杂度为O(n)。也就是说当输入一个几乎排好序的数组,快速排序趋于最坏的情况,而插入排序却趋于最佳的情况。为降低这种最坏情况出现的概率,采用快速排序随机化版本,期望的运行时间为O(nlgn)。 7.3-2 在过程RANDOMIZED-QUIKSORT的运行过程中,最坏情况下对随机排序产生器RANDOM调用了多少次?最佳情况下调用了多少次?以Θ记号形式个给出你的答案。 问题分析: 随机快速排序中,只要区间包含元素数目大于1,则需调用RANDOMIZED-PARTITION,选取主元(pivot)进行区间划分, 而主元的选取需调用Random。主元(pivot)一旦被选出来后,就不会在加入到后续的排序了。直白来说就是

算法导论 排序算法

旧时模样 提交于 2019-12-06 15:16:32
堆排序 二叉堆是一个数组,可以被看作一个近似的完全二叉树。二叉堆可以分为两种形式:最大堆和最小堆。 在最大堆中,最大堆性质是指除了根以外的所有结点i都满足:$A[PARENT[i]]>=A[i]$ 也就是说,某节点的值之多与其父结点一样大,因此,堆中的最大元素存放在根结点,并且,在任意子树中,该子树所包含的所有结点的数值都不大于该子树根结点的值。 最小堆性质是指除了根以外的所有结点i都满足:$A[PARENT[i]]<=A[i]$ 堆中最小元素存放在根结点中。 堆的高度是$lg n$,n是结点数量 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859 """维护堆的性质:输入一个数组A和下标i,调用MaxHeapify时,假定根结点为左子树LEFT(i)和右子树RIGHT(i)的二叉树都是最大堆,但此时A[i]可能会小于其孩子,这就违背了最大堆的性质。调用MaxHeapify通过让A[i]的值在最大堆中“逐级下降”,从而使得以下标i为根结点的子树重新遵循最大堆的性质。时间复杂度:$T(n) leq T(2n/3)+O(1),T(n)=O(lg n),h=lg n$"""def (A, i, size): left=i<

算法小论——第一章 天之道,损有余而奉不足……咳咳拿错稿子了

喜夏-厌秋 提交于 2019-12-06 01:39:22
笔记 这一章基本上就是忽悠大家努力学习算法:算法是一种通过有限步骤的运算来解决计算问题的方式,blabla...算法和数据结构密切相关。算法是一种技术。好的算法可以比差的算法猛的多,好几个数量级,等等。 习题答案 1.1-1 Give a real-world example that requires sorting or a real-world example that requires computing a convex hull. 排序,给班上的学生成绩排序,决定他们的爸妈回去打不打他们的屁股。 计算曲面,游戏或者电影里面用的上吧。 1.1-2 Other than speed, what other measures of efficiency might one use in a real-world setting? 这个问题在公开课上有很好的讨论。空间复杂度(内存和硬盘的占用率),实现方便程度,安全性,容易维护性,等等,都是实际工程需要讨论的。 Rob Pike有一篇 C语言编程实践 ,非常精炼,他认为数据结构才是程序的核心,而非算法,中文版在 这里 。 1.1-3 Select a data structure that you have seen previously, and discuss its strengths and limitations.