【问题标题】:Sorting a list with qsort?使用 qsort 对列表进行排序?
【发布时间】:2010-10-21 20:29:34
【问题描述】:

我正在编写一个程序,您可以在其中通过键盘或文件输入单词,然后按长度排序。有人告诉我应该使用链表,因为单词的长度和数量不是固定的。

我应该使用链表来表示单词吗?

struct node{
    char c;
    struct node *next;
};

然后如何使用 qsort 按长度对单词进行排序? qsort 不适用于数组吗?

我对编程很陌生。

谢谢。

【问题讨论】:

    标签: c sorting linked-list qsort


    【解决方案1】:

    我认为有一个比你应该选择的排序算法更大的问题。其中第一个是您定义的结构实际上不会保存单词列表,而是包含单个字母(或单个单词)的列表。C 中的字符串表示为以空字符结尾的字符数组,布局如下:

    | A | n | t | h | o | n | y | \0 |
    

    这个数组最好声明为 char[8] - 每个字母一个槽,加上一个空字节槽(字面意思是内存中的一个零字节。)

    现在我知道您可能知道这一点,但为了清楚起见,值得指出这一点。当您对数组进行操作时,您可以一次查看多个字节并加快处理速度。使用链表,您只能以真正的线性时间查看事物:从一个字符到下一个字符。当您尝试在字符串上快速执行某些操作时,这一点很重要。

    保存此信息的更合适的方式是采用非常类似于 C 的样式,并在 C++ 中用作向量:使用 malloc 和 realloc 自动调整大小的连续内存块。

    首先,我们设置一个这样的结构:

    struct sstring {
        char *data;
        int logLen;
        int allocLen;
    };
    typedef struct string sstring;
    

    我们为这些提供了一些功能:

    // mallocs a block of memory and holds its length in allocLen
    string_create(string* input); 
    
    // inserts a string and moves up the null character
    // if running out of space, (logLen == allocLen), realloc 2x as much
    string_addchar(string* input, char c);
    
    string_delete(string* input);
    

    现在,这不是很好,因为您不能只使用 scanf 读入一个简单的缓冲区,但是您可以使用类似 getchar() 的函数来获取单个字符并使用 string_addchar() 将它们放入字符串中避免使用链表。字符串尽可能避免重新分配,每 2^n 插入一次,您仍然可以在其上使用 C 字符串库中的字符串函数!这对实现您的排序有很大帮助。

    那么现在我该如何用这个来实现排序呢?您可以创建一个类似的类型,以类似的方式保存整个字符串,根据需要增长,以保存来自控制台的输入字符串。无论哪种方式,您的所有数据现在都位于可以作为数组访问的连续内存块中 - 因为它是一个数组!例如,假设我们有这个:

    struct stringarray {
        string *data;
        int logLen;
        int allocLen;
    };
    typedef struct stringarray cVector;
    cVector myData;
    

    和之前类似的功能:创建、删除、插入。

    这里的关键是您可以在 string.data 元素上使用 strcmp() 来实现排序函数,因为它只是一个 C 字符串。由于我们有一个使用函数指针的 qsort 的内置实现,我们所要做的就是包装 strcmp() 以用于这些类型并传入地址。

    【讨论】:

    • 你的 'string' 类型是一个结构体,所以你的原型必须采用 'struct string*' 而不仅仅是 'string*'。或者使用 typedef。我更喜欢 typedef,但任何一种都可以接受。
    • 是的,你是对的 - 最近做了太多类似 C 的 C++!
    【解决方案2】:

    您可以通过分配一组指针来对链表进行 qsort,每个列表元素一个。

    然后您对该数组进行排序,在比较函数中您当然会收到指向列表元素的指针。

    这会给你一个排序的指针列表。

    然后您通过遍历指针数组并依次调整每个元素来遍历您的列表。重新排列其在列表中的顺序以匹配指针数组的顺序。

    【讨论】:

      【解决方案3】:

      有很多方法可以处理它...如果您有足够的勇气尝试,可以使用数组,通过动态内存分配和 realloc。

      但是,qsort 的标准实现需要每个元素都是固定长度,这意味着有一个指向字符串的指针数组。

      不过,与使用指向指针的指针相比,实现链表应该很容易。

      我认为你被告知不要将字符串保存为列表;但是中是一个链表:

      struct node {
          char *string;
          node *next;
      }
      

      然后,您所要做的就是,每次读取字符串时,在列表中的有序位置添加一个新节点。 (遍历列表,直到当前字符串的长度大于您刚刚读取的字符串。)

      单词不是固定长度的问题很常见,通常通过将世界临时存储在缓冲区中,然后将其复制到适当长度的数组中(当然是动态分配的)来处理。

      编辑:

      在伪代码中:

      array = malloc(sizeof(*char))
      array_size = 1
      array_count = 0
      
      while (buffer = read != EOF):
          if(array_count == array_size)
              realloc(array, array_size * 2)
          array_count++
          sring_temp = malloc(strlen(buffer))
          array[array_count] = string_temp
      
      qsort(array, array_count, sizeof(*char), comparison)
      
      print array
      

      当然,这需要大量的打磨。请记住,数组的类型为char **array,即“指向char 指针的指针”(您将其作为指针数组处理);由于您要传递指针,因此不能只将缓冲区传递到数组中。

      【讨论】:

      • 我对如何使用 realloc 有一点想法 - 我有我的讲座笔记。我最初打算只使用动态数组来制作程序,但一位老师告诉我最好将列表用于something。如何制作缓冲区?缓冲区是否只是内存的较大部分,例如 100 个字符?他们会给我们布置作业,老师会靠在键盘上,看看是否预测会发生什么:-)。
      • 是的,缓冲区通常是一个足够大的固定数组,可以容纳“任何东西”。问题在于选择足够大的缓冲区以容纳任何东西,但又足够小不会使其效率低下(但这在涉及用户输入时并不是什么大问题)。如果您必须仅在输入完成后对列表进行排序,您仍然可以在获取字符串时将其放入列表中,然后再对它们进行排序。但是使用链表没有什么意义,然后:P。
      【解决方案4】:

      如果您知道要如何对项目进行排序,则在读取数据时应该使用插入排序,这样一旦输入了所有输入,您所要做的就是写入输出。使用链表是可以的,尽管您会发现它具有 O(N2) 性能。如果您将输入存储在按长度排序的二叉树中(平衡树最好),那么您的算法将具有 O(NlogN) 性能。如果你只打算做一次,那么就追求实现的简单性而不是效率。

      伪代码:

        list = new list
        read line
        while not end of file
            len = length(line)
            elem = head(list)
            while (len > length(elem->value))
                elem = elem->next
            end
            insert line in list before elem
            read line
        end
      
       // at this point the list's elements are sorted from shortest to longest
       // so just write it out in order
       elem = head(list)
       while (elem != null)
           output elem->value
           elem = elem->next
       end
      

      【讨论】:

      • 感谢您的回复。不幸的是,我无法在阅读时进行排序。必须在将它们“输入”到程序中后才能完成。
      • 我只是说要在结构中找到正确的位置,以便在您阅读时插入项目。这样你的内存结构总是被排序的。我将添加一些伪代码来说明。
      【解决方案5】:

      是的,经典的“C”库函数 qsort() 仅适用于数组。那是内存中值的连续集合。

      Tvanfosson 的建议非常好——在构建链表时,可以在正确的位置插入元素。这样,列表总是排序的。

      我认为你被告知使用链表的评论很有趣。确实,列表可以是在许多情况下使用的很好的数据结构,但它确实有缺点。例如,必须遍历它才能找到元素。

      根据您的应用程序,您可能希望使用哈希表。在 C++ 中,您可以使用 hash_set 或 hash_map。

      我建议您花一些时间研究基本的数据结构。在这里花费的时间将使您能够更好地评估诸如“使用链表”之类的建议。

      【讨论】:

        猜你喜欢
        • 2019-05-23
        • 1970-01-01
        • 1970-01-01
        • 2011-04-15
        • 1970-01-01
        • 1970-01-01
        • 2015-09-16
        • 2021-05-08
        • 2014-06-05
        相关资源
        最近更新 更多