改进链接列表的mergesort。怎么样?

时间:2010-11-27 13:26:40

标签: c linked-list mergesort

在我深入解释之前,您应该知道以下代码可能非常糟糕。我大约2个月前开始编程(那里和那里几个小时)。所以我缺乏经验,我的编码风格非常容易改进,我仍然怀念练习和很多(基础)知识。这也包括我用错误的名字调用东西:)。

我对算法(大学)感兴趣并希望练习一些指针处理(最初有一些问题)所以我决定使用单链接列表进行mergesort,看看与我的mergeSort算法相比它的表现如何教授(对数组进行排序)。不,这不是功课(我的大学课程(电气工程)都没有作业) - 这是我对算法,C和简单练习的理解的提高。


我的代码已经有效了。出于测试目的,我总是创建反向排序列表。对于像列表为NULL的情况,它仍然缺少一些东西。

所以在发布我正在使用的结构的代码之前:

struct list{
  int nbr;
  struct list *next_el;
};
typedef struct list LIST;
typedef LIST *z_LIST;

我有两个函数,mergeSort和merge。 mergeSort返回已排序(子)列表的新头,merge返回合并序列的头部。

现在我给mergeSort提供未排序列表的当前头部和元素数量。 然后它递归地分解列表(显然:))。 我不确定在下面的代码上说多少钱。如果事情不清楚,我会尽快回答并解释,但

z_LIST mergeSort ( z_LIST head, int length ) {

  int steps;
  int m = 0;
  z_LIST head1 = NULL, head2 = NULL, new_head = NULL;

if( length > 1) {

  m = (length+1)/2;


  head2 = head; 
  for(steps = 0; steps<m; steps++) {
    head2 = head2->next_el;
  }

  head1 = mergeSort(head, m);
  head2 = mergeSort(head2, length-m);

  new_head = merge(head1, head2, m, length-m);

  return new_head;

  } else {
    return head;
  }
}

merge接收两个子列表的头部(它们是一个元素或已经排序的序列)以及第一个和第二个列表的元素。

z_LIST merge (z_LIST head1, z_LIST head2, int l1, int l2)  {

  int i,j;
  z_LIST part1 = head1, part2 = head2;
  z_LIST temp_head = NULL, head = NULL;

/*First I let it check what the head of the new list is going to 
be and thus initiating the merging process with either i=1/j=0
or i=0/j=1.*/

  if(part1->nbr < part2->nbr){
    head = part1;
    if(part1->next_el != NULL)  {
      part1 = part1->next_el;
    }
    i=1;
    j=0;
  } else {
    head = part2;
    if(part2->next_el != NULL)  { //The last element of the original list points
      part2 = part2->next_el;     //to NULL. If I would then make part2 = NULL,
    }                             //then there wouldn't be part2->nbr ->lots
    i=0;
    j=1;
  }

  temp_head = head;

  while( (i<l1) || (j<l2) ) {
    if( ((part1->nbr < part2->nbr) && i<l1)||( j>=l2 ))  {
      temp_head->next_el = part1;
      part1 = part1->next_el;
      temp_head = temp_head->next_el;
      if (j>=l2)  { //If j>=l2 then I let merge add one more item of list1
       break;       //since list 1 is already sorted and linked correctly.
      }             //Same below. Should shave off some operations/time?
      i++;
    } else {
      temp_head->next_el = part2;
      part2 = part2->next_el;
      temp_head = temp_head->next_el;
      if (i>=l1)  {
        break;
      }
      j++;
    }
  }

  return head;
}

所以我欢迎任何关于我做了什么简单愚蠢的评论,在那里我没有考虑可能存在的问题,一些输入代码破坏代码或者如何做得更好,我确信还有一个相当多的改进可能性。提前谢谢。

1 个答案:

答案 0 :(得分:0)

排序合并阶段的“正常”结构是:

set output list to empty
while (list1 not empty && list2 not empty)
{
    if (list1->headvalue < list2->headvalue
        move head of list1 to output list
    else
        move head of list2 to output list
}
while (list1 not empty)
    move head of list1 to output list
while (list2 not empty)
    move head of list2 to output list

'move'操作包括更新指向列表中下一项的指针。

merge()函数中的结构有所不同。

要求对清单进行计数也是一种常规做法。通常,您可以使用'next is null'或'next is head'来确定列表的结尾,具体取决于列表是纯线性还是循环列表。