简体   繁体   English

从.txt文件创建单链表并反转C中每行的奇数

[英]Creating a singly linked list from a .txt file and reversing odd numbers of each line in C

I have a project about linked lists but I'm having a hard time doing it.我有一个关于链表的项目,但我很难做到。 The teacher wants me to read a.txt file and create singly linked list from it.老师要我读一个.txt 文件并从中创建单链表。 After that, I need to reverse odd numbers of every line.之后,我需要反转每行的奇数。 Then print it.然后打印它。 Here is the code which I used for printing the linked list.这是我用于打印链接列表的代码。 But I need help to reverse the odd numbers of each line.但我需要帮助来反转每行的奇数。

This is the code which I used to print the list:这是我用来打印列表的代码:

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

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

typedef struct list LIST;

int main(void) {
    FILE *fp;
    char line[10];
    LIST *current, *head;

    head = current = NULL;
    fp = fopen("data.txt", "r");

    while(fgets(line, sizeof(line), fp)){
        LIST *node = malloc(sizeof(LIST));
        node->string = strdup(line);
        node->next =NULL;

        if(head == NULL){
            current = head = node;
        } else {
            current = current->next = node;
        }
    }
    fclose(fp);
    
    for(current = head; current ; current=current->next){
        printf("%s", current->string);
    }
    
    return 0;
}

Here is the content of the.txt file:这是.txt文件的内容:

10
9,6,11,7,12,18,19,14,15,13
13,14,9,12,15,3,18,20,1,2
4,11,8,17,12,15,20,10,3,16
19,4,11,1,13,17,12,16,20,18
1,6,20,11,13,9,7,16,10,2
12,4,11,16,3,20,9,19,17,15
20,3,10,12,18,2,5,14,15,16
18,19,15,2,6,9,1,3,17,4
7,6,20,1,11,4,3,5,8,16
1,2,16,13,17,10,12,9,4,15

"But I need help to reverse the odd numbers of each line." “但我需要帮助来扭转每行的奇数。”

There are several other parts that need to be considered before this step can be developed.在开发此步骤之前,还需要考虑其他几个部分。

Following are suggestions for a functions approach implementation using your problem description.以下是使用您的问题描述实现函数方法的建议。 A few items are simply suggestions to simplify the existing code.一些项目只是简化现有代码的建议。 And a few other steps, are not mentioned as necessary, but should be considered:还有一些其他步骤,没有提到必要的,但应该考虑:

  • Since you are not mandated to use char *string;由于您没有被强制使用char *string; in your problem description, choose to use a reasonable string length variable that does not require an additional layer of dynamic allocation, such as char string[260];在你的问题描述中,选择使用合理的string长度变量,不需要额外增加一层动态分配,比如char string[260]; (or even smaller to fit your input file.) This will greatly simplify the code. (甚至更小以适合您的输入文件。)这将大大简化代码。
  • Because the input file is sized with lines ~30 char long, declare the variable line to be at least large enough to contain one line, eg 80 would allow larger values, and still allow enough space, but since memory is cheap, go with the same size as is used in the string member of your linked list.因为输入文件的大小大约为 30 字符长,所以声明变量line至少足够大以包含一行,例如80将允许更大的值,并且仍然允许足够的空间,但是由于 memory 很便宜,go 与与链接列表的string成员中使用的大小相同。
  • Move the work of populating each new node to a function .将填充每个新节点的工作移至function It also will greatly simplify the program, and provide greater readability.它还将大大简化程序,并提供更大的可读性。 Eg: void insert(LIST **head_ref, char *str);例如: void insert(LIST **head_ref, char *str);
  • Always test the return of fopen() before attempting to use the file descriptor.在尝试使用文件描述符之前,始终测试fopen()的返回。
  • To manipulate the contents of each odd row (eg 1, 3, 5, 7, 9), as numbers, the contents of each line read in from a file as a string, needs to first be converted to a collection of numbers.要将每个奇数行(例如 1、3、5、7、9)的内容作为数字操作,从文件中作为字符串读取的每一行的内容需要首先转换为数字集合。 This suggests an additional member be added to the struct .这建议向struct添加一个额外的成员。 For example int num[10] .例如int num[10]
  • The previous observation implicitly suggests the need of an additional function to parse and convert each comma delimited string into discrete integer values.先前的观察暗示需要额外的function来解析每个逗号分隔的字符串并将其转换为离散的 integer 值。 Perhaps with the prototype: void parseIntArray(LIST **list);也许使用原型: void parseIntArray(LIST **list);
  • The next and final task also suggests an additional function to reverse the contents of selected array member integer arrays.下一个也是最后一个任务还建议使用额外的function来反转所选数组成员 integer arrays 的内容。 This one might use a prototype such as: void reverse_odd(LIST **list, size_t size);这可能使用原型,例如: void reverse_odd(LIST **list, size_t size);
  • Finally, because each node of LIST created required dynamically allocated memory, once finished using LIST, the memory must be given back to the OS to prevent memory leaks.最后,由于创建的 LIST 的每个节点都需要动态分配 memory,一旦使用完 LIST,必须将 memory 还给操作系统,以防止 memory 泄漏。 An additional function to do this could be prototyped: void freeList(LIST **head);可以制作一个额外的 function 原型: void freeList(LIST **head);

Following are the main() function and preceding support declarations etc. It is intended here to illustrate the above suggested steps, and the benefits of breaking down a bigger problem into smaller problems, then implementing each smaller solution to support the whole.以下是main() function 和前面的支持声明等。这里旨在说明上述建议的步骤,以及将较大的问题分解为较小的问题,然后实施每个较小的解决方案以支持整体的好处。 Benefits include for example readability and maintainability and potential re-use of code-base, (Note the similarity of argument lists in each supporting function.):好处包括例如可读性和可维护性以及代码库的潜在重用,(注意每个支持 function 中参数列表的相似性。):

#define MAX_STRLEN 260  //use mnemonic values to avoid magic numbers in code

struct list {
    char string[MAX_STRLEN];
    int arr[10];
    struct list *next;
};
typedef struct list LIST;

//Prototypes of 'smaller' solutions
void insert(LIST **head_ref, char *str);
void parseIntArray(LIST **list);
void reverse_odd(LIST **list, size_t size);
void freeList(LIST **head);

int main(void) 
{
    FILE *fp;
    char line[MAX_STRLEN];
    LIST *current, *head;
    char *convPtr = NULL;

    head = current = NULL;
    fp = fopen("data.txt", "r");
    if(fp)
    {
        //consume 1st line
        if(fgets(line, sizeof(line), fp));//10
        {
            sizeArray = strtol(line, &convPtr, 10);
            if(errno != ERANGE)
            {
                while(fgets(line, sizeof(line), fp))
                {
                    //(see implementations of each below)
                    //create new node, insert num string
                    insert(&current, line);
                    //convert new->string to integers, place in new->array
                    parseIntArray(&current);
                    //reverse 'odd' contents of each array
                    reverse_odd(&current, sizeArray);
                }
            }else{//handle error and leave}
        }
        fclose(fp);
    }else{//handle error and leave}
    //At this point in code, entire file is captured into nodes of list.  
    //use list as needed
    //When finished using list, memory must  be freed to prevent memory leaks
    head = current;
    freeList(&head);

    return 0;
}

The remaining code segments are the function implementations used above:其余代码段是上面使用的 function 实现:

void freeList(LIST **head)
{
   LIST *tmp;

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

//create new node, insert num string
void insert(LIST **head_ref, char *str)  
{  
    int *arr = malloc(numNodes * sizeof(*arr));
    //allocate node
    LIST* new = calloc(1, sizeof(*new)); 

    //put in the data
    strcpy(new->string, str); 

    //Make next of new node as head
    new->next = (*head_ref);  

    //Move the head to point to the new node
    (*head_ref) = new;  
}  
//convert new->string to integers, place in list->array
void parseIntArray(LIST **list)
{
    char *tok = NULL;
    int i = 0;
    int tmp = 0;
    char *sArray = strdup((*list)->string);
    tok = strtok(sArray, ",\n ");
    while(tok)
    {
        errno = 0;
        tmp = atoi(tok);
        if(errno == ERANGE)
        {
            printf("Error converting string to number\nExiting.");
            return;
        }
        (*list)->arr[i] = tmp;
        i++;
        tok = strtok(NULL, ",\n "); 
    }
}
//reverse 'odd' contents of list->array              
void reverse_odd(LIST **list, size_t size)
{
    int *ptr = &((*list)->arr[0]);
    int *tmp = malloc(size * sizeof(*tmp));
    memset(tmp, -1, size*sizeof(*tmp));
    for(int i=0;i<size;i++)
    {
        if(ptr[i]%2 != 0) 
                tmp[size-1-i] = ptr[i];
    }
    for(int i=0;i<size;i++)
    {
        if(tmp[i] < 0)
        {
            while((*ptr)%2 != 0 ) ptr++;
            tmp[i] = *ptr;
            ptr++;
        }
    }
    memcpy((*list)->arr, tmp, size*sizeof(int));
}

This hope this code will do the job.这希望这段代码能完成这项工作。

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

typedef struct line {
    struct num *first;
    struct line *next;
} LineNode;

typedef struct num {
    int num;
    int order;
    struct num *next;
} NumNode;

int main() {
    FILE *fp;
    char ch;
    int counter = 0;
    NumNode *curr_num, *even_ptr, *odd_ptr, *odd_head, *even_head;
    LineNode *curr_line, *line_head;

    curr_num = even_head = odd_head = even_ptr = odd_ptr = NULL;
    line_head = curr_line = NULL;
    fp = fopen("data.txt", "r");

    if (fp == NULL)
    {
        return 1;
    }
    
    ch = fgetc(fp);
    while(ch != EOF){
        if (ch >= 48 && ch <= 57)
        {
            int n = 0;
            while (ch != EOF && ch != '\n' && ch >= 48 && ch <= 57)
            {
                int x = ch - 48;
                n = n * 10 + x;
                ch = fgetc(fp);
            }
            NumNode *node = malloc(sizeof(NumNode));
            node->num = n;
            node->order = counter;
            node->next =NULL;

            if (n % 2 == 0){
                if(even_head == NULL){
                    even_head = even_ptr = node;
                } else {
                    even_ptr = even_ptr->next = node;
                }
            }else{
                if(odd_head == NULL){
                    odd_head = node;
                } else {
                    node->next = odd_head;
                    odd_head = node;
                }
            }

            counter++;
        }
        

        if (ch == '\n' || ch == EOF)
        {
            NumNode *num_node, *head;
            num_node  = head = NULL;
            even_ptr = even_head;
            odd_ptr = odd_head;
            counter = 0;

            if (even_head != NULL && even_head->order == counter){
                head = num_node = even_ptr;
                even_ptr = even_ptr->next;
            } else {
                head = num_node = odd_ptr;
                odd_ptr = odd_ptr->next;
            }
            
            counter++;

            while (even_ptr != NULL)
            {
                if (even_ptr->order == counter) {
                    num_node = num_node->next = even_ptr;
                    even_ptr = even_ptr->next;
                } 
                else if (odd_ptr != NULL) {
                    num_node = num_node->next = odd_ptr;
                    odd_ptr = odd_ptr->next;
                }

                counter++;
            }

            while (odd_ptr != NULL)
            {
                num_node = num_node->next = odd_ptr;
                odd_ptr = odd_ptr->next;
            }
            
            
            LineNode *node = malloc(sizeof(LineNode));
            node->next =NULL;
            node->first = head;
            if (line_head == NULL)
                line_head = curr_line = node;
            else
                curr_line = curr_line->next = node;

            odd_head = even_head = NULL;
            counter = 0;
        }

        ch = fgetc(fp);
    }
    fclose(fp);

    for(curr_line = line_head; curr_line != NULL ; curr_line=curr_line->next) {
        for(curr_num = curr_line->first; curr_num != NULL ; curr_num=curr_num->next) {
            printf("%d", curr_num->num);
            if (curr_num->next != NULL)
                printf(",");
        }
        printf("\n");
    }
    
    return 0;
}

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

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