您的位置:首页 > 其它

【算法导论】分治法及归并排序

2014-09-18 00:39 330 查看
有很多算法,在结构上他们是递归的:为了解决一个已经给定的问题,算法要一次或多次的递归调用其自身来解决相关的子问题,这类算法通常采用分治策略。

分治法的基本思想:

(1).原问题==(划分)== >>若干个更小规模的子问题。

(2).要求子问题的求解方法与原问题相同。

分治法的求解步骤:

(1)分解(Divide):将当前问题划分成若干子问题

(2)解决(Conquer):递归解子问题,如果子问题足够小则直接解

(3)合并(Combine):将子问题的解合并长原问题

分治法示例,归并排序:

/*
《Introduction to Algorithms(second edition)》
chapter2,MERGE_SORT()
date:2014-9-18
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>

#define MAX 50

typedef struct
{
int arr[MAX+1];
int length;
}SortArr;

SortArr *CreateSortArr()
{
int i = 0;
char buf[4*MAX] = "";
char *ptr = NULL;
SortArr *sortArr = (SortArr *)malloc(sizeof(SortArr));
memset(sortArr, 0, sizeof(SortArr));

printf("请输入待排序数据,以逗号分隔,以分号结束\n"
"例:23,12,65,36,35;\n"
"input:");
scanf("%s", buf);

ptr = buf;
sortArr->arr[i] = 0;	//arr[0]不存值用作哨兵单元
i = 1;
while(*ptr != ';')
{
sortArr->arr[i] = atoi(ptr);
i++;

ptr = strstr(ptr, ",");
if(!ptr)
{
break;
}
ptr++;
}
sortArr->length = (i - 1);

return sortArr;
}

int merge(int arr[], int p, int q, int r)
{
int i = 0;
int j = 0;
int k = 0;
int n1 = 0;
int n2 = 0;
int *leftArr = NULL;
int *rightArr = NULL;

n1 = q - p + 1;
n2 = r - q;

//为了和arr[]下标保持一致,leftArr[0]和rightArr[0]不用
leftArr = (int *)malloc((n1 + 2) * sizeof(int));
rightArr = (int *)malloc((n2 + 2) * sizeof(int));

for(i = 1; i <= n1; i++)
{
leftArr[i] = arr[p+i-1];
}
for(j = 0; j <= n2; j++)
{
rightArr[j] = arr[q+j];
}

i = 1;
j = 1;

//将最后一个数设置为哨兵
leftArr[n1+1] = INT_MAX;
rightArr[n2+1] = INT_MAX;

for(k = p; k <= r; k++)
{
if(leftArr[i] <= rightArr[j])
{
arr[k] = leftArr[i];
i++;
}
else
{
arr[k] = rightArr[j];
j++;
}
}

free(leftArr);
free(rightArr);
return 0;
}

int mergeSort(int arr[], int p, int r)
{
int q = 0;

if(p < r)
{
q = (p + r) / 2;
mergeSort(arr, p, q);
mergeSort(arr, (q+1), r);
merge(arr, p, q, r);
}

return 0;
}

int MergingSortRecursion(SortArr *sortArr)
{
mergeSort(sortArr, 1, sortArr->length);
return 0;
}

int PrintArray(SortArr sortArr)
{
int i = 0;

for(i = 1; i <= sortArr.length; i++)
{
printf("%d,", sortArr.arr[i]);
}
printf("\b;\n");

return 0;
}

int main()
{
SortArr *sortArr = NULL;
sortArr = CreateSortArr();

printf("\nBefore Sort:\t");
PrintArray(*sortArr);

MergingSortRecursion(sortArr);

printf("Sorted Array:\t");
PrintArray(*sortArr);

free(sortArr);

return 0;
}
时间复杂度分析:

在merge()函数中,第70行~77行的的for()循环所需要的时间O(n1+n2)=O(n),第86行~98行的for循环共有n轮迭代,其中每一轮迭代所需的时间都是常量,所以merge()函数的时间复杂度为O(n)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: