[算法导论]第二章《算法基础》

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



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值