【问题标题】:split linked list of chars in C在C中拆分字符链表
【发布时间】:2021-05-10 13:26:41
【问题描述】:

我应该编写一个名为“disAssemblyList”的函数,它获取一个字符的链接列表(没有虚拟元素)。该函数应该将带有大字母的节点移动到“bigLetter”链表(没有虚拟元素),将带有小字母的节点移动到“smallLetter”链表,nums到“nums”链表,其他字符保留在原始列表中。

我需要通过引用传递 smallLetter、bigLetter 和 nums 链表并返回带有其他字符的列表。

我需要扫描原始列表。原始列表可以为空。

例如:

原始链表:

3-> a-> 7-> M-> K-> u-> 5-> #-> &-> P-> %-> A

bigLetter:

M-> K-> P-> A

smallLetter:

a-> u

nums:

3-> 7-> 5

其他字符(函数运行后的原始列表):

#-> &-> %

我编写了这段代码,但我似乎无法理解如何使它工作。 它不会将字符扫描到链表。

typedef struct chNode
{
    char data;
    struct chNode *next;
}chNode;


chNode * createCharList(char data)
{
    chNode *temp = (chNode*)malloc(sizeof(chNode));
    temp->data = data;
    temp->next = NULL;
    return temp;
}

chNode * addCharToLast(chNode *head, char data)
{
    chNode *p = head;
    chNode *temp = createCharList(data);
    if (head == NULL)
        return temp;
    while (p->next != NULL)
        p = p->next;
    p->next = temp;
    return head;
}

void printf_CharList(chNode *head)
{
    chNode *p = head;
    while (p != NULL)
    {
        printf("%d, ", p->data);
        p = p->next;
    }
    printf("\n\n");
}


chNode* insert_Charlist() // A function that imports numbers into a linked list , till -1
{
    char ch;
    chNode *Head = NULL;
    printf("Enter chars For Linked-List Till 'Enter':\n");
    //5scanf_s("%c", &ch);
    ch = getchar();
    while (ch != "\n")
    {

        Head = addCharToLast(Head, ch); //Makes last number to be First
        //scanf_s("%c", &ch);
        ch = getchar();
    }
    return Head;
}

void add_to_other_list(chNode** head, chNode* p)
{
    static chNode* tail = NULL;

    p->next = NULL;
    if (tail == NULL)
    {
        *head = p;
    }
    else
    {
        tail->next = p;
    }
    tail = p;
}


chNode* disAssemblyList(chNode* p, chNode **bigLetter, chNode **smallLetter, chNode **nums)
{
    chNode* t = NULL;

    if (p == NULL) return p;          // 0 elements
    if (p->next == NULL) return p;    // 1 element
    if (p->next->next == NULL)          // 2 elements
    {

        if ((p->next->data >= 65) && (p->next->data) <= 90)
        {
            // Move p->next to other list
            add_to_other_list(&(*bigLetter), p->next);
            p->next = NULL;
            return p;
        }
    }

    // Repeat as long as the list has minimum 3 elements
    while (p->next)
    {
        if ((p->next->data >= 65) && (p->next->data) <= 90)
        {
            // Move p-next
            t = p->next;
            p->next = p->next->next;
            add_to_other_list(&(*bigLetter), t);
        }

        if ((p->next->data >= 97) && (p->next->data) <= 122)
        {
            t = p->next;
            p->next = p->next->next;
            add_to_other_list(&(*smallLetter), t);
        }

        if ((p->next->data >= 48) && (p->next->data) <= 57)
        {
            t = p->next;
            p->next = p->next->next;
            add_to_other_list(&(*nums), t);

        }
        p = p->next;
    }

    return p;

}


void main()
{

    chNode *Orignial_list = NULL;
    chNode *bigLetter = NULL;
    chNode *smallLetter = NULL;
    chNode *nums = NULL;
    Orignial_list = insert_Charlist(); // Function that imports a list
    printf("You Entered This linked-list:\n");
    printf_CharList(Orignial_list); //Printing the linked list
    Orignial_list = disAssemblyList(Orignial_list,&bigLetter,&smallLetter,&nums);
    printf("The BigLetter Linked-List is:\n");
    printf_CharList(bigLetter);
    printf_CharList(smallLetter);
    printf_CharList(nums);
    printf_CharList(Orignial_list);
    getch();

}

