Introduction to Algorithms
1.Insertion Sort(插入排序)
伪代码如下:
c++代码实现:
#include<iostream>
#include<vector>
using namespace std;
void insert_sort(vector<int>& a)
{
for(int j=1;j<a.size();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()
{
vector<int> a;
a.push_back(3);
a.push_back(1);
a.push_back(2);
a.push_back(4);
a.push_back(5);
insert_sort(a);
for(int i=0;i<a.size();i++)
cout<<a[i]<<endl;
}
算法实现细节:
2.循环不变式
- A technique for proving that an algorithm is correct.Identify a
loop-invariant(循环不变式)
Initialization(初始化):
循环的第一次迭代之前,它为真。Maintenance(保持):
如果循环的某次迭代之前它为真,那么下次迭代之前,它仍为真。Termination(终止):
在循环终止时,不变式为我们提供一个有用的性质,该性质有助于证明算法是正确的。
让我们来看看对于插入排序如何证明这些性质成立:
3.Analysis algorithms
- 分析算法的结果意味着预测算法需要的资源,虽然有时我们主要关心像
memory(内存)、communication bandwidth(通信带宽)、computer hardware(计算机硬件)
等。 - 但通常我们想度量的是
computational time(计算时间)
。
n:执行n-1次,终止时还需执行一次判断。
最佳情况有tj=1。
最坏情况有tj=j。(因为逆序,所以每次都需j次)
最坏与平均情况分析:
- 一个算法的最坏情况运行时间给出了任何输入的运行时间的一个上界。
- 对某些算法,最坏情况经常出现。
- 平均情况往往与最坏情况大致一样差。
4.Order of Growth(增长量级)
只考虑公式中最重要的项,因为当n的值很大时,低阶项相对来说不太重要。
5.Divide-and-Conquer(分治法)
分治模式在每层递归时都有三个步骤:
- 分解原问题为若干子问题。
- 解决这些子问题,递归地求解各子问题。
- 合并这些子问题的解成为原问题的解。
6.Merge Sort Algorithm(归并排序)
归并排序完全遵守分治模式:
- 分解:分解待排序的n个元素的序列成各具n/2个元素的两个子序列。
- 解决:使用归并排序递归地排序两个子序列。
- 合并:合并两个已排序的子序列以产生已排序的答案。
MERGE-SORT:
MERGE:
代码实现如下:
#include<iostream>
using namespace std;
void merge(int A[],int p,int q,int r){
int n1=q-p+1;
int n2=r-q;
int L[n1+1],R[n2+1];
int i,j;
for(i=0;i<n1;i++)
L[i]=A[p+i];
for(j=0;j<n2;j++)
R[j]=A[q+j+1];
L[n1]=100000;
R[n2]=100000;
i=0;j=0;
for(int k=p;k<=r;k++)
{
if(L[i]<=R[j])
{
A[k]=L[i];
i++;
}
else{
A[k]=R[j];
j++;
}
}
}
void merge_sort(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);
}
}
int main()
{
int a[8]={5,2,4,7,1,3,2,6};
merge_sort(a,0,7);
for(int i=0;i<8;i++)
cout<<a[i]<<endl;
system("pause");
}
原理解释如下:
7.分析分治算法
把原问题分解成a
个子问题,每个子问题的规模是原问题的1/b
。n<=c
代表问题规模足够小;D(n)
代表分解问题成为子问题需要的时间;C(n)
代表合并子问题的解成为原问题的解需要的时间。
归并算法的分析:
总代价可用递归树(Recursion Tree)
进行分析:
-
初始化:
-
递归代换一次:
-
递归代换两次:
-
最终结果: