简体   繁体   English

C中链接列表的快速排序

[英]Quicksort of Linked List in C

Okay guys, after no success with gdb and valgrind, I humbly present my question to you. 好的,在使用gdb和valgrind失败之后,我谦虚地向您提出了我的问题。 We were asked to implement a version of a quicksort in c, using the first element of the list as the pivot (to maintain comparability with a simple haskell implementation we did earlier in the semester). 我们被要求使用列表中的第一个元素作为枢纽,以c语言实现quicksort的版本(以保持与本学期早些时候完成的简单haskell实现的可比性)。 The LIST implementation was provided (make, print, and the structure definition), the rest is up to us. 提供了LIST实现(制作,打印和结构定义),其余的工作由我们决定。 I am (surprise, surprise) receiving a segfault, but valgrind is turning up a HUGE number of errors as well as a stack overflow, so maybe some fresh eyes can help me. 我(感到惊讶)感到异常,但是valgrind出现了大量错误以及堆栈溢出,因此也许有些新鲜的眼睛可以对我有所帮助。

My code: 我的代码:

    #include <stdio.h>
#include <stdlib.h>

typedef struct CELL *LIST;
struct CELL {
    int element;
    LIST next;
};


LIST MakeList();
void PrintList(LIST);
LIST qSort(LIST);
int listLength(LIST);
LIST combine(LIST, LIST, LIST);


int main(){
   LIST list;
    printf ("enter a several numbers separated by spaces or returns and ended by Ctrl-D\n");
    list = MakeList();
    PrintList(qSort(list));
   return 0;
}

LIST qSort(LIST list){
   LIST current, pivot = list, temp = NULL;//use first element as pivot, start comparison at list->next
   LIST little, big, littleHead, bigHead;
   little = (LIST) malloc(sizeof(struct CELL));
   little->element = 0;
   little->next = NULL;
   littleHead = little;
   big = (LIST) malloc(sizeof(struct CELL));
   big->element = 0;
   big->next = NULL;
   bigHead = big;

   if(listLength(list) <= 1){//base case
      return list;
   }
//remove pivot by setting current to list->next
   current = list->next;

   do{
      if(current->element <= pivot->element){
         little->element = current->element;
         little->next = (LIST) malloc(sizeof(struct CELL));
         little = little->next;
         little->next = NULL;
      }
      else{
         big->element = current->element;
         big->next = (LIST) malloc(sizeof(struct CELL));
         big = big->next;
         big->next = NULL;
      }

      current = current->next;
   }while(current != NULL);

   littleHead = qSort(littleHead);
   bigHead = qSort(bigHead);

   return combine(littleHead, bigHead, pivot);
}

int listLength(LIST list){
   int length = 0;
   LIST current = list;
   if(NULL==list){
      return length;
   }
   else{
      while(current != NULL){
         current = current->next;
         length++;
      }
   }
   return length;
}



LIST combine(LIST little, LIST big, LIST pivot){
   LIST temp = little;
   while(temp->next != NULL){
      temp = temp->next;
   }
   temp->next = pivot;
   pivot->next = big;
   return little;
}

LIST MakeList()
{
    int x;
    LIST pNewCell;

    if (scanf("\%d", &x) == EOF) return NULL;
    else {
        pNewCell = (LIST) malloc(sizeof(struct CELL));
        pNewCell->next = MakeList();
        pNewCell->element = x;
        return pNewCell;
    }
}

void PrintList(LIST list)
{
    while (list != NULL) {
        printf("\%d\n", list->element);
        list = list->next;
    }
}

And the valgrind output 和valgrind输出

