【问题标题】:How to sort strings in an 2D array in C如何在C中对二维数组中的字符串进行排序
【发布时间】:2021-03-27 12:36:06
【问题描述】:
#include <stdio.h>

int main()
{
int N, i, j, k, z, v, x, c;

printf("Determine the number of your words: \n");
scanf("%d", &N);
char dict[N][50];
char tmp[50];
for(i=0; i<N; i++)
{
    printf("Determine your %d. word: \n", i+1);
    scanf("%49s", &dict[i]);
}




for(j=1; j<N; j++)
{
    k=j;
    z=0;
    while(dict[j][z]!= '\0')
    {
        tmp[z]=dict[j][z];
        z=z+1;
    }

    
    while((dict[j][1]<dict[k-1][1]) && (k>0))
    {
        v=0;
        while(dict[k][v]!= '\0')
        {
            dict[k][v] = dict[k-1][v];
            v= v+1;
        }
        k=k-1;
    }
    x=0;
    while(dict[k][x]!= '\0')
    {
        dict[k][x]=tmp[x];
        x=x+1;
    }
    
}


for(c=0; c<N; c++)
{
    
    printf("%s \n", dict[c]);
    
}



return 0;

}

所以作为一名初级 CE 学生,我们的任务是编写一个 C 代码,仅使用 库,根据它们在字母表中的第一个字符位置对二维数组中的字符串进行排序,这就是我的结果get在下面(我知道变量不是真的可以忍受但我有点着急):

Determine the number of your words:
5
Determine your 1. word:
LION
Determine your 2. word:
FISH
Determine your 3. word:
TIGER
Determine your 4. word:
SNAKE
Determine your 5. word:
SEALION
LION
FISH
TIGER
SEALI
SNAKE

我没有收到任何错误,只是结果有问题,我不希望得到任何答案。但我很高兴能了解我得到这个结果的原因

【问题讨论】:

  • 如果不允许使用strcmp()strcpy(),我可能会为这些任务编写自己的函数。
  • 我试图通过交换(改变第二个和第一个字符串的位置)来做到这一点
  • 为什么要在多个地方重写代码的细微变化?如果您调用的是命名良好的函数,则更容易理解代码,而不必弄清楚每个 while 循环的作用。
  • 再说一次,这是我在大学的第一个学期,我们还没有真正着手编码(这是第二个学期的主题),所以我们还没有创建自己的函数跨度>
  • 试着用英语解释你是如何排序的(你认为应该怎么做)

标签: c sorting multidimensional-array


【解决方案1】:

stdio.h

如果您仅限于使用stdio.h 中提供的功能,那么您只需编写与string.h 所需功能类似的字符串处理功能。对于排序,除非您想使用诸如快速排序或合并排序之类的分区排序,否则您将被限制为嵌套循环排序——它更易于编写——但速度要慢得多。 (但对于 1000 左右的字符串,没关系,100,000 - 然后会有可感知的差异)

要比较字符串,您可以编写一个简单的strcmp()like 函数,不需要额外的标头,例如

/** string compare without string.h */
int strcmp_nohdr (const char *a, const char *b)
{
    if (!a && !b) return 0;
    if ( a && !b) return 1;
    if (!a &&  b) return -1;

    for (; *a && *a == *b; a++, b++) {}

    return (*a > *b) - (*a < *b);
}

如果您没有声明一组额外的排序指针,那么您将需要在二维数组的行(一维数组)之间复制字符串。您可以编写一个不需要标头的简单 strcpy() 类似函数:

/** string copy wihout string.h */
char *strcpy_nohdr (char *dest, const char *src)
{
    char *p = dest;
    
    do {
        *p++ = *src;
    } while (*src++);
    
    return dest;
}

最后,您唯一需要的就是排序函数。 (您将无法编写快速的qsort() 替换)微不足道的冒泡排序 就可以了。您可以编写一个函数来将您的二维字符串数组排序为:

#define NCHR 50

/** bubble sort of strings in 'a' (highly inefficient) */
void bubblesort2D (char (*a)[NCHR], size_t n)
{
    size_t i, j;
    for (i = 0; i < n; i++) {
        for (j = 0; j < (n-1); j++) {
            if (strcmp_nohdr(a[j], a[j + 1]) > 0) {
                char temp[NCHR];
                strcpy_nohdr (temp, a[j + 1]);
                strcpy_nohdr  (a[j + 1], a[j]);
                strcpy_nohdr  (a[j], temp);
            }
        }
    }
}

