2015-11-24 2 views
1

Эта программа должна создать отсортированный список и отсортировать каждого пользователя по имени и фамилии. Я не могу понять, как правильно сортировать имена.C Сортированный связанный список программ

У меня только проблема с функцией append_to_list, остальные функции работают нормально.

Когда я первый начать ввод названия:

user ID: Last Name: First Name: 
3    Alex   Alex 
2    Jones   Alex 
1    andrew  john 

сортирует хорошо, пока я не ввести имя, которое должно сортировать два между ними имен , когда я ввожу имя Эндрю, Алекс это происходит.

user ID: Last Name: First Name: 
4    Andrew  Alex 
3    Alex   Alex 
2    Jones   Alex 
1    andrew  john 

но Эндрю, Алекс должен быть между пользователем 2 и 3


#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include "user.h" 
#include "readline.h" 

// function append_to_list takes user input from user, id, name and puts it  to the end of the list 
// as well as sorts each name alphabetically 
struct user *append_to_list(struct user *family) 
{ 
    struct user *cur, *prev, *new_node; 

    // generate memory 
    new_node = malloc(sizeof(struct user)); 

    if (new_node == NULL) { 
     printf("malloc failed in append\n"); 
     return family; 
    } 

    printf("Enter user ID: \n"); 
    scanf("%d", &new_node->number); 
    printf("Enter user last name: \n"); 
    read_line(new_node->last_name,NAME_LEN); 
    printf("Enter user first name: \n"); 
    read_line(new_node->first_name,NAME_LEN); 

    for(cur=family; cur != NULL; cur = cur->next) { 
     if (new_node->number == cur->number) { 
       printf("user already exists: %s, %s\n",new_node->first_name,  new_node->last_name); 
       free(new_node); 
       return family; 
     } 
    }  
    for (cur=family, prev = NULL; cur != NULL 
     && (strcmp(new_node->first_name,cur->first_name) < 0) 
     && (strcmp(new_node->last_name,cur->last_name) < 0); 
      prev = cur, cur = cur->next) { 

     if((strcmp(new_node->last_name,cur->last_name) < 0)) break; 

     if((strcmp(new_node->first_name,cur->first_name) == 0)) 

     if((strcmp(new_node->first_name,cur->first_name) < 0)) break; 
     ; 
     } 
     // use strcmp == 0 to see if name already exists 
     if (cur != NULL && (strcmp(new_node->first_name,cur->first_name) == 0) 
      && (strcmp(new_node->last_name,cur->last_name)) == 0) 
     { 
       printf("user already exists: %s, %s\n",new_node->first_name, new_node->last_name); 
       free(new_node); 
       return family; 
     } 

    // append the linkedlist to the end 
    new_node->next = cur; 
    // check to see if the node is empty 
    if (prev == NULL) { 
     return new_node; 
    } else { 
     prev->next = new_node->next; 
     return family; 
    } 
} 
// function delete_from_list removes a user from the family 
struct user* delete_from_list(struct user *family) 
{ 
    struct user *prev, *cur; 
    int id; 
    int not_found = 0; 
    printf("Enter user ID: \n"); 
    scanf("%d", &id); 

    for (cur = family, prev = NULL; cur != NULL; prev = cur, cur = cur->next) { 
     if (id == cur->number) { 
       // if only one user on family 
      if (prev == NULL) { 
       family = cur->next; 
      // if user is in the middle of family 
      // connects prev node to cur node 
      } else { 
       prev->next = cur->next; 
      } 
      printf("user deleted: %s ,%s\n",cur->first_name, cur->last_name); 
      free(cur); 
     } 
     else 
      not_found = 1; 
    } 
    if (not_found == 1) { 
     printf("user not found\n"); 
    } 
    return family; 
} 
// function find_user searches the family by ID and matches it with the users name 
void find_user(struct user *family) 
{ 
    struct user *p = family; 
    int id; 
    int count = 0; 
printf("Enter user ID: \n"); 
scanf("%d", &id); 

    // compares the family with the user entered ID 
    // if the ID is the same count set to 1 
    if (p != NULL) { 
     for (p = family; p != NULL; p = p->next) { 
      if (id == p->number) { 
       count = 1; 
       break; 
      } 
     } 
    } 
    // if count is 1 we know the function found that specific user 
    if (count == 1) { 
     printf("user found: %s, %s\n", p->last_name, p->first_name); 
    } else { 
     printf("user not found"); 
    } 
} 

