• 4. 归并排序


    一、基本思想

    对于一个待排序的序列,递归地将前半部分数据和后半部分数据各自归并排序,得到排序后的两部分数据,然后合并这两个部分。

    归并算法采用分而治之的策略:

           a. 将问题成一些小的问题然后递归求解;

      b. 将分的阶段解得的各个答案“修补”到一起。

    可以看到这种结构很像一棵完全二叉树,故我们可以采用递归来实现归并排序。

    二、分阶段可以理解为就是递归拆分子序列的过程

    由上图可知递归深度为logn,故其时间复杂度为O(logn)。

    三、治阶段可以理解为就是合并相邻有序子序列的过程

    我们需要将两个已经有序的子序列合并成一个有序序列。因为这两个输入子序列是有序的,所以若将输出放到第三个序列中时,则该算法可以通过对输入数据一趟排序来完成。即合并两个有序子序列的时间复杂度为O(n)。

    比如上图中的最后一次合并,要将[4,5,7,8]和[1,2,3,6]两个已经有序的子序列,合并为最终序列[1,2,3,4,5,6,7,8],下图为对应的实现步骤。

    四、代码

    /* 归并排序 */
    void MergeSort(int a[], int n)
    {
    	//在排序前,先建好一个长度等于原数组长度的临时数组,避免递归中频繁开辟空间
    	int *temp = new int[n];
    	sort(a, 0, n-1, temp);
    	delete []temp;
    } 
    
    void sort(int a[], int left, int right, int temp[])
    {
    	int mid;
    	if(left < right) {
    		mid = (left + right) / 2;
    		sort(a, 0, mid, temp);				// 左边归并排序,使得左子序列有序 
    		sort(a, mid + 1, right, temp);		// 右边归并排序,使得右子序列有序 
    		merge(a, left, mid + 1, right, temp);		// 将两个有序子数组合并 
    	}
    }
    
    void merge(int a[], int lPos, int rPos, int rightEnd, int temp[])
    {
    	int leftEnd = rPos - 1;						// 左边子序列的右端 
    	int tempPos = lPos;							// 临时数组的游标 
    	int elementNum = rightEnd - lPos + 1;		// 两个子序列拥有的总元素 
    	
    	// 合并两个子序列 
    	while(lPos <= leftEnd && rPos <= rightEnd) {
    		if(a[lPos] <= a[rPos])
    			temp[tempPos++] = a[lPos++];
    		else
    			temp[tempPos++] = a[rPos++];
    	}
    	while(lPos <= leftEnd)
    		temp[tempPos++] = a[lPos++];
    	while(rPos <= rightEnd)
    		temp[tempPos++] = a[rPos++];
    	// 拷贝到数组a中	
    	for(int i = 0; i < elementNum; ++i, --rightEnd)
    		a[rightEnd] = temp[rightEnd];
    }
    

      

  • 相关阅读:

    守护线程
    下载图片
    多线程
    self的作用
    设置项目地址环境
    对象 类
    ValueError: urls must start with a leading slash
    mock挡板接口开发
    K&R——第五章 指针与数组
  • 原文地址:https://www.cnblogs.com/xzxl/p/9581540.html
Copyright © 2020-2023  润新知