
《算法导论(第二版)》各章程序实现
文章平均质量分 64
MichealTX
算法/C/C++/JAVA/网络/python
展开
-
第七章快速排序之“快速排序QUICKSORT”
#include #include #define BUFFER_SIZE 10int Partition(int *a,int p,int r){ int x=0; int i=0; int j=0; int tmp=0; x=a[r]; i=p-1; for(j=p;j<r;j++) {//将数组划分为四个区,(a[p]~a[i])x,(a[j]~a[r-1])原创 2012-01-05 09:47:42 · 766 阅读 · 0 评论 -
第七章快速排序之“快速排序Hoare版本HOARE-QUICKSORT”(思考题7-1)
这是个历史更早的版本,Hoare是人名,这个版本的Partition()函数跟现在的不一样。我觉得这个老版本不如现在的版本好理解,大面上看起来可能好理解,但是具体写代码时考虑指针移动,很麻烦。#include #include #define BUFFER_SIZE 10int HoarePartition(int *a,int p,int r){ int tmp=0原创 2012-01-05 22:05:05 · 2407 阅读 · 0 评论 -
第七章快速排序之“快速插入排序”(练习7.4-5)
O(∩_∩)O~,这个名字乍听起来比较黄。其实就是先快速排序进行划分,等划分小到一定规模比如k时,进行插入排序,因为规模小到一定程度,插入排序的效率更高。我在前面还写过一个合并插入排序的算法,思想跟这个相似。总的时间复杂度为O(nk+nlg(n/k)),这个很好证明:先进行二分,划分到规模都为K时停止划分,此时深度为h,则T(n/2^h)=k,则h=lg(n/k),最底层规模为K的叶节点数原创 2012-01-05 22:03:27 · 3446 阅读 · 0 评论 -
第六章堆排序之“Young氏矩阵(Young tableau)”(思考题6-3)
这个程序是利用Young氏矩阵为n*n的数组排序。其中涉及到:插入法建立Young氏矩阵,然后再调用”去掉返回堆顶元素”的函数得到从小到大的排列。总的时间复杂度为O(n^3)。其中向Young氏矩阵“插入一个元素”的时间复杂度为O(m+n),m为Young氏矩阵的行数,n为Young氏矩阵的列数,建立Young氏矩阵要插入n*n个元素则为O((n^2)*2n)=O(n^3)。“去掉返回原创 2012-01-04 17:29:38 · 1597 阅读 · 0 评论 -
第六章堆排序之“插入法建堆”(思考题6-1)
建堆既可以用堆调整方法将原数组调整为一个堆,也可以借助往堆中插入元素的方法从无到有的建立一个堆。两种方法比较:(1)借助堆调整建堆的时间复杂度为O(n)。借助插入法建堆的时间复杂度为O(nlgn) ,书上第二问要求证明这个复杂度,但是我认为插入法的复杂度也是O(n),因为它和堆调整的区别在于针对每个节点i,堆调整是自上向下进行调整,插入法是自下向上进行调整。(2)对于同样的输入两个方法原创 2012-01-04 09:50:39 · 3801 阅读 · 0 评论 -
第六章堆排序之“对d叉堆的分析”(思考题6-2)
d叉堆在数组中如何表示:(1)若某个子节点索引为i,则它的父节点的索引为(i-2)/d+1,向下取整。(2)若某个父节点索引为i,则它的第j个子节点的索引为d*(i-1)+j+1。下面的程序是用插入法建立d叉最大堆,并显示了一次去掉和返回堆顶元素后剩余堆的情况。其中 “调整d叉堆” 的时间复杂度都为O(dlogd(n)),d为底哦。(纵向进行logd(n)(即深度)次,每次再横向比原创 2012-01-04 11:20:47 · 2912 阅读 · 0 评论 -
第六章堆排序之“优先级队列实现先进先出队列和栈”(练习6.5-6)
这个不写代码了。思路如下:首先要先明确优先级是谁?优先级队列嘛,当然最重要的是要先知道“优先级”是谁,才能按它排序。这里的优先级就是进出队的次序。(1)优先级队列实现先进先出队列先进队的优先级更高,赋予每个进队的元素一个优先级值,但优先级的值我们令0最大,1次之,2再次之,···,然后按着这个优先级值建立最大优先级队列,每次用HeapExtractMax()取堆顶元素,这个肯定原创 2012-01-03 11:52:59 · 3810 阅读 · 0 评论 -
第二章之“合并排序”(不使用哨兵元素,练习2.3-2)
#include #include #include #define BUFFER_SIZE 10void Merge(int *a,int p,int q,int r){ int n1=q-p+1; int n2=r-q; int b[n1]; int c[n2]; int n=n1+n2; int i=0; int j=0; int k=0; memset(b,原创 2011-12-25 16:15:08 · 747 阅读 · 0 评论 -
第二章之“冒泡排序”(思考题2-2)
重复的交换相邻的两个反序元素。#include #include #include #define BUFFER_SIZE 10void BubbleSort(int *a,int len){ int i=0; int j=0; int temp=0; for(i=1;i<len;i++) { for(j=0;j<len-i;j++) { if(a[j原创 2011-12-27 14:12:31 · 749 阅读 · 0 评论 -
第六章堆排序之“删除最大堆中的指定元素HEAP-DELETE”(练习6.5-7)
题目:HEAP-DELETE(A,i)操作将节点i中的项从堆中删去。对含n个元素的最大堆,请给出时间为O(lgn)的HEAP-DELETE的实现。编程思路:我们可以用堆中最后一个元素a[heapSize]放到节点i 位置,然后将heapSize减一。然后就涉及到堆调整以保持堆的性质。调整的依据就是这最后一个元素a[heapSize]跟原来i节点的元素a[i]的相对大小,分三种情况:原创 2012-01-03 14:32:57 · 6346 阅读 · 0 评论 -
第五章概率分析和随机算法之练习5.3-6
题目:解释如何实现算法PERMUTE-BY-SORTING,来处理两个或更多优先级相同的情况。即,即使有两个或更多个优先级相同,你的算法也必须产生一个均匀随机排列。刚才在百度算法吧看到有人提出这个问题,居然将近四年没人回答。我回复了一下那个帖子,顺便把自己的看法复制到这里。若有问题,请路过的大牛帮助斧正,不胜感激。我的解答:打比方有a,b,c,d这个序列,我们用原创 2012-04-14 14:29:33 · 2066 阅读 · 2 评论 -
第九章中位数和顺序统计学之“查找第i小的元素(迭代版)平均运行时间为O(n)算法”(练习9.2-3)
这个是相对前一篇文章来说的,这是个迭代版本。递归化为迭代的一个关键点,就是看递归调用时,哪些参数值发生改变,然后针对这个参数设计循环。#include #include #define BUFFER_SIZE 10int RandomizedPartition(int *a,int p,int r){ int i=0; int j=0; int tmp=0; int x原创 2012-01-17 19:03:08 · 1363 阅读 · 0 评论 -
第九章中位数和顺序统计学之“查找第i小的元素(递归版)平均运行时间为O(n)算法”
类似于快速排序的随机化版本,但是这里每次只处理划分的一侧。最坏情况下时间复杂度为O(n^2),即每次都是按最大区间进行划分。但在平均情况下,任何顺序统计量(特别是中位数)都可以在线性时间内得到,时间复杂度为O(n)。#include #include #define BUFFER_SIZE 10int RandomizedPartition(int *a,int p,in原创 2012-01-17 15:41:48 · 1177 阅读 · 0 评论 -
第六章堆排序之“用最小堆将k个已排序链表合并为一个排序链表”(练习6.5-8)
问题:请给出一个时间为O(nlgk),用来将k个已排序链表合并为一个排序链表的算法。此处的n为所有输入链表中元素的总数。(提示:用一个最小堆来做k路合并)编程思路:假设k个链表都是非降序排列的。(1)取k个元素建立最小堆,这k个元素分别是k个链表的第一个元素。建堆的时间复杂度O(k)。(2)堆顶元素就是k个链表中最小的那个元素,取出它。时间复杂度O(1)。(3)若堆顶元素所在链原创 2012-01-04 08:33:08 · 3658 阅读 · 3 评论 -
第十五章动态规划之“最长公共子序列”
时间复杂度为O(m*n),就是两个循环。#include using namespace std;void LCSLength(char *x,char *y,int m,int n,int (*c)[7],int (*b)[7]){ for(int i=0;i<=m;i++) { c[i][0]=0; } for(int i=0;i<=n;i++) { c[原创 2012-05-04 21:44:36 · 1098 阅读 · 0 评论 -
第十五章动态规划之“最优二叉查找树”
本书从文字翻译的案例切入,假设把英文翻译为法文,每个英文单词为关键字,其对应法文为卫星数据。用二叉查找树存储,该怎么设计这个查找树。即使是红黑树,查找的时间复杂度也为O(lgn)即树的深度。但是因为文章中某个单词出现的频率不同,所以可能有些频率很高的单词比如the的深度可能很深,而不常见的Aha的深度却可能很浅。根据直觉,我们应该让本例中the更加靠近树根才对(其实即使概率最高也不见得就是树根)。原创 2012-05-05 15:12:05 · 1750 阅读 · 0 评论 -
第十二章Trie树(字典树)解决HDU1251
http://acm.hdu.edu.cn/showproblem.php?pid=1251 #include using namespace std;struct TrieNode{ TrieNode *children[26]; bool flag; int cnt;//前缀数目};void InitTrieNode(TrieNode *t原创 2012-04-19 17:05:08 · 1307 阅读 · 0 评论 -
第十五章动态规划之“O(n^2)时间寻找n个数构成序列的最长递增子序列”(练习15.4-5)
这个问题类似于两个序列的最长公共子序列问题,但是这里只有一个序列啊?肿么办?想想这个n个数的序列,要想找它最长递增子序列,这个子序列肯定是从小到大排序的,从小到大排序的耶!跟谁对应呢?思路来了!先把原序列从小到大排序,然后跟原序列对比寻找最长公共子序列!排序时间为O(nlgn),两个长度为n的序列寻找最长子序列为O(n^2),所以总的时间复杂度为O(n^2)。代码:#inclu原创 2012-05-04 22:16:13 · 2475 阅读 · 0 评论 -
第十五章动态规划之“矩阵链乘法”
装配线调度与矩阵链乘法是很典型的动态规划的两个例子。关于这俩例子对于理解动态规划的作用稍后补上。这个程序的时间复杂度为Ω(n^3),这个可以通过替换法证明。输出最优加括号的代码对于理解递归很有帮助,蹭蹭蹭,先往回跑,路上什么也不干,跑到头再跑回来,把该干的都干了,先自顶向下,再自底向上。代码如下:#include using namespace std;void MatrixCh原创 2012-05-04 08:55:45 · 1981 阅读 · 0 评论 -
第十二章二叉查找树
二叉查找树的查找(查找某个值、查找最小元素、查找最大元素)、插入、删除操作的最坏时间都为O(h)。构造二叉查找树时采取随机算法,可以让二叉查找树的期望高度为O(lgn),则前面那些操作的最坏时间就可以为O(lgn)。非常高效的算法。代码如下:#include using namespace std;struct TreeNode{ int key; TreeNode *p;原创 2012-04-19 10:56:05 · 1230 阅读 · 0 评论 -
第十五章动态规划之“装配线调度”
动态规划研究的问题与分治法区别:动态规划的子问题不是相互独立的,而是有交集,即子问题相互重叠,为了避免重复计算重叠的子问题,所以选择从底向上的迭代,以后用到直接查表。从而将装配线调度的复杂度从O(2^n)降到了O(n)。代码如下:#include using namespace std;void FastestWay(int (*a)[7],int (*t)[7],int *e,i原创 2012-05-03 13:41:42 · 916 阅读 · 0 评论 -
第九章中位数和顺序统计学 之 “寻找第i小元素之最坏情况线性时间的选择 最坏运行时间就为O(n)算法”
使用这个算法查找第i小元素的最坏情况运行时间为O(n)。关于运行时间的证明简直屌爆了!唉,看了这么多证明,我发现其实最难的就是提出数学模型、数学描述,迈出这一步,剩下的就是凑了。这个算法比9.2节中那个“期望运行时间才是O(n)”的RandomizedPartition算法更加牛逼,它最坏运行时间就是O(n)。之所以这么屌,是因为它每次划分都能保证是最佳划分,即“中分”。要想实现中分,原创 2012-04-16 22:01:52 · 3757 阅读 · 0 评论 -
第二章之“CheckSums”(练习2.3-7)
题目:请给出一个运行时间为O(nlgn)的算法,使之能在给定一个由n个整数构成的集合S和另一个整数x时,判断出S中是否存在有两个其和等于x的元素。思路:输入:数组a[1...n],待查找整数v输出:若存在,输出在数组a中找到的第一对加和等于v的两个元素索引及其值。首先采用合并排序算法对数组进行从小到大排序(复杂度为O(nlgn))。从左→右扫描数组a(时间复杂度为O(n)),对原创 2011-12-27 09:51:08 · 693 阅读 · 0 评论 -
第二章之“合并排序中对小数组采用插入排序”(思考题2-1)
虽然插入排序的时间复杂度为O(n^2),合并排序的时间复杂度为O(nlgn),但是当子问题规模很小时,插入排序的效率要比合并排序高,所以,可以将合并排序和插入排序进行组合,当合并排序的子数组小到一定程度时,不再进行划分,而是改变算法,用插入排序算法对其进行排序。#include #include #include #define BUFFER_SIZE 10int Insert原创 2011-12-27 13:58:19 · 2137 阅读 · 2 评论 -
第六章堆排序之“最大优先级队列”
用最大堆实现最大优先级队列://返回堆的最大值int HeapMaximum(int *a)//去掉并返回堆中具有最大关键字的元素int HeapExtractMax(int *a,int *heapSize)//将元素x的关键字值增加到k,这里k不能小于x的原关键字值void HeapIncreaseKey(int *a,int i,int k)//将元素x插入到堆中原创 2012-01-02 22:01:38 · 936 阅读 · 0 评论 -
第九章中位数和顺序统计学之“寻找第2小元素”(练习9.1-1待改进)
在最坏的情况下,利用n+(lgn的上限)-2次比较,即可找到n个元素中的第2小元素。(提示:同时找最小元素)#include #include #define BUFFER_SIZE 10void FirstAndSecond(int *a,int len,int *first,int *second){ int i=0; int j=0; if(a[0]<a[1原创 2012-01-17 15:09:34 · 978 阅读 · 0 评论 -
第九章中位数与顺序统计学之“同时找出最小值和最大值”
在一个数组同时找出最小值和最大值。可以分别找出最小值,比较n-1次;找出最大值,比较n-1次,共比较2n-2次。其实还有更少的比较次数。就是成对的处理元素,先将一对输入元素互相比较,找出最小值和最大值,然后再用最小值与当前的最小值比较得出新的最小值,用最大值和当前最大值比较,得出新的最大值,所以这一对元素共比较了3次。n个元素则只需比较3*((n/2)的下限)次。当然对于n为偶数和奇数,处理过原创 2012-01-10 20:59:26 · 1868 阅读 · 0 评论 -
第八章线性时间排序之“桶排序BUCKET-SORT”
要对n个数进行排序,就要准备n个桶。先对n个数归一化,就是把它们除以一个较大的数,使之分布在【0,1)之间,然后对每个桶中的数插入排序,最后合并n个桶。时间复杂度为O(n)。#include #include typedef struct _Node { double value; struct _Node *next;}Node;#define BUFFER_SI原创 2012-01-10 16:39:00 · 813 阅读 · 0 评论 -
第八章线性时间排序之“基数排序RADIX-SORT”(练习8.3-1)
利用基数排序对a[17][4]={" ","COW","DOG","SEA","RUG","ROW","MOB","BOX","TAB","BAR","EAR","TAR","DIG","BIG","TEA","NOW","FOX"}进行排序。“基数排序”可以看做给“计数排序”创造条件,一般的小数用基数排序很麻烦,而且效率不如计数排序,但是要是n个长度为b的长整数或者字符串,可以先用r(r原创 2012-01-10 09:45:18 · 974 阅读 · 0 评论 -
第八章线形时间排序之“计数法排序COUNTING-SORT”
这个方法很牛逼,这个排序方法不再像前面那些排序方法一样根据比较来进行。时间复杂度为O(k+n+k+n+n)=O(n),当k=O(n)时,可以保证时间复杂度为O(n),就可以用计数法来进行排序了。这个方法的一个前提是必须要知道要排序的数组中元素的取值范围。#include #include #define BUFFER_SIZE 10void CountingSort(in原创 2012-01-09 14:53:30 · 936 阅读 · 0 评论 -
第七章快速排序之“区间模糊排序FUZZY-SORT”(待改进。。。)
快速排序可以看成区间大小为1的模糊排序。#include #include #define BUFFER_SIZE 10typedef struct{ int start; int end;}Node; int FuzzyPartition(Node *a,int p,int r){ Node tmp; int i=0; int j=0; int k=0; N原创 2012-01-07 17:14:03 · 1225 阅读 · 0 评论 -
第七章快速排序之“采取“尾递归”和“三数取中”技术的快速排序”(思考题7-4、7-5)
QUICKSORT算法包含两个对其自身的递归调用,即调用PARTITION后,左边的子数组和右边的子数组分别被递归排序。QUICKSORT中的第二次递归调用并不是必须的,可以用迭代控制结构来代替它,这种技术叫做“尾递归”,大多数的编译器也使用了这项技术。最坏的情况下,就是划分不好的时候,递归深度为O(n),能够二分的话递归深度为O(lgn),但是怎么才能得到好的划分呢?前面在快速排序中用了个随机化原创 2012-01-06 17:04:52 · 3821 阅读 · 0 评论 -
第六章堆排序之“建堆BUILD-MAX-HEAP”(迭代版)
自下向上对每一个结点或者只对每个非叶结点使用“保持堆的性质”即“堆调整”MAX-HEAPIFY#include #include #include #define BUFFER_SIZE 10void MaxHeapIfy(int *a,int i,int heapSize){ int left=i; int right=i; int tmp; int largest原创 2012-01-02 16:00:38 · 2824 阅读 · 0 评论 -
第二章之“逆序对数目”(思考题2-4)
设计用时间复杂度为O(nlgn)的算法对长度为n的数组中的逆序对计数。核心思想就是修改合并排序算法,因为当合并时会比较两个连续小数组中元素的大小。#include #include #include #define BUFFER_SIZE 10void Merge(int *a,int p,int q,int r,int *cnt){ int i=0; int j=0;原创 2011-12-27 14:51:47 · 818 阅读 · 0 评论 -
第二章之“插入排序”
#include #include #include #define BUFFER_SIZE 10void InsertionSort(int *a,int len){ int i=0; int j=0; int b[len]; b[0]=a[0]; for(j=1;j<len;j++) { i=j-1; while(i>=0&&b[i]>=a[j])//非降原创 2011-12-24 16:02:36 · 840 阅读 · 0 评论 -
第六章堆排序之“建堆BUILD-MAX-HEAP”(递归版)
自下向上对每一个结点或者只对每个非叶结点使用“保持堆的性质”即“堆调整”MAX-HEAPIFY#include #include #include #define BUFFER_SIZE 10void MaxHeapIfy(int *a,int i,int heapSize){ int left=i<<1; int right=(i<<1)+1; int tmp原创 2012-01-02 15:58:12 · 1551 阅读 · 0 评论 -
第六章堆排序之“堆排序HEAPSORT”
(1)先用BuildMaxHeap()建立最大堆(2)交换a[1]和a[heapSize],把最大的换到最后(3)堆大小heapSize减1(4)因为将最后一个元素换到堆顶可能会破坏堆的性质,所以调用MaxHeapIfy()将新的heapSize大小的堆调整最大堆(5)将(2)~(4)重复heapSize-1次,这里的heapSize是最初的那个heapSize。因为一共有heap原创 2012-01-02 19:45:59 · 947 阅读 · 0 评论 -
第二章之“二分查找”(迭代实现,练习2.3-5)
#include #include #include #define BUFFER_SIZE 10void Merge(int *a,int p,int q,int r){ int n1=q-p+1; int n2=r-q; int b[n1]; int c[n2]; int n=n1+n2; int i=0; int j=0; int k=0; memset(b,原创 2011-12-26 22:04:05 · 673 阅读 · 0 评论 -
第二章之“二分查找”(递归实现,练习2.3-5)
#include #include #include #define BUFFER_SIZE 10void Merge(int *a,int p,int q,int r){ int n1=q-p+1; int n2=r-q; int b[n1]; int c[n2]; int n=n1+n2; int i=0; int j=0; int k=0; memset(b,原创 2011-12-26 22:13:04 · 627 阅读 · 0 评论 -
第二章之“选择排序”
#include #include #include #define BUFFER_SIZE 10 void SelectionSort(int *a,int len){ int i=0; int j=0; int min=0; int temp=0; for(j=0;j<len-1;j++) { min=a[j]; for(i=j+1;i<len;i++)原创 2011-12-24 19:01:58 · 560 阅读 · 0 评论