// function printList prints the entire family 
void printList(struct user *family) 
{ 
    struct user *p; 
    printf("user ID:\tLast Name:\tFirst Name:\n"); 
    for (p = family; p != NULL; p = p->next) { 
     printf("%d\t\t%s\t\t%s\n", p->number, p->last_name, p->first_name); 
    } 

} 

// function clearList clears the entired linked list 
void clearList(struct user *family) 
{ 
    struct user *p; 
    while (family != NULL) { 
     p = family; 
     family = family->next; 
     if (p != NULL) { 
      free(p); 
     } 
    } 
} 
+0

Почему у вас есть сопоставление имен как в условии завершения цикла, так и в теле цикла в 'append_to_list()'? –

+0

В любом случае, я думаю, что сравнения в состоянии завершения и в теле цикла являются * оба * неправильными. Как минимум, случай с тем же именем, по-видимому, обрабатывается неправильно в обоих местах. –

ответ

0

Я думаю, что это лучшая идея, чтобы перекрыть операторы Comparation, а затем, после такого рода вашего списка с некоторыми существующих алгоритмов.

1

Проблема заключается в том, как вы сравнить узлы:

for (cur=family, prev = NULL; cur != NULL 
    && (strcmp(new_node->first_name,cur->first_name) < 0) 
    && (strcmp(new_node->last_name,cur->last_name) < 0); 
     prev = cur, cur = cur->next) { ... } 

Вы должны пропустить узлы, которые имеют меньшую семью или (то же имя, семья и меньшее имя). Исправьте сравнение таким образом:

for (cur=family, prev = NULL; 
    cur != NULL 
    && ((strcmp(new_node->first_name, cur->first_name) < 0) 
    || ((strcmp(new_node->first_name, cur->first_name) == 0) 
    && (strcmp(new_node->last_name,cur->last_name) < 0))); 
    prev = cur, cur = cur->next) { ... } 

И упростите последующий код. На самом деле вам не нужен какой-либо код. Цикл будет остановлен в точке ввода. Просто проверьте, существует ли одна и та же фамилия и имя (но что, если есть 2 Джона Делает?) И вставьте между prev и cur, или до family, если prev - NULL.

Цикл for выглядит уродливым: трудно читать, легко ошибаться. Напишите отдельную функцию сравнения, которая принимает 2 узла и возвращает -1, 0, +1 согласно заказу телефонной книги. Вы будете использовать эту функцию для append_to_list и delete_from_list, написав меньше кода, более читаемый и более согласованный.

+0

Функция сравнения, которую вы упоминаете, иногда называется оператором «космический корабль» <=> на некоторых языках. – ChuckCottrill

+0

@ChuckCottrill: Оператор космического корабля прибывает из Perl. Я не уверен, что сожалею о том, что не имею его в C ... '<=>' было бы более полезным в C в качестве оператора обмена между 2 lvalues. – chqrlie

+0

Да, perl (численные значения), ruby ​​(http://stackoverflow.com/questions/26581619/rubys-operator-and-sort-method), php, python (пишется на cmp) и ocaml (с помощью сравнения). – ChuckCottrill

0

У вас есть проблемы с условиями в этом цикле:

for (cur=family, prev = NULL; 
     cur != NULL && (strcmp(new_node->first_name,cur->first_name) < 0) 
        && (strcmp(new_node->last_name,cur->last_name) < 0); 
       prev = cur, cur = cur->next) 

Loop не будет выполняться:

(cur=family, family exist) 
cur != NULL -> True 
(Alex == Alex) 
((strcmp(new_node->first_name,cur->first_name) -> 0) < 0 -> False 
(Andrew > Alex) 
((strcmp(new_node->last_name,cur->last_name) -> 1) < 0 -> False 
True && False && False -> False 

В результате, вы будете добавлять новую запись в самом начале.

Далее в цикле у вас плохой 'если' код:

if((strcmp(new_node->first_name,cur->first_name) == 0)) 

if((strcmp(new_node->first_name,cur->first_name) < 0)) break; 
; 

Doc. strcmp

Подсказка: Удалить бесполезный код в вопросе. Cheer!

Смежные вопросы