修炼算法内功 归并排序(一)

内容:

  1. 归并排序算法思想
  2. 归并排序算法的实现
  3. 归并排序算法的优化

1、归并排序算法思想

对于给定的一串数组如:5、3、7、2、6、4、8、1

我们可以进行如下几个步骤:

  1. 将数组从中间分成两组数组——>5、3、7、26、4、8、1分别排序;
  2. 同样,我们可以继续拆分这两个数组为5、37、2以及6、48、1分别排序;
  3. 我们将想要排序的数组拆分再排序,就会形成循环,直到不能拆分为止。
  4. 排序完成后,再将排序完成后的数组合并。

分治法:将一个大的问题,分成若干个小的问题来处理,再将结果合并。

递归:在循环过程中,我们不断拆分数组本身,即不断调用递归函数。

递归到底:数组的长度是有限的,不断拆分后,数组就会拆分为只有一个元素时,数组就会无法拆分,递归结束。

算法分析:

2-路归并排序

两路归并:就是将两个有序表合并成一个有序表。即上述排序完成后,进行合并操作。

内容:对于数组我们给定三个指标:数组第一个元素first,中间元素mid,最后一个元素last。传入数组到函数是,我们就调用函数继续将[first,mid]和[mid+1,last]传入函数,即循环拆分数组,直到递归到底。然后,对拆分后数组进行排序合并。即:

扫描二维码关注公众号,回复: 2798161 查看本文章

template<typename T>
void mergeSort(T arr[],int first,int last)
{
    if (first >= last)//递归到底就结束
        return;
    int mid = (last + first) / 2;//取中间数,并向下取整
        //注意:传入的数组并不变,是传入的索引(参数)在不断变化
    mergeSort(arr,first,mid);//对左子序列进行归并排序
    mergeSort(arr,mid+1,last);//对右子序列进行归并排序
    merge(arr,first,mid,last);//归并
}

归并操作:——void merge(int arr[],int first,int mid,int last);

1)、对于两个数组合并,需要三个索引和一个辅助空间temp。即int i=first;用于访问第一个数组,int j=mid+1;用于访问第二个数组。k用来表示辅助空间temp的索引。

2)、同时,我们事先需要申明一块内存大小为last-first+1空间用来保存之前未拆分的数组(就是传入merge()函数的数组)即——

    int *temp = new int[last - first + 1];//申请一块辅助空间用来保存传入函数的数组arr中的数据
    for (int i = first;i <= last;i++)
    {
        temp[i - first] = arr[i];//将数组arr中i-first到last元素赋值给temp中,first为偏移量
    }

3)、从头逐一比较两个数组([firsr,mid]和[mid+1,last])之间大小,较小者存入数组arr中,i走完[firsr,mid],j走完[mid+1,last]就完成了合并操作。

int i = first, j = mid + 1;//创建索引:i表示数组[first,mid]索引,j表示数组[mid+1,last]数组的索引

    for (int k = first;k <=last;k++)//k指向数组中第一个元素
    {
        if (i > mid)//考虑到i越界
        {
            arr[k] = temp[j - first];
            j++;
        }
        else if (j > last)//考虑到j越界
        {
            arr[k] = temp[i - first];
            i++;
        }
        else if (temp[i - first] < temp[j - first])//注意:j是随着i相对变化的,偏移量也是first
        {
            arr[k] = temp[i - first];
            i++;
        }
        else 
        {
            arr[k] = temp[j-first];
            j++;
        }
    }

或者这么写:

//将有二个有序数列a[first...mid]和a[mid...last]合并。
void mergearray(int a[], int first, int mid, int last, int temp[])
{
    int i = first, j = mid + 1;
    int m = mid,   n = last;
    int k = 0;
    
    while (i <= m && j <= n)
    {
        if (a[i] <= a[j])
            temp[k++] = a[i++];
        else
            temp[k++] = a[j++];
    }
    
    while (i <= m)
        temp[k++] = a[i++];
    
    while (j <= n)
        temp[k++] = a[j++];
    
    for (i = 0; i < k; i++)
        a[first + i] = temp[i];
}
 

2、归并排序算法的实现

#include<iostream>
using namespace std;

//归并排序
template<typename T>
void MergeSort(T arr[],int n)
{
	mergeSort(arr,0,n-1);
}

template<typename T>
void mergeSort(T arr[],int first,int last)
{
	if (first >= last)//递归到底就结束
		return;
	int mid = (last + first) / 2;//取中间数,并向下取整
        //注意:传入的数组并不变,是传入的索引(参数)在不断变化
	mergeSort(arr,first,mid);//对左子序列进行归并排序
	mergeSort(arr,mid+1,last);//对右子序列进行归并排序
	merge(arr,first,mid,last);//归并
}

template<typename T>
void merge(T arr[],int first,int mid,int last)
{
	int *temp = new int[last - first + 1];//申请一块辅助空间用来保存传入函数的数组arr中的数据
	for (int i = first;i <= last;i++)
	{
		temp[i - first] = arr[i];//将数组arr中i-first到last元素赋值给temp中,first为偏移量
	}
	int i = first, j = mid + 1;//创建索引:i表示数组[first,mid]索引,j表示数组[mid+1,last]数组的索引

	for (int k = first;k <=last;k++)//k指向数组中第一个元素
	{
		if (i > mid)//考虑到i越界
		{
			arr[k] = temp[j - first];
			j++;
		}
		else if (j > last)//考虑到j越界
		{
			arr[k] = temp[i - first];
			i++;
		}
		else if (temp[i - first] < temp[j - first])//注意:j是随着i相对变化的,偏移量也是first
		{
			arr[k] = temp[i - first];
			i++;
		}
		else 
		{
			arr[k] = temp[j-first];
			j++;
		}
	}
}

int main()
{
	int a[] = { 3,8,4,7,2,1,5,6 };
	int len = sizeof(a) / sizeof(a[0]);
	cout << "排序前:";
	for (int i = 0;i < len;i++)
		cout << a[i] << " ";
	cout << endl;
	MergeSort(a,8);
	cout << "排序后:";
	for (int i = 0;i < len;i++)
		cout << a[i] << " ";
	cout << endl;
	system("pause");
	return 0;
}

精彩内容——>点击继续

猜你喜欢

转载自blog.csdn.net/Biubiuxin/article/details/81706245
今日推荐