【问题讨论】:

  • 您好,欢迎来到 StackOverflow。这是相当多的代码要经过,所以也许试着把它减少到一个“最小的可重现的例子”。例如,尝试只为初学者使用一个列表。此外,“不起作用”是一个非常通用的错误描述(但我们得到的最多)。您是否尝试过在调试器中单步执行您的代码并按照步骤操作?这可能会帮助您弄清楚事情的发展方向。
  • @RefugnicEternium 尝试在这样的评论中输入[mre]。对你来说更快,对 OP 更有帮助。
  • 我很抱歉,@Yunnosch,我通常不是第一个发布这个的,所以我不知道快捷方式。感谢您的提醒。 :) 所以是的,我们可能会要求您发布minimal reproducible example
  • 请尝试while (ch != '\n')printf("%c, ", p-&gt;data);,然后我们可以开始讨论实际的算法问题。
  • 正如 Yunnosh 已经正确指出的那样,您的问题可能已经出现在“输入”向量上,您似乎在等待字符“直到输入”。但是在那个时候,您将 charconst char * 进行比较,这应该已经给您一个编译错误。

标签: c split linked-list singly-linked-list function-definition


【解决方案1】:

我没有查看您的所有代码,因为据我了解,问题是关于将原始列表拆分为其他列表的一个函数实现。

虽然我确信您的代码存在缺陷,例如函数 print_CharList 输出字符的内部代码,而不是存储在列表中的字符本身。

void printf_CharList(chNode *head)
{
    chNode *p = head;
    while (p != NULL)
    {
        printf("%d, ", p->data);
        p = p->next;
    }
    printf("\n\n");
}

或者带有静态变量的函数add_to_other_list没有意义。

或者这个条件在函数的开头disAssemblyList

if (p->next == NULL) return p;    // 1 elementNevertheless the function 

也说不通。

尽管如此,拆分列表的函数看起来就像下面的演示程序中所示。

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

typedef struct chNode
{
    char data;
    struct chNode *next;
} chNode;

void clear( chNode **head )
{
    while ( *head != NULL )
    {
        chNode *tmp = *head;
        *head = ( *head )->next;
        free( tmp );
    }
}

size_t assign( chNode **head, const char *s )
{
    if ( *head ) clear( head );
    
    size_t n = 0;
    
    while ( *s && ( *head = malloc( sizeof( chNode ) ) ) != NULL )
    {
        ( *head )->data = *s++;
        ( *head )->next = NULL;
        head = &( *head )->next;
        ++n;
    }
    
    return n;
}

FILE * display( const chNode *head, FILE *fp )
{
    for ( ; head != NULL; head = head->next )
    {
        fprintf( fp, "%c -> ", head->data );
    }
    
    fputs( "null", fp );
    
    return fp;
}

chNode * disAssemblyList( chNode *p, 
                          chNode **bigLetter, 
                          chNode **smallLetter, 
                          chNode **nums )
{
    while ( *bigLetter ) bigLetter = &( *bigLetter )->next;
    while ( *smallLetter ) smallLetter = &( *smallLetter )->next;
    while ( *nums ) nums = &( *nums )->next;

    chNode **head = &p;
    
    while ( *head != NULL )
    {
        if ( isdigit( ( unsigned char )( *head )->data ) )
        {
            *nums = *head;
            *head = ( *head )->next;
            ( *nums )->next = NULL;
            nums = &( *nums )->next;
        }
        else if ( isupper( ( unsigned char )( *head )->data ) )
        {
            *bigLetter = *head;
            *head = ( *head )->next;
            ( *bigLetter )->next = NULL;
            bigLetter = &( *bigLetter )->next;
        }
        else if ( islower( ( unsigned char )( *head )->data ) )
        {
            *smallLetter = *head;
            *head = ( *head )->next;
            ( *smallLetter )->next = NULL;
            smallLetter = &( *smallLetter )->next;
        }
        else
        {
            head = &( *head )->next;
        }
    }
    
    return p;
}   

int main(void) 
{
    chNode *head = NULL;
    
    assign( &head, "3a7MKu5#&P%A" );
    
    fputc( '\n', display( head, stdout ) );
    
    putchar( '\n' );
    
    chNode *bigLetter = NULL;
    chNode *smallLetter = NULL;
    chNode *nums = NULL;
    
    head = disAssemblyList( head, &bigLetter, &smallLetter, &nums );
    
    fputc( '\n', display( head, stdout ) );
    fputc( '\n', display( bigLetter, stdout ) );
    fputc( '\n', display( smallLetter, stdout ) );
    fputc( '\n', display( nums, stdout ) );
    
    clear( &head );
    clear( &bigLetter );
    clear( &smallLetter );
    clear( &nums );

    return 0;
}     

