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

原创 2014年09月18日 00:39:58

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

分治法的基本思想:

(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)。

相关文章推荐

【算法导论】2-2 二路归并排序(分治)merge-sort 和逆序对的问题

#include using namespace std; //二路排序算法,书p17 正确性证明见p18-19 void merge(int *b,int p,int q,int r) ...

算法导论学习:归并排序法的实现

上回学习了最简单也是最直接的插入排序。插入排序在小数据量时是很高效的,但是遇到大数据时,便显得无力了,今天来介绍归并排序,在大数据排序时,时间短,但同时它的空间使用率就显得高了。 第二章...

分治法算法——归并排序

分治法算法中的经典——归并排序上一节,我讲了分治法的相关思想,并贴出数字旋转方阵的代码以及解决思想。算法的话,主要还是要靠自己领悟,要多思考,不会再去看看别人的思路。以下,我分析一下分治法算法中的经典...

js算法:分治法-归并排序之合并有序数组

合并有序数组是合并排序重要的一步,下面js演示了每一步的操作过程  附代码: js合并有序数组 table,td{ bord...
  • jrn1012
  • jrn1012
  • 2015年08月22日 22:52
  • 2213

算法-分治法非常典型的应用之归并排序模拟与分析

归并排序的过程您了解吗?本文模拟了归并排序的过程,带有清楚的归并排序示意图。...

分治法 归并排序(递归算法)

当待排序的序列长度为1,递归“开始回升”,在这种情况下不要做任何工作,因为长度为1的每个序列都以排好序。分解—>解决—>合并#include using namespace std; int MERG...

js算法:分治法-归并排序

归并排序(合并排序)是一个递归算法,这个算法的理解其实可以借助下面这个图: 对于原始的数组2,1,3,8,5,7,6,4,10,在整个过程执行的是顺序是途中红色编号1-20。虽然我们描述中说的是程序...
  • jrn1012
  • jrn1012
  • 2015年08月23日 17:30
  • 1989

【算法】分治法之归并排序实现

所谓分治:分而治之,中华民族智慧的结晶。对其联盟,使其分裂而利于各个击破;对其国使用,使其国分裂而利于控制;对其公司使用,使其公司分裂而利于控制;对其团队使用,使其团队分裂而利于控制。可见,分治法被运...
  • tww85
  • tww85
  • 2016年11月03日 12:17
  • 220

排序算法之归并排序(分治法排序)

算法思想:将一个数列划分为较小的部分,并使每一部分有序,然后将这些较小的有序部分合并。                   下面实现,二路归并排序。 C#实现: /// ...
  • chthq
  • chthq
  • 2012年09月20日 15:16
  • 1018
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【算法导论】分治法及归并排序
举报原因:
原因补充:

(最多只允许输入30个字)