使用 qsort 对列表进行排序?
我正在编写一个程序,您可以在其中通过键盘或文件输入单词,然后将它们按长度排序。 有人告诉我应该使用链表,因为单词的长度和数量不固定。
我应该使用链表来表示单词吗?
struct node{
char c;
struct node *next;
};
那么如何使用 qsort 按长度对单词进行排序呢? qsort 不适用于数组吗?
我对编程还很陌生。
谢谢。
I'm writing a program in which you enter words via the keyboard or file and then they come out sorted by length. I was told I should use linked lists, because the length of the words and their number aren't fixed.
should I use linked lists to represent words?
struct node{
char c;
struct node *next;
};
And then how can I use qsort to sort the words by length? Doesn't qsort work with arrays?
I'm pretty new to programming.
Thank you.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我认为有一个比您应该选择的排序算法更大的问题。 第一个是您定义的结构实际上不会保存单词列表,而是保存单个字母(或单个单词)的列表。C 中的字符串表示为以 null 结尾的字符数组,布局如下:
这个数组理想地被声明为 char[8] - 每个字母一个插槽,加上一个空字节插槽(实际上是内存中的一个字节的零。)
现在我知道你可能知道这一点,但为了清楚起见,值得指出这一点。 当您操作数组时,您可以一次查看多个字节并加快速度。 使用链表,您只能以真正线性的时间查看事物:从一个字符走到下一个字符。 当您尝试在字符串上快速执行某些操作时,这一点很重要。
保存此信息的更合适的方法是采用非常类似于 C 的风格,并在 C++ 中用作向量:使用 malloc 和 realloc 自动调整连续内存块的大小。
首先,我们设置一个像这样的结构:
我们为此提供了一些函数:
现在,这不太好,因为您不能只使用 scanf 读入一个简单的缓冲区,但您可以使用类似 getchar() 的函数来获取单个字符并使用 string_addchar() 将它们放入字符串中以避免使用链表。 该字符串尽可能避免重新分配,每 2^n 插入一次,并且您仍然可以使用 C 字符串库中的字符串函数!!这对实现排序有很大帮助。
那么现在我该如何实际实现排序呢? 您可以创建一个类似的类型,旨在以类似的方式保存整个字符串,并根据需要进行增长,以保存来自控制台的输入字符串。 无论哪种方式,您的所有数据现在都位于可以作为数组访问的连续内存块中 - 因为它是一个数组! 例如,假设我们有这个:
以及与以前类似的功能:创建、删除、插入。
这里的关键是您可以在 string.data 元素上使用 strcmp() 来实现排序函数,因为它只是一个 C 字符串。 由于我们有一个使用函数指针的 qsort 内置实现,因此我们所要做的就是包装 strcmp() 以与这些类型一起使用并传入地址。
I think there is a bigger issue than the sorting algorithm which you should pick. The first of these is that the struct that you're defining is actually not going to hold a list of words, but rather a list of single letters (or a single word.) Strings in C are represented as null-terminated arrays of characters, laid out like so:
This array would ideally be declared as char[8] - one slot for each letter, plus one slot for the null byte (literally one byte of zeros in memory.)
Now I'm aware you probably know this, but it's worth pointing this out for clarity. When you operate on arrays, you can look at multiple bytes at a time and speed things up. With a linked list, you can only look at things in truly linear time: step from one character to the next. This is important when you're trying to do something quickly on strings.
The more appropriate way to hold this information is in a style that is very C like, and used in C++ as vectors: automatically-resized blocks of contiguous memory using malloc and realloc.
First, we setup a struct like this:
And we provide some functions for these:
Now, this isn't great because you can't just read into an easy buffer using scanf, but you can use a getchar()-like function to get in single characters and place them into the string using string_addchar() to avoid using a linked list. The string avoids reallocation as much as possible, only once every 2^n inserts, and you can still use string functions on it from the C string library!! This helps a LOT with implementing your sorts.
So now how do I actually implement a sort with this? You can create a similar type intended to hold entire strings in a similar manner, growing as necessary, to hold the input strings from the console. Either way, all your data now lives in contiguous blocks of memory that can be accessed as an array - because it is an array! For example, say we've got this:
And similar functions as before: create, delete, insert.
The key here is that you can implement your sort functions using strcmp() on the string.data element since it's JUST a C string. Since we've got a built-in implementation of qsort that uses a function pointer, all we have to do is wrap strcmp() for use with these types and pass the address in.
如果您知道如何对项目进行排序,则在读取数据时应该使用插入排序,这样一旦输入了所有输入,您所要做的就是写入输出。 使用链表就可以了,尽管您会发现它具有 O(N2) 性能。 如果您将输入存储在按长度排序的二叉树中(平衡树最好),那么您的算法将具有 O(NlogN) 性能。 如果您只想执行一次,那么就应该优先考虑实施的简单性而不是效率。
伪代码:
If you know how you want the items sorted, you should use an insertion sort when reading the data so that once all the input has been entered, all you have to do is write the output. Using a linked list would be ok, though you'll find that it has O(N2) performance. If you store the input in a binary tree ordered by length (a balanced tree would be best), then your algorithm will have O(NlogN) performance. If you're only going to do it once, then go for simplicity of implementation over efficiency.
Pseudocode:
是的,经典的“C”库函数 qsort() 只适用于数组。 这是内存中连续的值集合。
Tvanfosson 的建议非常好——当你构建链表时,你可以在正确的位置插入元素。 这样,列表始终是排序的。
我认为您被告知要使用链接列表的评论很有趣。 事实上,列表在许多情况下都是一种很好的数据结构,但它确实有缺点; 例如,必须遍历它才能找到元素。
根据您的应用程序,您可能需要使用哈希表。 在 C++ 中,您可以使用 hash_set 或 hash_map。
我建议您花一些时间学习基本数据结构。 在这里花费的时间将使您受益匪浅,并且更好地让您能够评估诸如“使用链接列表”之类的建议。
Yes, the classic "C" library function qsort() only works on an array. That is a contiguous collection of values in memory.
Tvanfosson advice is pretty good - as you build the linked list, you can insert elements at the correct position. That way, the list is always sorted.
I think the comment you made that you were told to use a linked list is interesting. Indeed a list can be a good data structure to use in many instances, but it does have draw backs; for example, it must be traversed to find elements.
Depending on your application, you may want to use a hash table. In C++ you could use a hash_set or a hash_map.
I would recommend you you spend some time studying basic data structures. Time spent here will server you will and better put you in a position to evaluate advice such as "use a linked list".
有很多方法可以处理它......如果您有足够的勇气尝试,您可以通过动态内存分配和 realloc 使用数组。
然而,qsort 的标准实现需要每个元素都是固定长度,这意味着有一个字符串指针数组。
不过,与使用指向指针的指针相比,实现链表应该很容易。
我认为您被告知要做的不是将字符串保存为列表;而是将字符串保存为列表。 但是在链表中:
然后,您所要做的就是每次读取字符串时,将一个新节点添加到列表中的有序位置。 (遍历列表,直到当前字符串的长度大于您刚刚读取的字符串。)
单词长度不固定的问题很常见,通常通过将世界临时存储在缓冲区中,然后将其复制到适当长度的数组(当然是动态分配的)。
编辑:
在伪代码中:
当然,这需要大量的润色。 请记住,数组的类型为
char **array
,即“指向 char 的指针的指针”(将其作为指针数组处理); 由于您要传递指针,因此不能只将缓冲区传递到数组中。There are lots of ways to handle it... You can use arrays, via dynamic memory allocation, with realloc, if you feel brave enough to try.
The standard implementation of qsort, though, needs each element to be a fixed length, which would mean having an array-of-pointers-to-strings.
Implementing a linked list, though, should be easy, compared to using pointers to pointers.
I think what you were told to do was not to save the strings as list; but in a linked list:
Then, all you have to do is, every time you read a string, add a new node into the list, in its ordered place. (Walk the list until the current string's length is greater than the string you just read.)
The problem of words not being a fixed length is common, and it's usually handled by storing the world temporarily in a buffer, and then copying it into a proper length array (dynamically allocated, of course).
Edit:
In pseudo code:
Of course, that needs a TON of polishing. Remember that array is of type
char **array
, ie "A pointer to a pointer to char" (which you handle as an array of pointers); since you're passing pointers around, you can't just pass the buffer into the array.您可以通过分配一个指针数组(每个列表元素一个)来对链表进行排序。
然后,您对该数组进行排序,在比较函数中,您当然会收到指向列表元素的指针。
然后,这将为您提供一个排序的指针列表。
然后,您可以通过遍历指针数组并依次调整每个元素来遍历列表。 重新排列其在列表中的顺序以匹配指针数组的顺序。
You qsort a linked list by allocating an array of pointers, one per list element.
You then sort that array, where in the compare function you are of course receiving pointers to your list elements.
This then gives you a sorted list of pointers.
You then traverse your list, by traversing the array of pointers and adjusting each element in turn. rearranging its order in the list to match the order of your array of pointers.