【郭炜老师】【分治】1.归并排序

分治概念:

            把一个任务分成更小的相同的小任务(一般分成两个),然后先处理小的任务,最后在综合处理大的任务即可完成任务。

举例:

            有16枚硬币,只有1个假币,且重量比较轻。问最短需要多少次能找到假币?

解析:

           如果我们用1-1测试的方法。需要8次才能测完。但是如果8-8的测试呢?

           8-8,则若有假币,必定有一方倾斜,对翘起的一方继续测量。

           4-4

           2-2

           1-1

           只需要经过4次,就可以找到那枚硬币,是不是很简单呢?这就是分治的思想之一。

------------------------------------------------------------------------------------------------------------------------------------

但是我们再说下本轮的重点,归并排序:

 

归并排序的思想:

           1.把前一段排序

           2.把后一段排序

           3.把两半归并到一个新的有序数组。然后再拷贝回原数组,排序完成。

           (前一段排序和后一段排序依旧是同样的过程,显然这是一个递归的过程)

           那么递归的结束时刻是哪呢?即归并的起点和终点相同时,显然代表只有一个数,那么它本身就是有序的,直接返回即可。

复杂度:

           时间复杂度O(nlogn):推导过程。

           空间复杂度O(N):

                      因为需要一个tmp数组来存放排序好的数,然后赋值给本身。

如何排序:

           思想了解了,我们思考如何对排序好的2段数进行归并:假设有2个已排序好的数组a和b,则可以

           1.设置两个指针变量p0和p1。p0指向数组a,p1指向数组b。同时需要一个tmp数组用来存放排序好的数。用指针pb指向首部。

           2.判断两个指针指向变量的值的大小,小的则将其赋值到tmp,同时它相对的指针向后移动。

           当两段数组中的一个赋值完成,则剩下的一段直接赋值过去即可。(这里假设a赋值完成,则将b数组直接赋值过去)

while(i<=s)
    tmp[pb++] = b[p1++];

 

归并过程1

 

 

归并过程2

附上全部代码:

1.解释版: 

#include <iostream>
using namespace std;

void Merge(int a[],int s,int m,int e,int tmp[])
{
    //将数组a的局部a[s,m]和a[m+1,e]合并到tmp,并保证tmp有序
    //然后再拷贝回a[s,e]
    //归并操作时间复杂度:O(e-s+1),即O(n)
    int pb = 0;//pb指向额外的数组tmp
    int p1 = s,p2 = m+1;//p1指向前一个指针,p2指向后一个指针
			//标记1:我这里些错过1会,写成了p2 = m,出错,自己思考下,应该是m+1.如果填的是m,则顺序只能与原来相同,不会改变。
    while( p1 <= m && p2 <= e){//两者都没有走到头
            if( a[p1] < a[p2])
                tmp[pb++] = a[p1++];
            else
                tmp[pb++] = a[p2++];
    }
    //有一半走到头了,直接把另一半直接拷过去
    while( p1 <= m)
        tmp[pb++] = a[p1++];
    while( p2 <= e)
        tmp[pb++] = a[p2++];
    //把排序好的tmp数组赋值到a数组中
    for(int i=0;i<e-s+1;++i)
        a[s+i] = tmp[i];
	//标记2:我原来写成了a[i] = tmp[i];应该写成a[s+i],即把归并后的数放到原来的位置在进行新的归并。
}

//a数组,对s到e进行排序,依靠额外的数组tmp
void MergeSort(int a[],int s,int e,int tmp[])
{
    //如果s = e,就是这个数本身,不用排序,直接返回
    if( s < e){
        int m = s + (e-s)/2;
        MergeSort(a,s,m,tmp);
        MergeSort(a,m+1,e,tmp);
        Merge(a,s,m,e,tmp);
    }
    else return;//else return这句话是我自己加的,加了更容易理解,这是他的递归结束条件。不加程序也能运行
}

int a[10] = { 13,27,19,2,8,12,2,8,30,89};
int b[10];
int main()
{
    int size = sizeof(a)/sizeof(int);
    //对数组a的0~size-1位置进行归并排序,并依靠一个额外的数组b
    MergeSort(a,0,size-1,b);
    for(int i=0;i<size;++i)
        cout << a[i] << ",";
    cout << endl;
    return 0;
}

2.套用版:

#include <iostream>
using namespace std;

void Merge(int a[],int s,int m,int e,int tmp[])
{
    int pb = 0;
    int p1 = s,p2 = m+1;
		
    while( p1 <= m && p2 <= e){
            if( a[p1] < a[p2])
                tmp[pb++] = a[p1++];
            else
                tmp[pb++] = a[p2++];
    }

    while( p1 <= m)
        tmp[pb++] = a[p1++];
    while( p2 <= e)
        tmp[pb++] = a[p2++];

    for(int i=0;i<e-s+1;++i)
        a[s+i] = tmp[i];	
}

//a数组,对s到e进行排序,依靠额外的数组tmp
void MergeSort(int a[],int s,int e,int tmp[])
{
    if( s < e){
        int m = s + (e-s)/2;
        MergeSort(a,s,m,tmp);
        MergeSort(a,m+1,e,tmp);
        Merge(a,s,m,e,tmp);
    }
}

int a[10] = { 13,27,19,2,8,12,2,8,30,89};
int b[10];
int main()
{
    int size = sizeof(a)/sizeof(int);
    MergeSort(a,0,size-1,b);

    for(int i=0;i<size;++i)
        cout << a[i] << ",";
    cout << endl;
    return 0;
}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值