(图源:大话数据结构)
好文分享:排序算法解析:https://blog.csdn.net/kexuanxiu1163/article/details/103051357
目录
0准备工作
保存排序内容的自定义结构体,其中顺序表的长度,不算哨兵(下标为零的部分)
#define MAX 10
typedef struct SqlistData
{
int r[MAX+1];//把r[0]空出来当哨兵或者临时变量
int length;//记录长度,因为0被空出来了,所以长度和下标此时统一了
}SqList;
交换接口
void swap(SqList * L,int i,int j)//交换
{
int temp = L->r[i];
L->r[i] = L->r[j];
L->r[j] = temp;
}
打印接口
void print(SqList * L)
{
qDebug()<<"开始打印";
for(int i = 1;i<=L->length;++i)
{
qDebug()<<L->r[i];
}
}
顺序表的储存结构如下:
零位下标什么也不储存,所以无论是遍历还是排序,都是从下标1开始,顺序表长度为5,小标和顺序表中的元素序号完全一致。
1归并排序
执行代码如下:
void MSort(int SR[],int TR1[],int s,int t)
{
int m;
int TR2[MAX+1];
if(s==t)
TR1[s] = SR[s];
else
{
m = (s+t)/2;
MSort(SR,TR2,s,m);
MSort(SR,TR2,m+1,t);
Merge(TR2,TR1,s,m,t);
}
}
接口要求的输入值:顺序表表头地址,起始元素下标,终点元素下标
典型的递归调用,下面举例说明程序是如何运行的:
此图没有显示出整理(Merge)的部分,只是展示出了分离(MSort)部分的递归调用规律
函数关键,在于起点和终点的输入,1,m 第一部分。m+1,End,第二部分,一直调用一直分割,知道最后分割成单个元素,然后返回,进行整理排序。
下面是书中解释:
MSort的作用:就是把顺序表进行分离
下面看看整理函数Merge
void Merge(int SR[],int TR[],int i,int m,int n)
{
int j,k,d;
for(j = m+1,k=i;i<=m&&j<=n;k++)//两个游标,
{
if(SR[i]<SR[j])
TR[k]=SR[i++];
else
TR[k]=SR[j++];
//谁小放谁
}
qDebug()<<"k"<<k<<"j"<<j<<"i"<<i<<"m"<<m<<"n"<<n;
//因为前后分成了两个部分,长度不一样,最后需要补回来
//
if(i<=m)//后半部分先结束,前半部分长,有剩余元素
{
for(d = 0;d<=m-i;d++)
TR[k+d]=SR[i+d];
}
if(j<=n)//前半部分先结束,后半部分长,有剩余元素
{
for(d=0;d<=n-j;d++)
TR[k+1]=SR[j+1];
}
}
整理程序再解析:
for(j = m+1,k=i;i<=m&&j<=n;k++)//两个游标,
{
if(SR[i]<SR[j])
TR[k]=SR[i++];
else
TR[k]=SR[j++];
//谁小放谁
}
用下面这张图最好理解:
递归到最后,其实就是两个数值比大小,不断返回的过程中,TR1和TR2的长度才不断累积
这一段很好理解,TR1和TR2自身都是有顺序的,此时需要的是TR1和TR2之间的排序
TR1的第i个,和TR2的第j个比较,谁小谁放到TR里面,自然,TR的序号是要不断累加的
如果TR1的第i个元素比较小,被选中放入了TR中,那么自然i累加,不能同一个位置上的元素使劲儿和之后的比较。
这段程序写的非常简练。
但是因为TR1和TR2的长度不一样而且比较也是非常随机的,万一TR1中的最大元素都比TR2中的小,TR1循环结束的时候
TR2还在第一个元素,此时就要停止循环,所以循环条件是TR1的游标和TR2的游标,都要小于末尾元素的序号;
跳出循环后,需要把没有插入的元素,插入到TR的后面,此时没有进入TR的元素一定都是数值较大的元素,直接在后面补上就行。
if(i<=m)//后半部分先结束,前半部分长,有剩余元素
{
for(d = 0;d<=m-i;d++)
TR[k+d]=SR[i+d];
}
if(j<=n)//前半部分先结束,后半部分长,有剩余元素
{
for(d=0;d<=n-j;d++)
TR[k+d]=SR[j+d];
}
此时再看这段程序 ,TR1剩余,进入第一段,TR2剩余,进入第二段
之后就是累计然后不断放入的过程了。
如果你仔细观察代码,看内存空间的使用,就会发现,分割其实什么都没有做,分割到最后,每个元素的编号和原来该元素在顺序表中的编号是一样的,分割,完全是为了后期的重新排序,排序才是真的关键。
这就是TR2,在MSort中存在的意义,相当于temp,临时储存原始变量。
2归并优化