算法设计技巧与分析

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
算法设计技巧与分析
算法设计技巧与分析 Chapter1:基本的算法 二分搜索算法* Merge算法 选择排序 插入排序 自底向上的归并排序:BottomUpSort* Chapter4: Heap Shift_Up Shift_Down InsertionHeap DeleteHeap MakeHeap HeapSort Chapter 5 Induction SelectionSort InsertionSort *EXPREC(1) *EXPREC(2) Honor rule Majority* Chapter 6 Divide and conquer BinarySearch MergeSort *SELECT *QuickSort large number multiplication Chapter 7 Dynamic planningLCS ModifiedLCS Matrix chain multiplication Bag problem Chapter 8 Greedy algorithm Dijkstra Kruskal Prim Chapter13 Backtracking Triple-color painting problem(1) Triple-color painting (2) AppendixA: Basic conceptions and the calculations AppendixB: Formula AppendixC The examination patterns AppendixD Some classic algorithm for supplement Greedy algorithm 最优服务次序问题 选择需要服务最少的人先服务
算法分析:O(log(n)
InsertionHeap
算法描述:给定一个堆H[1~n],给定一个x. 伪代码
n++; H[n]=x; SiftUp(H,n)
算法分析:O(log(n)
DeleteHeap
算法描述:给定一个堆H[1-n],删除H[i]. 伪代码
x=H[i],y=H[n] n--; if(i=n+1) exit //直接已经完成 H[i]=y; if(H[i]>x)SiftUp(H,i) else Sift_down(H,i)
伪代码
t=1
while(t<n)
//上一次合并之后最小的小组的长度已经大于等于n
{
//t是本次迭代之后的小组长度
s=t,t=2s;i=0.
//其中s是本次迭代的小组的长度 i是游标
while(i+t<=n)
来自百度文库
//t是本次合并之后的小组的长度
Merge(A,i+1,i+s,i+t);
i=i+t;
end while
插入排序
算法思想:对下标为2~n的元素进行分别插入定位。具体地来说,在对第i个元素进行插入定位的时候,其实要 处理的情况是:前i-1个元素已经是有序的。因此只需要做到每次向前移动的时候将前面的元素拷贝到后面即 可。
代码
for i=2 to i=n x=A[i],j=i-1 while(j>0 and A[j]>x) { A[j+1]=A[j]; j--; } A[j+1]=x;
low=1,high=n; while(low<=hign) {
mid=A[low+high];
//取底函数
if(x=mid)j=mid; else if (x<mid)high=mid-1; else low=mid+1;
} end while return j;
算法分析:算法执行第i次循环的时候,剩余的元素个数为【n/2i-1】,为了找到元素比较次数最多的次数,只需 要使得上式子的值为1即可。
Chapter4: Heap
Shift_Up
问题描述:针对一个大顶堆而言,如果一个元素的值变大,那么显然以它为根的子树仍然是一个堆,但是上面 整体的堆的结构遭到了破坏,这个时候调用该算法即可解决。 算法思想:对发生改变的节点,对他进行定位。如果它的父节点的值比他小的话,那么就交换他们的值。这样 就可以保证它上面一层是个堆了。以此类推,直到i本身就是一个爸爸为止。 伪代码
end for
算法分析
元素比较次数 :n-1~n*(n-1)/2 元素赋值次数:元素比较次数+n-1...元素比较次数+2(n-1)。下面是对它的解释:我们关注于一次具体的 for循环内部。如果每次其中while循环终止下来是因为A[j]>x不满足。那么总的元素赋值次数就是加上n-1 否则就是加上2(n-1) 此排序算法的稳定性:稳定的。参考上面代码的第3行。 算法的空间复杂度:O(1)
for i=1 to i=n-1 k=i for j=i+1 to n if (A[j]<A[k])swap(j,k) end for if(k!=i)swap(A[i],A[k]).
end for
算法分析:显然选择排序是一个比较低效率的算法,因为它的元素比较次数是固定的,且为n*(n-1)/2.是Θ(n2) 的。
done=false; if(2i>n) then exit //i节点已经是叶子节点 repeat
i=2i if(i+1<=n&&H[i+1]>H[i]) i++; if(H[【i/2】]<H[i]) swap(H[i],H[【i/2】]) else done=true; until 2i>n or done
问题描述:对数组A[1...n]进行升序排列。 算法思想:先对第一个数进行定位,然后递归调用排序后n-1个元素,依次类推。特别要注意的是这一题的启 发:递归算法不一定是先递归,然后对递归的结果进行处理,也可能是像本题一样,先对整体的数据进行处 理,然后再进行递归调用。 算法伪代码
//sort(i)表示对数组中A[i...n]进行排序 ////k是当前数组中最小元素的下标 if i<n
Shift_Down
算法描述:对于一个大顶堆而言,堆顶元素变小了,破坏了堆的属性,调用用该算法。 算法思想:显然虽然顶点元素的值变小了,但是只破坏了以它为子树的堆的性质。因此只需要堆它为根的子树 进行调整即可。每一次迭代循环中,首先得到最大的那个值,(可能是左儿子也可能是右儿子)。然后和当前 顶点进行比较,如果儿子比老子大,那么直接交换值。显然现在问题转移到了那个儿子的子树上,问题的规模 就进一步缩小了。直到当前节点的左儿子都大于n为止。 伪代码
if(i+s<n)Merge(A,i+1,i+s,n)
}
BottomUpSort 算法的分析:首先我们假设元素的个数是2的正整数次幂。那么,我们可以将整个排序的过 程用树的结构来表示。树的深度为 logn .第一层(也就是根节点)的个数是n个,表示本次循环排序之后每 个小组的个数为 n ,也就是最后一次循环。第二层就是2个 n/2 的树。以此类推,共有 logn 层的数据,循 环 logn 。元素赋值次数一共为 2nlogn 次。因此元素赋值次数即为 2nlog(n) 次 元素比较次数:显然本算法的实质实际上是对 Merge 算法的不停调用。因此算法的比较次数实际上是由该 算法来决定的。为了得到最少的元素比较次数,我们假设第一层,我们的元素比较次数为 (n/2-1)*1 ,第二
A[p...r]=B[p...r];
算法分析 元素比较次数:n1...n-1. 元素赋值次数:2n 需要一个辅助数组的原因。
选择排序
问题描述:A[1-n],进行升序排列。 算法思想:对下标为1到n-1的元素分别进行定位,即找到这个位置的该有的那个元素。其中对每一次循环:都 从它后面一个元素开始查找,在后面找最大的那个数的下标。注意一点:选择排序中设置的flag是下标而不是具 体的值。 算法伪代码
元素比较次数:n(n-1)/2. 元素赋值次数:元素交换次数位于0~n-1. 每次交换需要三次赋值,故元素赋值次数位于0-3(n-1)。有必 要进行一点说明,我们说的元素赋值次数不包括对你下标的操作。 最好和最坏情况分析:选择排序的最好情况和最坏情况都是O(n2). 选择排序的稳定性:选择排序是不稳定的。 算法的空间复杂度:由于只需要一个 flag 也就是本题中的k,因此空间复杂度是O(1)
比较次数:1~【log(n)】+1 *【】为底函数 []为顶函数 空间复杂度:O(1).
Merge算法
问题描述:合并两个已经排好序的表。A[p...q]和A[q+1...r]已经有序。设置B[p~r]是辅助数组. 算法思想:分别设置指向两个排好序的表的表头的指针。另外设置一个指向辅助数组的指针。对两个指针所指 的值进行比较,二者选择其一赋值给辅助数组指针,直到两个表一个为空为止,然后对没有读完的表进行拷贝 即可。 伪代码
HeapSort
问题描述:给定一个数组H[n],使用堆排序算法实现升序排序。 算法思想:首先先建立一个堆,然后分别对第 i 个、第 i-1 个...第 2 个数据进行定位。具体地来说,定位的方法 如下:对于第i个元素的定位,只需要将A[1]和A[i]进行交换即可。然后将第i个元素移除堆。依此类推。 伪代码
自底向上的归并排序:BottomUpSort*
算法适用范围:A[1-n],进行非降序排列
算法思想:该算法比较复杂。但其基本思想却并不复杂,简单地来说,就是先将数组划分为不同的小组。其中 组内有序而组间是无序的。(显然最开始划分小组的时候就只能将小组的宽度设为1)。然后每两个小组进行一 次合并,形成更大的小组。直到将所有的元素都进入一个小组内。显然在进行组间合并的时候我们可以调用前 面已经实现的 Merge 算法。
货币选择问题 直接选择货币值最大的那一个 字典序最小问题 直接从头和尾中选择最小的那一个 区间调度问题 直接结束时间最早的那一个 最大整数问题 将整数转化为字符串然后对字符串进行排序即可
Chapter1:基本的算法
二分搜索算法*
问题描述:对线序升序集合的搜索,给定数组和一个元素的值,搜索数组(下标从1到n),如果在其中,则返回这 个下标j,否则返回0. 算法基本思想:由于是已经排好序的数组。因此我们每一次循环迭代,都用 x 和中项元素进行比较。如果相 等,则直接返回该下标,否则,缩小范围数组比较范围。 算法伪代码
MakeHeap(A);
//实现的是大顶堆
for(j=n down to 2)
swap(A[1],A[j]);
Sift_down(A[1],j-1);
end for
算法分析: 算法的时间复杂度:O(nlogn). 空间复杂度:O(1)
Chapter 5 Induction
SelectionSort
s=p,t=q+1,k=p; while(s<=q&&t<=r) {
if A[s]<=A[t] {
B[k]=A[t];
//s和t都指向原数组 k指向新数组
t=t+1; } else {
B[k]=A[s]; t=t+1; } }
if(s=q+1) then B[k...r]=A[t...r]; else B[k...r]=A[s...q];
done=false;
//标识是否已经完成
if(i=1) then exit
//已经为根节点
repeat
if(key[H[i]]>key[H[【i/2】]]) swap H[i] H[【i/2】]
else done=true
i=【i/2】
until i=1 or done
算法分析:显然树的深度是 log(n+1) 的。算法少进行1次比较,最多进行 log(n+1)-1 次比较。
层则是 (n/4-1)*2 以此类推,第 logn 层应该是 (n/2^logn^-1)*logn 求和。因此元素比较次数是介于 nlogn/2 和 nlogn-n+1 之间的。 归并排序的空间复杂度:O(n)的,定义一个全局辅助数组。 归并排序的稳定性:稳定的。这是因为Merge算法是稳定的。且算法的循环迭代是从前到后执行的。
算法说明:O(logn)
MakeHeap
算法说明:对于一个数组A[1~n],调用该函数使之变成一个堆。 伪代码
for(i=【i/2】 to 1) ShiftDown(A,i)
end for
//使得堆的规模加1
算法说明:元素比较次数C的取值范围是 n-1<=C<=4n,故该算法的时间复杂度是Θ(n)的。
相关文档
最新文档