刚开始学习算法导论(第三版),目前打算把书上的伪代码转换成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 10000000
using 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;
}