2015-11-24 107 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

之間我認爲這是一個更好的主意重疊表的比較運營商,然後那種後您的一些列表存在的算法。

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約翰呢?),並在prevcur之間插入,或者在family之間插入,如果prevNULL

for循環看起來很醜陋:很難閱讀,很容易出錯。編寫一個單獨的比較函數,該函數需要2個節點,並根據電話簿順序返回-1, 0, +1。您將使用append_to_listdelete_from_list這個函數,編寫更少的代碼,更具可讀性和更一致。

+0

您提到的比較函數在某些語言中有時稱爲'太空船'運算符<=>。 – ChuckCottrill

+0

@ChuckCottrill:飛船運營商來自Perl。我不確定我後悔沒有在C ...'<=>'會在C中作爲2個左值之間的交換運算符更有用。 – chqrlie

+0

是的,perl(numerics),ruby(http://stackoverflow.com/questions/26581619/rubys-operator-and-sort-method),php,python(spelled cmp)和ocaml(spelled compare)。 – 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) 

循環將不會執行:

(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

提示:有關刪除無用的代碼。 歡呼!