程序输出是

3 -> a -> 7 -> M -> K -> u -> 5 -> # -> & -> P -> % -> A -> null

# -> & -> % -> null
M -> K -> P -> A -> null
a -> u -> null
3 -> 7 -> 5 -> null

如果不允许使用标头 &lt;ctype.h&gt; 中的标准 C 函数,则函数 disAssemblyList 中的 while 循环可能看起来像

    while ( *head != NULL )
    {
        char c = ( *head )->data;

        if ( '0' <= c && c <= '9' )
        {
            *nums = *head;
            *head = ( *head )->next;
            ( *nums )->next = NULL;
            nums = &( *nums )->next;
        }
        else if ( 'A' <= c && c <= 'Z' )
        {
            *bigLetter = *head;
            *head = ( *head )->next;
            ( *bigLetter )->next = NULL;
            bigLetter = &( *bigLetter )->next;
        }
        else if ( 'a' <= c && c <= 'z' )
        {
            *smallLetter = *head;
            *head = ( *head )->next;
            ( *smallLetter )->next = NULL;
            smallLetter = &( *smallLetter )->next;
        }
        else
        {
            head = &( *head )->next;
        }
    }

【讨论】:

  • 我不能在这个练习中使用文件。
  • @PashaGrobov 有什么问题?不要使用它们。您可以使用自己的函数来输出列表。演示程序旨在展示如何实现拆分列表的功能。
  • 还是没有解决我的问题,第一个问题是我需要“从用户”扫描原始链表,还是不行。
  • @PashaGrobov 您关于如何编写拆分列表的函数的问题。我展示了这样一个函数定义。我们不在这里做你的功课。
  • @PashaGrobov 如果您在使用其他功能时遇到问题,那么您应该通过选择最佳答案来结束您的问题,并针对您的其他问题提出一个新问题。
【解决方案2】:

您的代码中有一些小问题和两个大问题。

首先是小问题:

  • 代码不包含所需的包含:

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

    好的,我假设它们存在于您的真实代码中(是,不是吗)

  • 代码声明了void main()。除了特殊情况(例如构建内核的独立环境),您必须使用int main() 并返回一个值

  • 您正在比较insert_Charlistwhile (ch != "\n") 中的charchar *。应该是:

      while (ch != '\n')
    
  • 您未能释放分配的内存。问题不大,因为它会在程序结束时返回到环境中,但最佳实践建议始终使用 free malloc-ed。

现在是严肃的。 add_to_other_listdisAssemblyList 两个基本功能都完全损坏。现在是学习如何使用调试器单步调试代码并查看会发生什么的时候了。更糟糕的是,它们的一般逻辑被打破了,我不得不重新编写它们:

void add_to_other_list(chNode** head, chNode* p)
{
    static chNode* tail;

    p->next = NULL;
    if (*head == NULL)
    {
        *head = p;
    }
    else
    {
        for (tail=*head; tail->next != NULL; tail = tail->next);  //skip to end of list
        tail->next = p;
    }
}

chNode* disAssemblyList(chNode* head, chNode **bigLetter, chNode **smallLetter, chNode **nums)
{
    chNode dummy = {0, head};  // build a dummy node to start one before current head
    chNode *p = &dummy;
    chNode* t;

    // Repeat as long as the list has minimum 1 element to process
    while (p->next)
    {
        if ((p->next->data >= 65) && (p->next->data) <= 90)
        {
            // Move p-next
            t = p->next;
            p->next = p->next->next;
            add_to_other_list(&(*bigLetter), t);
        }

        else if ((p->next->data >= 97) && (p->next->data) <= 122)
        {
            t = p->next;
            p->next = p->next->next;
            add_to_other_list(&(*smallLetter), t);
        }

        else if ((p->next->data >= 48) && (p->next->data) <= 57)
        {
            t = p->next;
            p->next = p->next->next;
            add_to_other_list(&(*nums), t);

        }
        else p = p->next;   // only advance p if p->next has not been moved
    }

    return dummy.next;

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-04-14
    • 2021-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多