链接列表和(字母)冒泡排序

时间:2014-11-23 02:24:09

标签: c sorting linked-list alphabetical

我遇到了使用链接列表进行冒泡排序的问题。我几个小时没有在我的简单代码中找到错误。你能看一下吗?

int listSort(node_t ** _list)
{
     int size = listSize(_list);

     for(int i = 0; i < size; i++)
     {
          node_t *pointer = *_list;

          for(int j = 0 ; j < size - 1; j++)
          {
               if(strcmp(pointer->title, pointer->next->title) > 0)
                    listSwapWithNext(_list, j);

               pointer = pointer->next;
          }
     }

     return 0;
}

和这里的交换功能(但似乎工作正常,因为我手动测试了所有边界情况):

int listSwapWithNext(node_t **_list, size_t first)
{
     node_t *pointer = *_list;
     node_t *ptr_b;
     node_t *ptr_c;
     node_t *ptr_d;

     if(!first)
          ptr_b = pointer;

     for(size_t i = 0; pointer->next->next; i++, pointer = pointer->next)
     {
          if(i == first - 1 || first == 0)
          {
               if(first)
                    ptr_b = pointer->next;

               ptr_c = ptr_b->next;
               ptr_d = ptr_c->next;

               if(first)
                    pointer->next = ptr_c;
               else
                    *_list = ptr_c;

               ptr_c->next = ptr_b;
               ptr_b->next = ptr_d;

               break;
          }
     }

     return 0;     
}

导致此崩溃(在第229行): It causes this crash (on line 229)

当我将sort函数中内部循环的condidition修改为:

for(int j = 0; j < size - 1 && pointer->next; j++)
为了防止从坏地址读取,我注意到了奇怪的事情。内循环somtimes运行时间比它应该少一次。

谢谢!

修改 这里有一个修改版的sort函数,在内部循环和我的调试指示器(用printf())中有防止条件:

int listSort(node_t ** _list)
{
     int size = listSize(_list);
     int i;
     for(i = 0; i < size; i++)
     {
          node_t *pointer = *_list;
          int j;
          for(j = 0 ; j < size - 1 && pointer->next; j++)
          {
               if(strcmp(pointer->title, pointer->next->title) > 0)
                    listSwapWithNext(_list, j);

               printf("# %d %d\n", i, j);
               pointer = pointer->next;
          }
          printf("\n");
     }

     return 0;
}

这是控制台中的结果。看,它并不是每个周期都做,所以它会给糟糕的排序带来好处。

enter image description here

EDIT2: 这是问题的根本所在。 http://pastebin.com/e5K6C1A2

仍然无法解决此问题。

2 个答案:

答案 0 :(得分:2)

在进行交换的情况下,

pointer = pointer->next不正确。如果您进行了互换,pointer应该保持pointer,因为它已经向前移动了一个元素。

编辑:我的意思是这样做:

if(strcmp(pointer->title, pointer->next->title) > 0)
    listSwapWithNext(_list, j);
else
    pointer = pointer->next;

答案 1 :(得分:0)

根据您的说法,我相信我可以帮助您识别代码中的一些问题。我相信您所描述的问题是由您发布的第一个代码块引起的,特别是此部分。

 for(int i = 0; i < size; i++)
     {
          node_t *pointer = *_list;

          for(int j = 0 ; j < size - 1; j++)
          {
               if(strcmp(pointer->title, pointer->next->title) > 0)
                    listSwapWithNext(_list, j);

               pointer = pointer->next;
          }

这条线引发了这个问题:

if(strcmp(pointer->title, pointer->next->title) > 0)

因为这里构造了内循环:

for(int j = 0 ; j < size - 1; j++)

所以你要考虑的事实是,因为我们交换,我们需要比列表的总大小少1。但问题是,这导致您尝试在最后一次运行时取消引用空指针。链表中的节点包含指向某些数据的指针和指向下一个对象的指针。所以让我们想象一下这个for循环执行的倒数第二次会发生什么。如果strcmp为真,它会进行交换,然后它会使指针前进以引用链接列表中的下一个元素。这是你出错的地方。因为你在我们再次执行循环时已经这样做了,所以这一行:

if(strcmp(pointer->title, pointer->next->title) > 0) 

具体到这一部分: pointer->next->title 将失败,因为当前对象是链接列表中的最后一个元素。因此,它的下一个指向NULL,并且您正在尝试获取NULL元素的标题对象,该元素不存在。

现在让我们看看你修改过的代码。

int listSort(node_t ** _list)
{
     int size = listSize(_list);
     int i;
     for(i = 0; i < size; i++)
     {
          node_t *pointer = *_list;
          int j;
          for(j = 0 ; j < size - 1 && pointer->next; j++)
          {
               if(strcmp(pointer->title, pointer->next->title) > 0)
                    listSwapWithNext(_list, j);

               printf("# %d %d\n", i, j);
               pointer = pointer->next;
          }
          printf("\n");
     }

     return 0;
}

您不会遭受同样的错误,但结果不正确。这不是由排序函数引起的,这也是由于for循环的构造引起的:

for(j = 0 ; j < size - 1 && pointer->next; j++)

只要指定的条件为真,就会执行for循环。再次让我们想象倒数第二次执行。我们在我们的大小范围内,所以第一个条件为真,并且在此之后存在另一个元素,因此第二个条件也是如此。循环运行并将指针前进到下一个元素。现在我们仍然在我们的大小限制范围内,所以这是真的,但在此之后列表中没有更多元素,因此pointer->nextNULL。这意味着循环不会运行,因此不会对所有数据进行排序,从而导致结果不佳。