请问谁熟悉链表的归并排序?
下面是我参考的网上的一篇归并排序的讲解,然后根据讲解编了一个链表归并排序的的程序,但是有问题,所以请教大家。下面是所参考的文章,不知有错误否:
归并排序(Merge Sort)
归并排序(Merge Sort)是利用 "归并 "技术来进行排序。归并是指将若干个已排序的子文件合并成一个有序的文件。
两路归并算法
1、算法基本思路
设两个有序的子文件(相当于输入堆)放在同一向量中相邻的位置上:R[low..m],R[m+1..high],先将它们合并到一个局部的暂存向量R1(相当于输出堆)中,待合并完成后将R1复制回R[low..high]中。
(1)合并过程
合并过程中,设置i,j和p三个指针,其初值分别指向这三个记录区的起始位置。合并时依次比较R和R[j]的关键字,取关键字较小的记录复制到R1[p]中,然后将被复制记录的指针i或j加1,以及指向复制位置的指针p加1。
重复这一过程直至两个输入的子文件有一个已全部复制完毕(不妨称其为空),此时将另一非空的子文件中剩余记录依次复制到R1中即可。
(2)动态申请R1
实现时,R1是动态申请的,因为申请的空间可能很大,故须加入申请空间是否成功的处理。
2、归并算法
void Merge(SeqList R,int low,int m,int high)
{//将两个有序的子文件R[low..m)和R[m+1..high]归并成一个有序的
//子文件R[low..high]
int i=low,j=m+1,p=0; //置初始值
RecType *R1; //R1是局部向量,若p定义为此类型指针速度更快
R1=(ReeType *)malloc((high-low+1)*sizeof(RecType));
if(! R1) //申请空间失败
Error( "Insufficient memory available! ");
while(i <=m&&j <=high) //两子文件非空时取其小者输出到R1[p]上
R1[p++]=(R.key <=R[j].key)?R[i++]:R[j++];
while(i <=m) //若第1个子文件非空,则复制剩余记录到R1中
R1[p++]=R[i++];
while(j <=high) //若第2个子文件非空,则复制剩余记录到R1中
R1[p++]=R[j++];
for(p=0,i=low;i <=high;p++,i++)
R=R1[p];//归并完成后将结果复制回R[low..high]
} //Merge
归并排序有两种实现方法:自底向上和自顶向下。
1、 自底向上的方法
(1) 自底向上的基本思想
自底向上的基本思想是:第1趟归并排序时,将待排序的文件R[1..n]看作是n个长度为1的有序子文件,将这些子文件两两归并,若n为偶数,则得到 个长度为2的有序子文件;若n为奇数,则最后一个子文件轮空(不
参与归并)。故本趟归并完成后,前 个有序子文件长度为2,但最
后一个子文件长度仍为1;第2趟归并则是将第1趟归并所得到的 个有
序的子文件两两归并,如此反复,直到最后得到一个长度为n的有序文件为止。
上述的每次归并操作,均是将两个有序的子文件合并成一个有序的子文件,故称其为 "二路归并排序 "。类似地有k(k> 2)路归并排序。
(2) 一趟归并算法
分析:
在某趟归并中,设各子文件长度为length(最后一个子文件的长度可能小于length),则归并前R[1..n]中共有 个有序的子文件:R
[1..length],R[length+1..2length],…, 。
注意:
调用归并操作将相邻的一对子文件进行归并时,必须对子文件的个数可能是奇数、以及最后一个子文件的长度小于length这两种特殊情况进行特殊处理:
① 若子文件个数为奇数,则最后一个子文件无须和其它子文件归并(即本趟轮空);
② 若子文件个数为偶数,则要注意最后一对子文件中后一子文件的区间上界是n。
具体算法如下:
void MergePass(SeqList R,int length)
{ //对R[1..n]做一趟归并排序
int i;
for(i=1;i+2*length-1 <=n;i=i+2*length)
Merge(R,i,i+length-1,i+2*length-1);
//归并长度为length的两个相邻子文件
if(i+length-1 <n) //尚有两个子文件,其中后一个长度小于length
Merge(R,i,i+length-1,n); //归并最后两个子文件
//注意:若i≤n且i+length-1≥n时,则剩余一个子文件轮空,无须归并
} //MergePass
(4)二路归并排序算法
void MergeSort(SeqList R)
{//采用自底向上的方法,对R[1..n]进行二路归并排序
int length;
for(1ength=1;length <n;length*=2) //做 趟归并
MergePass(R,length); //有序段长度≥n时终止
}
下面是我根据上面的文章编的程序,在调试的时候,总是得不到预期的结果:
#include "stdlib.h "
#include "stddef.h "
#include "string.h "
#include "ctype.h "
#include "stdio.h "
#include "math.h "
#include "assert.h "
struct LNode
{
int sequence;
int type;
union Lrange
{
char **c_range;
int *i_range;
double *d_range;
}Lrange;
int rangenum;
int n;
int flag;
struct LNode *next;
}LNode;
typedef struct LNode *Linklist;
int NodeNum(Linklist parentlist)
{/* 计算链表中的结点数目。该链表有头结点,计算结点数目时,将其略去 */
int i=0;
Linklist p;
p=parentlist-> next;
while(p)
{
i++;
p=p-> next;
}
return (i);
}
void Copy(struct LNode *node, Linklist parentdmp)
{/* 将结点拷贝到新建的已排序链表中 */
Linklist p;
struct LNode *q,*r;
p=parentdmp;
q=node;
printf( "call copy fuction.\n ");
r=(struct LNode *)malloc(sizeof(struct LNode));
assert(r!=NULL);
r-> sequence=q-> sequence;
r-> type=q-> type;
if (r-> type==0)
r-> Lrange.c_range=q-> Lrange.c_range;
else if ((r-> type==1))
r-> Lrange.i_range=q-> Lrange.i_range;
else
r-> Lrange.d_range=q-> Lrange.d_range;
r-> rangenum=q-> rangenum;
r-> n=q-> n;
r-> flag=q-> flag;
while(p-> next)
p=p-> next;
p-> next=r;
r-> next=NULL;
}
void Destory(Linklist parentlist)
{/* 将链表释放 */
Linklist p;
while (parentlist)
{
p=parentlist-> next;
free (parentlist);
parentlist=p;
}
}
void Merge(Linklist parentlist, int low, int mid, int high)
{/* 将两个有序链表归并成一个有序链表 */
int i,j,k;
int number;/* 该链表内的结点数量 */
Linklist p,q,r,tmp,parentdmp;
i=low;
j=mid+1;
number=NodeNum(parentlist);
p=q=r=tmp=parentlist-> next;
parentdmp=(Linklist)malloc(sizeof(struct LNode));
assert(parentdmp!=NULL);
parentdmp-> next=NULL;
for(k=1; k <=number; k++)
{
if(k==mid+1) q=tmp;/* 将q指向mid+1的位置 */
else if(k==high) r=tmp;/* 将r指向high的位置 */
tmp=tmp-> next;
}
printf( "q-> sequence=%d\tr-> sequence=%d\n ",q-> sequence,r-> sequence);
while(i <=mid && j <=high)/* 两文件链表非空时,
取其小者输出到parentdmp上 */
{
if(p-> sequence <= q-> sequence)
{
Copy(p,parentdmp);
p=p-> next;
i++;
}
else
{
Copy(q,parentdmp);
q=q-> next;
j++;
}
}
while(i <=mid)/* 若第1个链表非空,
则复制剩余结点到parentdmp中 */
{
Copy(p,parentdmp);
p=p-> next;
i++;
}
while(j <=high)/* 若第2个链表非空,
则复制剩余结点到parentdmp中 */
{
Copy(q,parentdmp);
q=q-> next;
j++;
}
p=parentlist;
q=parentlist-> next;
p-> next=parentdmp-> next;/* 将parentdmp的结点(头除外)连接到parentlist头结点 */
parentdmp-> next=NULL;
Destory(q);/* parentlist结点(头除外)释放 */
free(parentdmp);/* 将parentdmp头结点释放 */
}
void MergePass(Linklist parentlist, int length)
{/* 对parentlist做一趟归并排序,长度为length */
int i;
int number;
printf( "call mergepass fuction.\n ");
number=NodeNum(parentlist);
for (i=1; i+2*length-1 <=number; i=i+2*length)/* 归并长度为length的两个相邻子链表 */
Merge(parentlist,i,i+length-1,i+2*length-1);
if (i+length-1 <number)/* 尚有两个子链表,
其中后一个长度小于length */
Merge(parentlist,i,i+length-1,number);/* 归并最后两个子链表。
若i≤number且i+length-1≥number时,
则剩余一个子链表轮空,无须归并 */
}
void MergeSort(Linklist parentlist)
{
int length;/* 采用自底向上的方法,
对parentlist进行二路归并排序 */
int number;
printf( "call sort function.\n ");
number=NodeNum(parentlist);/* 求链表长度 */
for (length=1; length <number; length*=2)/* 有序子链表长度≥n时终止 */
MergePass(parentlist,length);
}
反复查找多次,但是无法发现问题的所在,请教大家,多谢了!
[解决办法]
template <class _II1, class _II2, class _OI> inline
_OI merge(_II1 _F1, _II1 _L1, _II2 _F2, _II2 _L2, _OI _X)
{for (; _F1 != _L1 && _F2 != _L2; ++_X)
if (*_F2 < *_F1)
*_X = *_F2++;
else
*_X = *_F1++;
return (copy(_F2, _L2, copy(_F1, _L1, _X))); }
看看STL的list,和algorithm
google一下,学习学习