翻开算法导论的第一章,可以算作是基本介绍吧,第二章开始介绍算法,本以为最开始会介绍冒泡排序。。。哈哈哈,结果很尴尬,最先介绍的就是今天要讲的第一个算法,
插入排序一个非常形象的例子就是扑克牌的插入,我们每次拿起一张新牌时,总是可以插入到合适的位置,因此可以将他的处理方式总结为每次拿起新牌时,从左开始向右依次比较,直至有牌比新的牌要小,则将牌插入到这张比它小的牌的后面,依次插入完所有的牌,那么排序也就完成了。插入排序的伪代码如下:
INSERITION_SORT(A)
1 for j = 2 to A.length
2 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 A[i+1] = A[i]
7 i = i-1
8 A[i+1] = key
根据伪代码可以很方便地写出对应的C++代码如下:
//chapter2 插入算法
//插入排序将result数组进行排序
//输入:数组以及数组的元素个数,操作对象为数组result
//输出:无,只是对result进行排序
//insertion
void Isort::insertion_sort(int result[],int c)
{
int key,i,arraycount;
arraycount = c;
if(arraycount > 1)
{
for(int j = 1; j1;
while(i >= 0 && result[i] > key)
{
result[i+1] = result[i];
i--;
}
result[i+1] = key;
}
}
else
{
}
}
注意:伪代码中的下标是从1开始的,而我们在实际中操作数组时是从下标0开始的,因此在while的判断条件时伪代码是大于0,而C++代码中是大于等于0。
插入算法介绍完之后再介绍另一种算法,分治算法,这一算法虽然不是很出色,但是他的思想是很棒的,就是将一个大问题分解成两个类似于大问题的小问题,通过递归的思想来一步一步的求解,分治算法的伪代码如下:
MERGE_SORT(A,p,r)
1 if p < r
2 q = []{(p+r)/2} //表示不大于(p+r)/2的最大整数
3 MERGE_SORT(A,p,q)
4 MERGE_SORT(A,q+1,r)
5 MERGER(A,p,q,r)
其中合并函数的伪代码如下:
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 L[i] = A[p+i-1]
6 for j = 1 to n2
7 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 A[k] = L[i]
15 i = i+1
16 else
17 A[k] = R[j]
18 j = j+1
根据伪代码写出对应的C++代码如下:
//chapter2 分治算法
//分治法排序,采用分治法对数组进行排序
//输入:数组a,数组a的第一个元素的坐标p,最后一个元素的坐标r
//输出:无,操作后数组a为已经排列好的数组
//merge
void Isort::merge_sort(int a[], int p, int r)
{
if(pint q = (p+r)/2;
merge_sort(a,p,q);
merge_sort(a,q+1,r);
merge(a,p,q,r);
}
}
//合并算法:在使用分治算法时需要调用的合并算法
//输入:数组a,元素下表p,q,r
//输出:无,功能是将数组a中排好序的两部分合二为一
void Isort::merge(int a[], int p, int q, int r)
{
int n1,n2,i,j,k;
int *L,*R;
n1 = q - p + 1;
n2 = r - q;
L = (int *)malloc((sizeof(int))*n1);
R = (int *)malloc((sizeof(int))*n2);
for(i = 0 ; i < n1 ; i++)
{
L[i] = a[p+i];
}
for(i = 0 ; i < n2 ; i++)
{
R[i] = a[q+i+1];
}
i = 0;
j = 0;
for(k = p ; k < r+1 ; k++)
{
if((L[i] <= R[j] && i < n1) || (j >= n2))
{
a[k] = L[i];
i = i+1;
}
else
{
a[k] = R[j];
j = j+1;
}
}
free(L);
free(R);
}
需要注意的一点是在伪代码中放置了哨兵牌,即最后一张牌的大小是无穷大,然而在实际的代码中我们无法完成这一功能,因此可以根据i与n1的关系以及j与n2的关系来判断是否其中的一个数组已经全部合并完成,注意if的判断条件应该要怎么写。
到此为止,插入排序与分治算法的代码介绍完毕。