首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C语言 >

请教哪位高手熟悉链表的归并排序

2012-02-05 
请问谁熟悉链表的归并排序?下面是我参考的网上的一篇归并排序的讲解,然后根据讲解编了一个链表归并排序的

请问谁熟悉链表的归并排序?
下面是我参考的网上的一篇归并排序的讲解,然后根据讲解编了一个链表归并排序的的程序,但是有问题,所以请教大家。下面是所参考的文章,不知有错误否:

归并排序(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! ");
    &nbsp;&nbsp;&nbsp;while(i <=m&&j <=high)   //两子文件非空时取其小者输出到R1[p]上
              R1[p++]=(R.key <=R[j].key)?R[i++]:R[j++];
    &nbsp;&nbsp;&nbsp;while(i <=m)   //若第1个子文件非空,则复制剩余记录到R1中
              R1[p++]=R[i++];
    &nbsp;&nbsp;&nbsp;while(j <=high)   //若第2个子文件非空,则复制剩余记录到R1中
              R1[p++]=R[j++];
    &nbsp;&nbsp;&nbsp;for(p=0,i=low;i <=high;p++,i++)
              R=R1[p];//归并完成后将结果复制回R[low..high]
        }   //Merge

归并排序有两种实现方法:自底向上和自顶向下。

1、   自底向上的方法
(1)   自底向上的基本思想
    &nbsp;&nbsp;&nbsp;自底向上的基本思想是:第1趟归并排序时,将待排序的文件R[1..n]看作是n个长度为1的有序子文件,将这些子文件两两归并,若n为偶数,则得到   个长度为2的有序子文件;若n为奇数,则最后一个子文件轮空(不

参与归并)。故本趟归并完成后,前   个有序子文件长度为2,但最

后一个子文件长度仍为1;第2趟归并则是将第1趟归并所得到的   个有

序的子文件两两归并,如此反复,直到最后得到一个长度为n的有序文件为止。
    &nbsp;&nbsp;&nbsp;上述的每次归并操作,均是将两个有序的子文件合并成一个有序的子文件,故称其为 "二路归并排序 "。类似地有k(k> 2)路归并排序。

(2)   一趟归并算法
分析:
          &nbsp;在某趟归并中,设各子文件长度为length(最后一个子文件的长度可能小于length),则归并前R[1..n]中共有   个有序的子文件:R

[1..length],R[length+1..2length],…,   。
注意:
    &nbsp;&nbsp;&nbsp;调用归并操作将相邻的一对子文件进行归并时,必须对子文件的个数可能是奇数、以及最后一个子文件的长度小于length这两种特殊情况进行特殊处理:
  ①   若子文件个数为奇数,则最后一个子文件无须和其它子文件归并(即本趟轮空);
  ②   若子文件个数为偶数,则要注意最后一对子文件中后一子文件的区间上界是n。

具体算法如下:
        void   MergePass(SeqList   R,int   length)
    &nbsp;&nbsp;&nbsp;{   //对R[1..n]做一趟归并排序
          &nbsp;int   i;
          &nbsp;for(i=1;i+2*length-1 <=n;i=i+2*length)
          &nbsp;Merge(R,i,i+length-1,i+2*length-1);
                &nbsp;&nbsp;&nbsp;//归并长度为length的两个相邻子文件
          &nbsp;if(i+length-1 <n)   //尚有两个子文件,其中后一个长度小于length


                &nbsp;Merge(R,i,i+length-1,n);   //归并最后两个子文件
          &nbsp;//注意:若i≤n且i+length-1≥n时,则剩余一个子文件轮空,无须归并
    &nbsp;&nbsp;&nbsp;}   //MergePass

(4)二路归并排序算法
&nbsp;&nbsp;void   MergeSort(SeqList   R)
    &nbsp;{//采用自底向上的方法,对R[1..n]进行二路归并排序
    &nbsp;&nbsp;&nbsp;int   length;
    &nbsp;&nbsp;&nbsp;for(1ength=1;length <n;length*=2)   //做   趟归并

          &nbsp;&nbsp;&nbsp;MergePass(R,length);   //有序段长度≥n时终止
    &nbsp;}

下面是我根据上面的文章编的程序,在调试的时候,总是得不到预期的结果:

#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一下,学习学习

热点排行