你好!归并排序!

算法:归并排序

时间复杂度:nlog(n)                原理:我不知道

空间复杂度:我不知道                原理:我不知道

重难点:

        理解好临时数组temp的作用:是把有序的数据覆盖回原先的数组(后面详细说明)

代码(c++):

源码:

#include <bits/stdc++.h>

using namespace std;

const int N=1e5+10;

int a[N],temp[N];

void quick_sort(int q[],int l,int r)
{
	if(l>=r) return ;
	
	int mid = l + r>>1;
	
	quick_sort(q, l, mid), quick_sort(q, mid + 1, r);
	
	int i = l, j= mid + 1, k = 0;
	
	while(i <= mid && j <= r)	
		if(q[i] <= q[j]) temp[k++] = q[i++];
		else temp[k++] = q[j++];
	
	while(i<=mid)temp[k++] = q[i++];
	while(j<=r)temp[k++] = q[j++];
	
	for(i=l,j=0;i<=r;i++,j++)q[i] = temp[j];
	
 } 
int main()
{
	int x;
	
	cin>>x;
	
	for(int i=0;i<x;i++) cin>>a[i];
	
	quick_sort(a,0,x-1);
	
	for(int i=0;i<x;i++) cout<<a[i]<<" ";
	
	return 0;
 } 


注释码:

#include <bits/stdc++.h>

using namespace std;

const int N=1e5+10;//const是关键字,修饰一个变量后,这个变量的值就不能在后文中发生任何修改
                   //比如 const int  a=1;那么a++就是错的
                   //static也是一个关键字,修饰一个变量后,这个变量的数值会永久改变,常用于
                   //函数运行后希望保持改变后的数值;
                   //比如static int a=1;a++之后,a==2;这个值未发生改变时是永久性的。
int a[N],temp[N];

void quick_sort(int q[],int l,int r)
{
	if(l>=r) return ;//当递推到只有一个元素时,那就没办法排序(或者说是不用排序),就返回
	
	int mid = l + r>>1;//'>>'位运算,表示'/2'(除2)一次;同理'<<1'表示'*2'一次;而'>>2'表                                
                       //示/2两次(/4);
	
	quick_sort(q, l, mid), quick_sort(q, mid + 1, r);//如果不是单个元素,那就死命分
	
	int i = l, j= mid + 1, k = 0;//因为最后一次的时候会在本函数的第一条语句返回,所以执行这句                                            
                                // 话的必然是最后一个递推的前面的函数(倒数第二,三, 
                                //四。。。。。次);
                                 //之所以强调倒数第几次,是因为后面就直接当作排完序进行存储和        
                                  //覆盖操作了。看不懂的先看看文末说明,再回来看代码。
	
	while(i <= mid && j <= r)//用临时数组temp存储有序的(部分)元素,把小的放前面,大的放后面
		if(q[i] <= q[j]) temp[k++] = q[i++];//    为什么不用括号?if/else天生一对。
		else temp[k++] = q[j++];
	
	while(i<=mid)temp[k++] = q[i++];//防止有某一半的存完了,但是另一半的还没存完,那就说明没 
                                   //存的部分比存完的那部分的最后一个都大,那就只要单独对没存 
                                   //完数据放到temp后面;
	while(j<=r)temp[k++] = q[j++];//因为上文说的是(i <= mid && j <= r);所以录取后当j==但是        
                                    //i<r是,可能存在q[j]<q[i],所以temp录取了q[j];那么这        
                                     //时候j++了,j就>r了;所以也不用写说明if/else。
	
	for(i=l,j=0;i<=r;i++,j++)q[i] = temp[j];//开始覆盖,不懂得看文末
	
 } 

int main()
{
	int x;
	
	cin>>x;
	
	for(int i=0;i<x;i++) cin>>a[i];
	
	quick_sort(a,0,x-1);
	
	for(int i=0;i<x;i++) cout<<a[i]<<" ";
	
	return 0;
 } 

下面是对为什么执行完“quick_sort(q, l, mid), quick_sort(q, mid + 1, r);”  语句就完成了排序的详细说明

误区:

①真的以为就是执行了  quick_sort(q, l, mid), quick_sort(q, mid + 1, r); 这一条完成了排序。

