一、归并排序
(1)基本思想:将两个或两个以上的有序表合并为一个新的有序表。
(2)延展:二路归并——将一个序列R[0,...n-1]看作成两个序列R[0,...mid]和R[mid+1,...n-1],利用递归思想,再将R[0,...mid]和R[mid+1,...n-1]序列各自划分成两个序列,直到序列中元素个数为1,再进行两两归并排序,直到得到一个长度为n的有序序列。
(3)每趟排序的有序区都是局部有序,直到归并完成,才能算归位。
(4)算法:
void Merge(Elemtype R[],int low,int mid, int high)
{
Elemtype *B=(Elemtype *)malloc((high-low+1)*sizeof(Elemtype)); //定义一个B数组存放排序前的元素
int i=low;
int j=mid+1;
int k;
for(k=low;k<=high;k++) //将R数组的元素移动到B数组中
B[K].key=R[k].key;
k=i;
while(i<=mid && j<=high) //如果某一个序列扫描完毕则跳出比较,剩余的序列直接添加在有序区后
{
if(B[i].key<=B[j].key) //比较谁更小,“=”确保稳定性
{
R[k].key=B[i].key;
i++; //注意i++是放在if语句里面的
}
else
{
R[k].key=B[j].key;
j++;
}
k++; //k++可放在里面当if和else语句中都得有
}
while(i<=mid) //剩余元素直接复制
R[k++].key=B[i++].key;
while(j<=high)
R[k++].key=B[j++].key;
}
void MergeSort(Elemtype R[],int low,int high)
{
if(low<high) //递归思想,将一个大序列,划分为n个小序列
{
int mid=(low+high)/2;
MergeSort(R,low,mid);
MergeSort(R,mid+1,high);
Merge(R,low,mid,high);
}
}
(4)算法分析:
空间复杂度:B数组——n,递归工作栈——log2n,取大——O(n)
时间复杂度:需要进行h-1次排序,每次排序比较n次,则O(nlog2n)
稳定算法。
二、基数排序(一般考手算)
(1)基本思想:通过分配和收集来排序,分为最低位优先和最高位优先。
(2)思想过程:
1.将待排序链表的关键字按要求划分成d位数字组成,每一位数字表示关键字的一位,且每位的值都在0<=d<=r之内,其中r称为基数。
2.分配:开始时把Q0,...Qr-1各个队列置空,依次扫描线性表中的每一个元素,如果元素aj的关键词kji=k,则把元素插入Qk中。
3.收集:将Q0,...Qr-1队列中元素依次首尾相接,得到新的元素序列,从而组成新的线性表。
4.总共需要进行d趟。
5.每趟排序的有序区都是局部有序,直到归并完成,才能算归位。
(3)算法:
typedef struct node
{
char data[MAXD];
struct node *next;
}NodeType;
void RadixSort(Nodetype *&p,int r,int d)
{
NodeTypee *head[MAXR],*tail[MAXR],*t;
int i,j,k;
for(i=0;i<=d-1;i++)
{
for(j=0;j<=r;j++)
head[j]=tail[j]=NULL;
while(p!=NULL)
{
k=p->data[i]-'0';
if(head[k]==NULL)
{
head[k]=p;
tail[k]=p;
}
else
{
tail[k]->next=p;
tail[k]=p;
}
p=p->next;
}
p=NULL;
for(j=0;j<=r;j++)
{
if(p==NULL)
{
p=head[j];
t=tail[j];
}
else
{
t->next=head[j];
t=tail[j];
}
}
t->next=NULL;
}
}
(4)算法分析:
时间复杂度:O(d(n+r))
空间复杂度:O(r)
稳定的排序方法。
三、错题总结
1.李春葆例题
2.王道选择题
(1)将两个各有n个元素的有序表合成一个有序表,最少比较次数为N(第一个有序表最大值比第二个有序表最小值小),最多比较次数为2n-1(两个有序表大小交替出现)。
(2)对数据文件进行排序,使用的方法是归并排序。