一、算法描述
分治策略:将原问题划分n个规模较小而结构与原问题相似的子问题;递归地解决这些子问题,然后再合并其结果,得到原问题的解。字面上的解释就是“分而治之”。
- “分” 将问题分解为规模更小的子问题;
- “治” 将这些规模更小的子问题逐个击破;
- “合” 将已解决的子问题合并,最终得出“母”问题的解;
分治模式在每一层递归上都有三个步骤:
1、分解:将原问题分解成一系列子问题;
2、解决:递归地解各子问题。若子问题足够小,则直接求解;
3、合并:将子问题的结果合并成原问题的解。
MERGE(A, p, q, r)
n1 <- q - p + 1
n2 <- r-q
// creat arrays L[1..n1 + 1] and R[1..n2 + 1]
for i <- 1 to n1
do L[i] <- A[p + i -1]
for j <- 1 to n2
do R[i]<- A[q + j]
L[n1 + 1] <- “sentinel card” // 避免检测堆空, 引入“哨兵牌”。
R[n2 + 1] <- “sentinel card”
i <- 1
j <- 1
for k <- p to r
do if L[i] <= R[j]
then A[k] <- L[i]
i <- i + 1
else A[k] <- R[j]
j <- j + 1
合并排序(归并排序)算法完全依照上述模式:
1、分解:将n个元素分成各含n/2个元素的子序列;
2、解决:用合并排序法对两个子序列递归地排序;
3、合并:合并两个已排序的子序列以得到排序结构。
MERGE-SORT(A, p, r)
if p < r
then q <- [(p + r) / 2]
MERGE-SORT(A, p, q)
MERGE-SORT(A, q + 1, r)
MERGE(A, p, q, r)
二、算法实现(归并排序)
void Merge(int* pDataArray, int nLpos, int nRpos, int nRend)
{
const int MaxInt = 32767;
int i, j, n;
int nLeftLen = nRpos - nLpos + 1;
int nRightLen = nRend - nRpos;
int *pLArray = (int *)malloc( (nLeftLen + 1) * sizeof(int));
int *pRArray = (int *)malloc( (nRightLen + 1) * sizeof(int));
for (i = 0; i < nLeftLen; i++)
{
*(pLArray + i) = *(pDataArray + nLpos + i);
}
for (j = 0; j < nRightLen; j++)
{
*(pRArray + j) = *(pDataArray + nRpos + j + 1);
}
*(pLArray + nLeftLen) = MaxInt;
*(pRArray + nRightLen) = MaxInt;
i = 0;
j = 0;
for(n = nLpos; n <= nRend; n++)
{
if(*(pLArray + i) <= *(pRArray + j))
{
*(pDataArray + n) = *(pLArray + i);
i++;
}
else
{
*(pDataArray + n) = *(pRArray + j);
j++;
}
}
free(pLArray);
free(pRArray);
}
void MergeSort(int* pDataArray, int nLeft, int nRight)
{
int nMid;
if(nLeft >= nRight)
{
return ;
}
else
{
nMid = (nLeft + nRight) / 2;
MergeSort(pDataArray, nLeft, nMid);
MergeSort(pDataArray, nMid + 1, nRight);
Merge(pDataArray, nLeft, nMid, nRight);
}
}