②没有理解到  元素所在位置  和  元素的值  不是绑死的

不是只有定义成指针的变量才能充当指针的作用,函数中的i,j就是充当着指针的作用!只不过它们记录的是数组下标。

写的很琐碎,建议自己拿纸笔画图试试

假设:  q[0]=7   q[1]=5   q[2]=76  q[3]=99  q[4]=123

先运行第一次quick_sort(q, l, mid), quick_sort(q, mid + 1, r);

下面我都用大括号表示分块了

那么数据就被分为两块
{ q[0]=7   q[1]=5   q[2]=76 }         { q[3]=99  q[4]=123 }

第二次运行quick_sort(q, l, mid), quick_sort(q, mid + 1, r);

那么数据被分为四块
{ q[0]=7   q[1]=5 }   {  q[2]=76 }  { q[3]=99 }  { q[4]=123 }

前面说过了,只有一个元素的会被返回,所以这里就只剩下{ q[0]=7   q[1]=5 }要分,其他的我省略

第三次运行quick_sort(q, l, mid), quick_sort(q, mid + 1, r);
{ q[0]=7 }       { q[1]=5 } 

然后这两个因为也是一个元素,也被返回了;

怎么理解返回?其实就是把之前分开后变成单个的那一步拿回来。
也就是
{ q[0]=7 }       { q[1]=5 }    回归变成了       { q[0]=7   q[1]=5 } 

但是这里的!!!!表示!!!发生了变化,原先左侧的块用i表示地址(下标),右侧的用j表示地址(下标)

所以在下面这个代码中,才会有i,和j的拆分
while(i <= mid && j <= r)	
		if(q[i] <= q[j]) temp[k++] = q[i++];
		else temp[k++] = q[j++];

这个时候i表是q[0]=7的下标0,(即i==0)
同理,j表是q[1]=5的下标1,(即j==1)

所以代码运行后temp[0]==5;
             temp[1]==7;

之后还有两个细节while:
    while(i<=mid)temp[k++] = q[i++];
	while(j<=r)temp[k++] = q[j++];
之后再说,这里用不到。


然后运行最后一个语句
        for(i=l,j=0;i<=r;i++,j++)q[i] = temp[j];
这里的i=l其实是l=0,因为这里是最左边的递归块,要是再中间的位置,那l也要应当是最左侧的地址。

这个语句使得(//原先q[0]==7,q[1]==5)
    q[0]=5
    q[1]==7

之后又从
!!!!{ q[0]=7   q[1]=5 }   { q[2]=76 }
!!!!                回归到了
!!!!                            { q[0]=5   q[1]=7   q[2]=76 }  
!!!!   !!!!!注意!!!!!!!!
!!!!                这里就是由于第一次回归,使得前两个位置的元素发生了改变
!!!!                同样的,这里的下标表示也是发生了改变(i==0,j==2)

然后运行while:
while(i <= mid && j <= r)	
		if(q[i] <= q[j]) temp[k++] = q[i++];
		else temp[k++] = q[j++];
!!!!!!!!!!!!怕没看到,每使用一次j或i,都会让其值自加一次!!!!!!!
因为
        q[i(i==0)]=5 < q[j(j==2)]=76
    所以temp[0]==q[i(i==0)]=5     //用了一次i,所以i自加了,所以后面的i==1而不是i==0
同理
        q[i(i==1)]=7 < q[j(j==2)]=76
    所以temp[i(i==1)]==q[i(i==1)]=7;//用了一次i,所以i自加了,所以后面的i==2而不是i==1


这个时候i==2了,不满足while(i <= mid && j <= r)	的i<mid(mid==1)
        但这个时候q[j(j==2)]=76还没有录用,怎么办?

这时候就是两个while的细节作用
    while(i<=mid)temp[k++] = q[i++];//不满足,直接掠过
	while(j<=r)temp[k++] = q[j++];//满足,赋值(覆盖)

这个时候
        temp[0]==5 
	    temp[1]==7
        temp{2]==76

然后,再次进行最后一个语句
            for(i=l,j=0;i<=r;i++,j++)q[i] = temp[j];
所以
        q[0]==5 
	    q[1]==7
        q{2]==76

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值