在《算法导论》中还提到了合并算法,该算法采用分治法(divide-and-conquer)的思想。再次以整理扑克牌为例说明,当一堆杂乱无序的牌堆分为有序的两堆,比较两堆牌最上面的一张,按从小到大的方式合并起来,最后得到的一定是有序的,但由一堆无序的牌分为两堆时,所得到的仍旧是杂乱无序的,我们可以依次下去,直到最小的牌堆中只有一张牌时,此时是绝对有序的,然后依次合并,最后得到整理好的牌,这种算法称为合并算法。
在设计算法时,为了“监视”合并时纸牌不会“越界”,在每个牌堆末设置“哨兵(sentinel)”牌,其伪代码如下:
MERGE(A, p, q, r)
n1 = q - p + 1
n2 = r - q
L[n1+1], P[n2+1]
for i : 0 to n1-1
L[i] = A[p+i-1]
for j : 0 to n2-1
R[j] = A[q+j]
L[n1+1] = ∞
R[n2+1] = ∞
i = 0
j = 0
for k : p to r
if L[i] <= R[j]
A[k] = L[i]
i++
else
A[k] = R[j]
j++
给定一组实例,用C++实现合并算法如下:
#include
void MergeSort(int A[], int p, int q);
int main(void)
{
int A[20] = {5, 2, 4, 6, 1,
3, 15, 12, 14, 16,
11, 13, 8, 9, 7,
10, 18, 19, 17, 20};
int left = 20 / 2;
int right = 20 - left;
MergeSort(A, left, right);
for (int i = 0; i < 20; i++)
std::cout << A[i] << " ";
return 0;
}
void MergeSort(int A[], int p, int q)
{
int n1 = p;
int n2 = q;
int L[n1 + 1];
int R[n2 + 1];
for (int i = 0; i < n1; i++)
L[i] = A[i];
for (int i = 0; i < n2; i++)
R[i] = A[i + p];
L[n1] = 999;
R[n2] = 999;
if (n1 != 1)
{
int left = n1 / 2;
int right = n1 - left;
MergeSort(L, left, right);
}
if (n2 != 1)
{
int left = n2 / 2;
int right = n2 - left;
MergeSort(R, left, right);
}
int i = 0;
int j = 0;
for (int k = 0; k < p + q; k++)
{
if (L[i] <= R[j])
{
A[k] = L[i];
i++;
}
else
{
A[k] = R[j];
j++;
}
}
}
#include
void MergeSort(int A[], int p, int q);
int main(void)
{
int A[8] = {3, 41, 26, 52, 38, 57, 9, 49};
int left = 8 / 2;
int right = 8 - left;
MergeSort(A, left, right);
for (int i = 0; i < 8; i++)
std::cout << A[i] << " ";
return 0;
}
void MergeSort(int A[], int p, int q)
{
int n1 = p;
int n2 = q;
int L[n1 + 1];
int R[n2 + 1];
for (int i = 0; i < n1; i++)
L[i] = A[i];
for (int i = 0; i < n2; i++)
R[i] = A[i + p];
if (n1 != 1)
{
int left = n1 / 2;
int right = n1 - left;
MergeSort(L, left, right);
}
if (n2 != 1)
{
int left = n2 / 2;
int right = n2 - left;
MergeSort(R, left, right);
}
int i = 0;
int j = 0;
for (int k = 0; k < p + q; k++)
{
if (L[i] <= R[j])
{
A[k] = L[i];
i++;
while(i == n1 && j < n2)
A[++k] = R[j++];
}
else
{
A[k] = R[j];
j++;
while(j == n2 && i < n1)
A[++k] = L[i++];
}
}
}
除此之外,练习中还提到了一种排序算法,冒泡排序,其思路是依次比较相邻两个元素大小,符合筛选条件的交换位置,就好像吐泡泡一样,每次遍历从最末尾开始,结束时将最小或者最大的放到前面。给定一组实例,C++编程实现如下:
#include
int main(void)
{
int A[6] = {5, 3, 2, 4, 1, 6};
int temp= 0;
for (int i = 0; i < 6; i++)
{
for (int j = 5; j > i; j--)
{
if (A[j] < A[j - 1])
{
temp = A[j];
A[j] = A[j - 1];
A[j - 1] = temp;
}
}
}
for (int i = 0; i < 6; i++)
std::cout << A[i] << " ";
return 0;
}