刚刚认真学习了第二章,习题还未做。现在趁热打铁,先来凭空总结和回忆一下整个过程。

本章主要线索:通过引入两个算法,从插入排序分析和设计排序算法,引出了整本书后续各章节的算法设计和分析的框架。这个框架归纳起来即是:

引入问题并以实际情景进行思考-->抽象出精确的算法描述(这里就包含了所用的数据结构)-->伪码表示-->证明算法的正确性-->算法分析-->算法设计。

本章先引入的是插入排序算法。

1.实际情景:

插入排序可以以这个实际情景来设想:有一堆牌拿在右手上,你左手开始是空的。每次从右手拿一张牌,与左手已有的排从右到左的进行比较,并插在正确的位置,则左手在每一次插入后均是排好序的。直到右手没有牌时,则终止,此时全部排序完成。

2.算法描述:

输入:含有n个待排序的数组A。(a[1]、a[2]、...、a[n]);

输出:含有n个已排序的数组A。(a`[1]、a`[2]、...、a`[n]);

3.伪码表示:

INSERTION-SORT(A) //输入:待排序数组A

for j <-- 2 to length[A]

do key <-- A[j]

》对每一个待排序数组的元素,将其与已排序数组的元素从右向左的比较,找到合适位置时停止比较并插入

i <-- j-1

while(i > 0 and A[i] > key)//“从右向左比较,找到合适位置停止”包含两层意思:1.向左递进到起始位置则停止,2.找到合适位置则停止;所以这话不妨改为:“从右到左进行比较,到达起始位置或者找到合适位置时停止。(未到达且未找到时不停止)”

A[i+1] <-- A[i] /

i <-- i-1

A[i+1] <-- key

4.算法正确性证明:

先引入所谓"loop invariant'的概念:一般而言,用这个式子表示希望得到的结果,如果在循环的每一步,这个式子都是正确的,那么循环结束后,这个式子也正确,并得到了期望的结果.(有人建议译为循环不变性,因为这是种性质不一定是式子)

循环不变式证明遵循以下三步:1.初始化 2.保持 3.终止

先假设的循环不变式为:在每轮循环开始前,A[1]..A[j-1]是排好序的。

1.初始化:对于for循环就是在第一次测试之前,这里即是在j赋值为2并且在测试j<=length[A]之前。可以看到,这时j=2,此时A[1]是单个元素,是排好序的,满足。

2.保持:假设在某轮循环(j = k时)开始前,循环不变式成立,即A[1]..A[k-1]有序,则在下一轮循环(j = k+1)开始前,已经执行了循环部分,此时A[1]..A[k]成立,满足。

3.终止:j=n+1时,A[1]..A[j-1]即A[1]..A[n]有序,成立。

5.算法分析:

对于算法分析,需要一个模型,我们设计的是一种单处理器的随机存取机模型,指令一条条执行,没有并发。在算法分析中,实际要考虑的因素往往很多,而我们为了方便,只考虑大的因素,小的因素忽略掉。

现在开始分析。

先通过代码标注执行时间:

INSERTION-SORT(A)       costtimes

for j <-- 2 to length[A]c1n

do key <-- A[j]c2n-1

》对每一个待排序数组的元素,将其与已排序数组的元素从右向左的比较,找到合适位置时停止比较并插入

i <-- j-1 c4n-1

while(i > 0 and A[i] > key)c5求和(j=2..n)*t(j)//由于while测试次数不定,故设为t(j)

A[i+1] <-- A[i] c6求和(j=2..n)*(t(j)-1)

i <-- i-1                c7求和(j=2..n)*(t(j)-1)

A[i+1] <-- keyc8n-1

所以T(n)=c1n+c2(n-1)+c4(n-1)+c5(求和(j=2..n)*t(j))+c6(求和(j=2..n)*(t(j)-1))+c7(求和(j=2..n)*(t(j)-1))+c8(n-1)

最好情况:即当数组本身就有序,则A[i] <= key,只测试一次,所以t(j)=1,化简得T(n) = (c1+c2+c4+c5+c8)n-(c2+c4+c5+c8),所以是满足@(n)的(@表示sita)

最坏情况:即循环j-1次,亦即while处测试j次,此时T(n) = (...)n^2+(...)n-(...)

在实际的算法分析中,若平均情况不好估计,一般分析的是最坏情况, 因为最坏情况一般与平均情况一样差,比如这里平均情况是:对于一个插入元素A[j],有一半元素小于它一半大于它,那么t(j) = j/2,亦得一个二次函数,故运行效率相等。

但有时我们仍然对平均情况或期望感兴趣,那么我们可以根据后面会介绍的概率分析技术来进行分析。

下面我们可对执行时间进行简化,因为考虑大规模输入时,相对于增长率来说,系数是次要的,故这里可以改写成:@(n^2)。不解释了吧。

6.设计更好的算法

我们既然分析了算法,就应该找出时间耗费的地方,根据其他的技术或思想来设计更好的算法。开始吧。

我们知道插入排序使用的思想是增量式的设计,还有一种常见的思想则是分治法。

分治法的框架是:1.分解 2.解决3.合并

根据这个框架我们设计出合并排序算法,同样遵循步骤:

1.实际情景:略

2.算法描述:略

3.伪码表示:略

4.算法正确性证明:增量式设计的算法如插入排序使用的证明方法是循环不变式;而对于这种分治法则采用递归主定理来证明即可。

5.算法分析:(可以画递归树来分析)

执行时间写成一般表达式是:

T(n)= @(1)n<=c时

aT(n/b)+D(n)+C(n)否则

解释如下:当规模小于c时,可以直接解决,执行常量时间;否则分解为a个子问题,每个子问题大小是原问题的1/b,D(n)是分解所用时间,C(n)是合并所用时间。

针对这个特定问题,c=1,a=b=2,D(n) = @(n),C(n) = @(n)

不用主定理的话,可以画出递归树来看,可以得到T(n) = cn * (lg n +1)

故T(n) = @(nlgn)

以上就是我对第二章的主线和内容总结。

下面是实现:

插入排序:

#include <iostream>
using namespace std;
void InsertionSort(int A[], int n){ //输入含有n个数的数组Aint length_A = n;for(int j=1; j<=length_A-1; j++){ //从右边挨个取数进行迭代比较int key = A[j];int i = j-1;while(i>-1 && A[i]>key){A[i+1] = A[i];i = i-1;}A[i+1] = key;}
}
//测试
int main(){int A[]={10,9,4,7,8,3,1};InsertionSort(A, 7);for(int i=0; i<7; i++)cout<<A[i]<<" ";return 0;
}

合并排序:

#include <iostream>
using namespace std;
#define SENTINEL 10000; //用一个比所有数字都大的值作为哨兵
void Merge(int* A, int p, int q, int r){int n1 = q-p+1;int n2 = r-q;int *L = new int[n1+1];int *R = new int[n2+1];for(int i=0; i<=n1-1; i++)L[i] = A[p+i-1];for(int j=0; j<=n2-1; j++)R[j] = A[q+j];L[n1] = SENTINEL;R[n2] = SENTINEL;int i = 0;int j = 0;for(int k=p-1; k<=r-1; k++){if(L[i]<=R[j]){A[k] = L[i];i++;}else{A[k] = R[j];j++;}}delete[] L;delete[] R;
}
void MergeSort(int* A, int p,int r){if(p<r){int q = (p+r)/2;MergeSort(A, p, q);MergeSort(A, q+1, r);Merge(A, p, q, r);}
}
int main(){int A[]={10,9,4,7,8,3,1,15,12};int length_A = 9;;MergeSort(A, 1, length_A);for(int i=0; i<length_A; i++)cout<<A[i]<<" ";return 0;
}

算法入门章——引出贯穿《算法导论》全书的算法分析和设计框架相关推荐

  1. 算法入门篇八 贪心算法

    牛客网 左程云老师的算法入门课 贪心算法 贪心算法的解题步骤  例子 题目要求  解题策略 按照结束时间早的会议先安排,比如先安排[2,4],当4结束了,所有开始时间小于4的全部淘汰,[1,7].[3 ...

  2. 令人拍案叫绝的算法学习网站新手算法入门到精通,算法面试冲刺资料这里都有

    (9月已更)学算法认准这6个网站就够了! 写在前面:作为ACM铜牌选手,从FB到腾讯,从事算法&java岗位工作也是5年有余.在工作中接触到了很多同学,在算法学习和算法面试这件事上我还是很有发 ...

  3. 令人拍案叫绝的算法学习网站,算法入门到精通,算法面试冲刺资料这里都有

    前言 作为ACM铜牌选手,从FB到腾讯,从事算法&java岗位工作也是5年有余.在工作中接触到了很多同学,在算法学习和算法面试这件事上我还是很有发言权的. 今天就跟想学算法的同学分享一下我私藏 ...

  4. 有这样一套AI算法入门书,学习算法不再难

    本系列图书将向读者介绍人工智能领域的各种热门主题.由于人工智能是一个庞大而繁杂的领域,并且其涵盖的内容与日俱增,任何一本书都只可能专注于特定领域,因此本书也无意成为一本巨细靡遗的人工智能教程. 本系列 ...

  5. 猿创征文|【算法入门必刷】数据结构-栈(二)

    [算法入门必刷]算法入门-数据结构-栈(二) 前言 算法入门刷题训练 题目AB2: 栈的压入.弹出序列 题目分析 理论准备 题解 小结

  6. 猿创征文 |【算法入门必刷】数据结构-栈(三)

    [算法入门必刷]算法入门-数据结构-栈(三) 前言 算法入门刷题训练 题目AB3:有效括号序列 题目分析 理论准备 题解 小结

  7. 猿创征文 |【算法入门必刷】数据结构-栈(四)

    [算法入门必刷]算法入门-数据结构-栈(四) 前言 算法入门刷题训练 AB4:逆波兰表达式求值 题目分析 理论准备 题解 小结

  8. LDA算法入门(转)

    LDA算法入门 一. LDA算法概述: 线性判别式分析(Linear Discriminant Analysis, LDA),也叫做Fisher线性判别(Fisher Linear Discrimin ...

  9. cordic算法反正切c语言,Cordic 算法之 反正切

    在通信的算法中,常采用Cordic算法之一,知道角度产生正交的的正弦余弦, 或者知道正弦和余弦求角度,求反正切. 1. 求正弦和余弦值. 方法:旋转角度,得到正弦余弦值: 再旋转角度,到达下一个正弦余 ...

最新文章

  1. 小程序这件事 撸起袖子加油干
  2. mysql 分页测试,
  3. 1-36随机生成6个不重复的数
  4. Jpa规范原始编程步骤
  5. 1.RTMP流媒体服务器搭建
  6. Angular应用页面里_ngcontent属性的生成逻辑
  7. dll放在unity哪个文件夹下_unity中调用dll文件总结
  8. 软件集成策略故事连载----构建错误是怎么来的
  9. loadrunner11破解技巧
  10. 搭建Ubuntu下c/c++编译环境
  11. 前端导出excel,单独设置表头
  12. 5月电脑攒机配置推荐!
  13. 基于HFSS的圆形左旋圆极化贴片天线仿真分析
  14. 三阶魔方层先还原方法图解
  15. latex中表格、图片的排版
  16. 20145212罗天晨 逆向及Bof基础实践
  17. 低配本用win10服务器系统,低配电脑用win7还是win10比较好_低配置电脑装win7还是win10系统合适...
  18. 盛邀相聚贵阳,共赴“计算”之约,CNCC2022新闻发布会举行
  19. 从WAVE SUMMIT+2021,寻找新一代AI人不可或缺的“凝视”
  20. Flutter尽然还能有这种操作!隔壁都馋哭了

热门文章

  1. 利用gensim里word2vec训练实例——分析三国里人物关系
  2. Eclipse打开报错,The Eclipse executable launcher was unable to locate its companion shared library.
  3. APS系统如何让企业实现“多赢”?看高博通信是怎么做的
  4. kingcms php 下载,KingCMS企业版(PHP) v6.1.1641(Sp2)
  5. ubuntu装后的常用软件的安装与配置
  6. 从用户文件到系统驱动,全面清理c盘
  7. 今天,昆山向全世界发出邀请!
  8. 先进先出SQL Server 语句
  9. python+opencv遇到的错误(长期更新)
  10. 趣味数学:解24点游戏小技巧