==20391== Conditional jump or move depends on uninitialised value(s)
==20391==    at 0x804855D: qSort (2100assignment4.c:45)
==20391==    by 0x80485E0: qSort (2100assignment4.c:61)
==20391==    by 0x80484BD: main (2100assignment4.c:22)
==20391==  Uninitialised value was created by a heap allocation
==20391==    at 0x402BE68: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==20391==    by 0x8048574: qSort (2100assignment4.c:47)
==20391==    by 0x80484BD: main (2100assignment4.c:22)
==20391==
==20391== Conditional jump or move depends on uninitialised value(s)
==20391==    at 0x804855D: qSort (2100assignment4.c:45)
==20391==    by 0x80485E0: qSort (2100assignment4.c:61)
==20391==    by 0x80485E0: qSort (2100assignment4.c:61)
==20391==    by 0x80484BD: main (2100assignment4.c:22)
==20391==  Uninitialised value was created by a heap allocation
==20391==    at 0x402BE68: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==20391==    by 0x8048574: qSort (2100assignment4.c:47)
==20391==    by 0x80484BD: main (2100assignment4.c:22)
==20391==
==20391== Conditional jump or move depends on uninitialised value(s)
==20391==    at 0x804855D: qSort (2100assignment4.c:45)
==20391==    by 0x80485E0: qSort (2100assignment4.c:61)
==20391==    by 0x80485E0: qSort (2100assignment4.c:61)
==20391==    by 0x80485E0: qSort (2100assignment4.c:61)
==20391==    by 0x80484BD: main (2100assignment4.c:22)
==20391==  Uninitialised value was created by a heap allocation
==20391==    at 0x402BE68: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==20391==    by 0x8048574: qSort (2100assignment4.c:47)
==20391==    by 0x80485E0: qSort (2100assignment4.c:61)
==20391==    by 0x80484BD: main (2100assignment4.c:22)
==20391==
==20391== Stack overflow in thread 1: can't grow stack to 0xbe297ff4
==20391==
==20391== Process terminating with default action of signal 11 (SIGSEGV)
==20391==  Access not within mapped region at address 0xBE297FF4
==20391==    at 0x402BE35: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==20391==  If you believe this happened as a result of a stack
==20391==  overflow in your program's main thread (unlikely but
==20391==  possible), you can try to increase the size of the
==20391==  main thread stack using the --main-stacksize= flag.
==20391==  The main thread stack size used in this run was 8388608.
==20391== Stack overflow in thread 1: can't grow stack to 0xbe297fe4
==20391==
==20391== Process terminating with default action of signal 11 (SIGSEGV)
==20391==  Access not within mapped region at address 0xBE297FE4
==20391==    at 0x4025430: _vgnU_freeres (in /usr/lib/valgrind/vgpreload_core-x86-linux.so)
==20391==  If you believe this happened as a result of a stack
==20391==  overflow in your program's main thread (unlikely but
==20391==  possible), you can try to increase the size of the
==20391==  main thread stack using the --main-stacksize= flag.
==20391==  The main thread stack size used in this run was 8388608.
==20391==
==20391== HEAP SUMMARY:
==20391==     in use at exit: 4,190,952 bytes in 523,869 blocks
==20391==   total heap usage: 523,869 allocs, 0 frees, 4,190,952 bytes allocated
==20391==
==20391== LEAK SUMMARY:
==20391==    definitely lost: 0 bytes in 0 blocks
==20391==    indirectly lost: 0 bytes in 0 blocks
==20391==      possibly lost: 0 bytes in 0 blocks
==20391==    still reachable: 4,190,952 bytes in 523,869 blocks
==20391==         suppressed: 0 bytes in 0 blocks
==20391== Rerun with --leak-check=full to see details of leaked memory
==20391==
==20391== For counts of detected and suppressed errors, rerun with: -v
==20391== ERROR SUMMARY: 261929 errors from 3 contexts (suppressed: 0 from 0)

Some problems to start with: 首先要解决的一些问题:

if (scanf("\%d", &x) == EOF) return NULL;

The \\ is not needed. 不需要\\。 It might be easier to check for != 1 as you are expecting one value. 检查!= 1可能会更容易,因为您期望一个值。

This caused your MakeList to recurse infinitely (at least on my machine). 这导致您的MakeList无限递归(至少在我的机器上)。

In your qsort function, your little and big lists always have a dummy entry at the end - done by this code 在您的qsort函数中,小列表和大列表始终在末尾有一个虚拟条目-通过此代码完成

little->next = (LIST) malloc(sizeof(struct CELL));
little = little->next;
little->next = NULL;

This means that when you split your lists you always end up more entries than you started with, so it never finishes. 这意味着,当您拆分列表时,最终得到的条目总是比开始时要多,因此它永远都不会结束。 Also note that these new entries don't have their element values set, which is probably where you are getting the uninitialized warnings. 还要注意,这些新条目未设置其元素值,这可能是您收到未初始化警告的地方。

You should rethink how you are storing the sub lists, perhaps start them as NULL, to indicate empty, although that will make adding new values a bit harder. 您应该重新考虑如何存储子列表,也许以NULL开头,以指示为空,尽管这会使添加新值变得更加困难。

You can edit your makelist function as below.. 您可以按以下方式编辑清单列表功能。

You will observe few changes. 您将观察到一些变化。

  1. scanf is correct by removing \\ (Refer The Dark's answer) scanf通过删除\\是正确的(请参阅《黑暗的答案》)
  2. scanf read in while, this will ensure reading will stop if you enter any incompatible input like any letter instead of Ctrl + D. scanf读取时,如果您输入任何不兼容的输入(例如字母)而不是Ctrl + D,这将确保读取停止。
LIST MakeList()
{
    int x;
    LIST pNewCell;

    while(scanf("%d", &x))
    {
        pNewCell = (LIST) malloc(sizeof(struct CELL));
        pNewCell->next = MakeList();
        pNewCell->element = x;
        return pNewCell;
    }
    return NULL;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM