[算法导论]第二章《算法基础》
来源:互联网 发布:js 函数触发submit 编辑:程序博客网 时间:2024/06/07 02:40
刚开始学习算法导论(第三版),目前打算把书上的伪代码转换成C++代码。有错或者其他累赘求指教。
插入排序算法伪代码
INSERTION-SORT(A)1 for j=2 to A.length[A]
2 do key=A[j]
3 //Insert A[j] into the sorted sequence A[1..j-1]
4 i=j-1
5 while i>0 and A[i]>key6 do A[i+1] = A[i]
7 i=i-1
8 A[i+1] =key
循环不变式:证明算法正确性的一个重要工具。对于循环不变式,必须证明它的三个性质:
初始化:循环的第一轮迭代开始之前,它为真。
保持:如果在循环的某一次迭代开始之前它为真,那么下次迭代开始之前它仍为真。
终止:当循环终止时,不变式给了我们一个有用的性质,它有助于表明算法是正确的。
运用循环不变式对插入排序算法的正确性进行证明:
初始化:j=2,子数组A[1..j-1]只包含一个元素A[1],显然它是已排序的。
保持:若A[1..j-1]是已排序的,则按照大小确定了插入元素A[j]位置之后的数组A[1..j]显然也是已排序的。
终止:当j=n+1时,退出循环,此时已排序的数组是由A[1],A[2],A[3]…A[n]组成的A[1..n],此即原始数组A。
算法的C++代码实现:
#include <iostream>#include <vector>using namespace std;void input (vector<int> &A){cout<<"输入数据(crtl+a回车结束)\n"; int data; while(cin>>data) {A.push_back(data);}}void insertion_sort(vector<int> &A){for(int j=1;j<A.size();++j){int key=A[j];int i=j-1;while(i>=0&&key<A[i]){ A[i+1]=A[i];--i;}A[i+1]=key;}}void output(vector<int> &A){cout<<"排序后:";for(vector<int>::iterator iter=A.begin();iter!=A.end();++iter){cout<<*iter<<" ";}cout<<endl;}int main(int argc, char *argv[]){vector<int> A; input(A);insertion_sort(A);output(A); return 0;}
2.3.1.分治法
有很多算法在结构上是递归的:为了解决一个给定的问题,算法要一次或多次地递归调用其自身来解决相关的问题。这些算法通常采用分治策略:将原问题划分成n个规模较小而结构与原问题相似的子问题;递归地解决这些子问题,然后再合并其结果,就得到原问题的解。
容易确定运行时间,是分治算法的有点之一。
分治模式在每一层递归上都有三个步骤:
分解:将原问题分解成一系列子问题;
解决:递归地解各子问题。若子问题足够小,则直接求解;
合并:将子问题的结果合并成原问题的解。
归并排序算法完全依照了分治模式。
分解:将n个元素分成各含n/2个元素的子序列;
解决:用合并排序法对两个子序列递归地排序;
合并:合并两个已排序的子序列以得到排序结果。
在对子序列排序时,其长度为1时递归结束。单个元素被视为是已排好序的。
合并排序的关键步骤在于合并步骤中的合并两个已排序子序列。为做合并,引入一个辅助过程MERGE(A,p,q,r),其中A是个数组,p、q和r是下标,满足 。该过程假设子数组A[p..q]和A[q+1..r]都已排好序,并将他们合并成一个已排好序的子数组代替当前子数组A[p..r]。
MERGE过程的时间代价为Θ(n),其中n=r-p+1是待合并的元素个数。
MERGE过程:
MERGE(A,p,q,r)
1 n1=q-p+1
2 n2=r-q
3 //Let L[1..n1+1] and R[1..n2+1] be new arrays
4 for i=1 to n1
5 do L[i] =A[p+i-1]
6 for j=1 to n2
7 do R[j] ← A[q+j]
8 L[ n1+1] =无穷
9 R[ n2+1] =无穷
10 i=1
11 j=1
12 for k=p to r
13 if L[i]<= R[j]
14 then A[k] =L[i]
15 i=i+1
16 else A[k] =R[j]
17 j=j+1
MERGE过程正确性的证明
初始化:第一轮循环,k=p,i=1,j=1,已排序数组L、R,比较两数组中最小元素L[i]、R[j],取较小的置于A[p],此时子数组A[p..p]不仅是已排序的(仅有一个元素),而且是所有待排序元素中最小的。若最小元素是L[i],取i=i+1,即i指向L中未排入A的所有元素中最小的一个;同理,j之于R数组也是如此。
保持:若A[p..k]是已排序的,由计算方法知,L中i所指、R中j所指及其后任意元素均大于等于A[p..k]中最大元素A[k],当k=k+1,A[k+1]中存入的是L[i]、R[j]中较小的一个,但是仍有A[k] <= A[k+1],而此时,子数组A[p..k+1]也必是有序的,i、j仍是分别指向L、R中未排入A的所有元素中最小的一个。
终止: k=r+1时终止跳出循环,此时,A[p..r]是已排序的,且显有A[p] A[p+1] .. A[r]。此即原待排序子数组,故算法正确。
MERGE-SORT(A,p,r)
1 if p<r
2 then q=[(p+r)/2]
3 MERGE-SORT(A,p,r)
4 MERGE-SORT(A,q+1,r)
5 MERGE-SORT(A,p,q,r)
归并排序算法的C++实现代码:
#include <iostream>#include <vector>#define INFINITE 10000000using namespace std;void input (vector<int> &A){cout<<"输入数据(crtl+a回车结束)\n"; int data; while(cin>>data) {A.push_back(data);}}void MERGE (vector<int> &A, int p, int q, int r){vector<int> L,R;int n1 = q-p+1;int n2 = r-q; for(int i=p;i<=q;++i)L.push_back(A[i]); L.push_back(INFINITE); for(int j=q+1;j<=r;++j) R.push_back(A[j]); R.push_back(INFINITE);for (int k=p,m=0,n=0;k<=r ;++k ){if (L[m]<R[n]){A[k]=L[m++];}else{A[k]=R[n++];}}}void MERGE_SORT(vector<int> &A,int p,int r){if (p<r){int q=(p+r)/2;MERGE_SORT(A,p,q);MERGE_SORT(A,q+1,r);MERGE(A,p,q,r);}}void output(vector<int> &A){cout<<"排序后:";for(vector<int>::iterator iter=A.begin();iter!=A.end();++iter){cout<<*iter<<" ";}cout<<endl;}int main(int argc, char *argv[]){vector<int> A; input(A);MERGE_SORT(A,0,A.size()-1);output(A);system ("pause"); return 0;}
- [算法导论]第二章《算法基础》
- 算法导论第二章
- 算法导论第二章
- 算法导论 第二章
- 算法导论 第二章
- 算法导论-第二章
- 算法导论第二章
- 算法导论第二章-算法基础-Cpp代码实现
- 算法导论_第二章_算法基础
- 算法导论详解(1) 第二章算法基础+python实现
- 算法导论 第二章InsertSort
- 算法导论 第二章MergeSort
- 《算法导论》第二章 入门
- 算法导论第二章心得
- 算法导论:第二章总结
- 算法导论 第二章作业
- 算法导论第二章笔记
- <笔记><算法导论><第二章>
- 开发web项目遇到的问题
- 让笔记本成为无线路由
- ENVI下植被指数模型详解
- C ++ sort()与stable_sort()
- jvm的几个运行时数据区域
- [算法导论]第二章《算法基础》
- Choosing the right estimator
- 关于GDAL180中文路径不能打开的问题分析与解决
- 我爱天文 - 初级天文爱好者理想的天文望远镜是什么?
- 从 Java 代码到 Java 堆
- 一次对某韩国网站渗透记
- poj 3253(哈夫曼树priority_queue实现)
- kernel怎么知道是user还是system空间(ARM架构实现)
- Windows 64位环境的Java 服务配置 from iteye