如果您将这些全部放在一个简短的示例中(之前与 qsort() 使用的相同,您将:

#include <stdio.h>

#define NCHR 50

/** string compare without string.h */
int strcmp_nohdr (const char *a, const char *b)
{
    if (!a && !b) return 0;
    if ( a && !b) return 1;
    if (!a &&  b) return -1;

    for (; *a && *a == *b; a++, b++) {}

    return (*a > *b) - (*a < *b);
}

/** string copy wihout string.h */
char *strcpy_nohdr (char *dest, const char *src)
{
    char *p = dest;
    
    do {
        *p++ = *src;
    } while (*src++);
    
    return dest;
}

/** bubble sort of strings in 'a' (highly inefficient) */
void bubblesort2D (char (*a)[NCHR], size_t n)
{
    size_t i, j;
    for (i = 0; i < n; i++) {
        for (j = 0; j < (n-1); j++) {
            if (strcmp_nohdr(a[j], a[j + 1]) > 0) {
                char temp[NCHR];
                strcpy_nohdr (temp, a[j + 1]);
                strcpy_nohdr  (a[j + 1], a[j]);
                strcpy_nohdr  (a[j], temp);
            }
        }
    }
}

int main (void) {
    
    char strings[][NCHR] = { "zebra", "alligators", "frogs", "racoons", "opossums" };
    size_t n = sizeof strings / sizeof *strings;
    
    bubblesort2D (strings, n);
    
    for (size_t i = 0; i < n; i++)
        puts (strings[i]);
}

使用/输出示例

结果和之前一样:

$ ./bin/sort_2d_strings_stdio
alligators
frogs
opossums
racoons
zebra

由于我最初写了qsort() 答案,我将把它留在下面,作为您在实践中处理排序(无论您正在排序的数组)的方式。

实际使用qsort()

C 提供qsort(),它将根据您编写的compare 函数对任何对象的数组进行排序,以告诉qsort() 如何比较数组的元素。对于字符串,您只想返回strcmp() 的结果。 compare 函数的每个参数都有一个指向数组元素的 Pointers。由于它是一个void* 指针,因此您必须将指针转换回正确的类型。

在 C 中回想一下,二维数组只是 一维数组的数组。在您的情况下,它是一个包含 50 个字符的数组。指向 50 个字符数组的指针的类型为 char (*)[50],因此您的 qsort() compare 函数可以编写如下:

int cmpstr50 (const void *a, const void *b)
{
    const char  *pa = *(char (*)[50])a,
                *pb = *(char (*)[50])b;
    
    return strcmp (pa, pb);
}

其中每个参数都是指向char [50] 数组的指针。没有什么比这更容易了。此外,qsort() 使用的算法将比您使用嵌套循环编写的算法快几个数量级。

您的案例的完整示例是:

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

int cmpstr50 (const void *a, const void *b)
{
    const char  *pa = *(char (*)[50])a,
                *pb = *(char (*)[50])b;
    
    return strcmp (pa, pb);
}

int main (void) {
    
    char strings[][50] = { "zebra", "alligators", "frogs", "racoons", "opossums" };
    size_t n = sizeof strings / sizeof *strings;
    
    qsort (strings, n, sizeof *strings, cmpstr50);
    
    for (size_t i = 0; i < n; i++)
        puts (strings[i]);
}

在编写 compare 函数后,对字符串数组(或任何数组)进行排序所需的只是对 qsort() 的一次调用:

    qsort (strings, n, sizeof *strings, cmpstr50);

比尝试重新发明轮子要简单得多。

使用/输出示例

$ ./bin/qsort_2d_strings
alligators
frogs
opossums
racoons
zebra

如果您还有其他问题,请告诉我。

【讨论】:

  • 我很欣赏你的回答,但问题是我几乎不能使用这些,因为我被允许使用的唯一库是 :D。我也不能使用任何额外的功能,如 int main void。我只能在 int main 下编写代码
  • OP 仅限于使用&lt;stdio.h&gt;qsort() 需要&lt;stdlib.h&gt; 有时需要&lt;search.h&gt;
【解决方案2】:

这个比较不正确:

while((dict[j][1]<dict[k-1][1]) && (k>0))

首先,如果要比较每个单词的第一个字符,请使用[0] 而不是[1]。这是因为数组索引在 C 中是从零开始的。其次,在使用 k-1 作为数组的索引之前,先将 k&gt;0 比较。这将利用“短路”来确保您没有使用无效的数组索引。结果:

while(k > 0 && dict[j][0] < dict[k-1][0])

另一个问题是,当您复制它们时,您并没有确保您的字符串是空终止的。我相信这就是你的“SEALION”出现“SEALI”的原因。比如这个循环:

x=0;
while(dict[k][x]!= '\0')
{
    dict[k][x]=tmp[x];
    x=x+1;
}

您在目标而不是源上检查 null。此外,您在空字符处停止复制,但实际上您也需要复制它,或者至少在末尾添加一个空字符:

x=0;
while(tmp[x]!= '\0')
{
    dict[k][x]=tmp[x];
    x=x+1;
}
dict[k][x] = '\0';

仔细查看每个字符串复制循环是否存在此类错误。

【讨论】:

  • 这就是我一直在寻找的答案。这样的错误会毁掉整个代码,这很痛苦。谢谢你。
  • 这就是编程的本质。如果此答案解决了您的问题,请点击答案分数下方的灰色复选标记接受。
  • 使用此输入确实解决了我的问题,但出现了一个新问题,即当我使用混合顺序提供更多输入时,结果并未完全解决,例如:确定您的单词数:10 确定您的 1 . 单词:FISH 确定您的 2. 单词:LION 确定您的 3. 单词:SNAKE 确定您的 4. 单词:LOPRICON 确定您的 5. 单词:TIGER 确定您的 6. 单词:SEALION 确定您的 7. 单词:FRAG 确定您的 8.词:手榴弹 确定你的 9. 词:超人 确定你的 10. 词:魔术师鱼狮 LOPRICON SNAKE SEALION FRAG 手榴弹 SUPERMAN MAGICIAN TIGE
  • 您的排序算法存在缺陷。尝试研究bubble sort algorithm,看看它误入歧途。
  • 我发布了一个相同主题的新问题,但这次我使用了冒泡排序。如果你能达到顶峰,我会很高兴。链接:stackoverflow.com/questions/65344720/…
猜你喜欢
  • 2021-08-16
  • 2014-08-10
  • 1970-01-01
  • 2011-07-01
  • 2013-05-26
  • 2011-02-17
  • 1970-01-01
  • 2023-01-02
相关资源
最近更新 更多