我正在编写一个包含姓名和年龄的程序。然后可以调用这些名称,并打印出该人的年龄。如果该人不在列表中,则将其年龄打印为-1。如果使用列表中已有的新年龄输入名称,则不会添加新条目。目前看来名称按我输入的顺序排序。如何通过仅更改函数add的代码按字母顺序对它们进行排序?此代码是可编译的,除了非按字母顺序排列的列表外,可以按预期工作。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct person {
char *name;
int age;
struct person *next;
} Person;
void print(Person *); // prints the entire list
Person *add(Person *, char *, int); // adds a new node to the list
int getAge(Person *, char *); // returns the age of the person or -1 if not found
int main(void) {
char input1[100];
int input2;
Person *myList = NULL;
printf("Enter a person's name (one word) and age : ");
scanf("%s %d", input1, &input2);
while (input2 != 0) {
myList = add (myList, input1, input2);
printf("\n\nThe list is now : "); print(myList);
printf("Enter a name (one word) and age, enter 'xxx' and 0 to exit : ");
scanf("%s %d", input1, &input2);
}
printf("\n\nThe final list is "); print(myList);
printf("\n\nEnter the name of a person to look up their age : ");
scanf("%s", input1);
while ( strcmp(input1, "xxx") != 0 ) {
printf("\t%s is %d years old\n", input1, getAge(myList, input1) );
printf("Enter a name to look up their age or 'xxx' to exit : ");
scanf("%s", input1);
}
return 0;
}
void print(Person *ptr) {
while (ptr) { printf("[%s-%d] ", ptr->name, ptr->age); ptr = ptr->next; }
printf("\n");
return;
}
//adds person to list if the person does not exist already
Person *add(Person *ptr, char *n, int a) {
Person *newNode = malloc( sizeof(Person) );
int duplicate = 1;
Person *dummy = ptr;
while (dummy) {
if(strcmp(dummy->name, n) == 0) {
printf("Name Already Exists in List! Please retry with other name..\n");
duplicate=-1;
break;
}
else
dummy = dummy->next;
}
if (duplicate!=-1) {
newNode->name = malloc( strlen(n) + 1 );
strcpy(newNode->name, n);
newNode->age = a;
newNode->next = ptr;
return newNode;
}
duplicate = 1;
return ptr;
}
//function to find age of the passed person
int getAge(Person *ptr, char *name) {
while (ptr) {//while loop to traverse entire linked list elements (All persons one by one)
if(strcmp(ptr->name, name) == 0) //comparing person name in the list with the search key name
return ptr->age; //if found, returning the age of that person
else
ptr = ptr->next; //if not found, check in next node of linked list
}
return -1; // if not found, even after visting all nodes, return -1
}
答案 0 :(得分:1)
您可以进行插入排序。每次添加新记录时,都会扫描列表以查看它所属的位置并将其插入其中。这可以与扫描重复项结合使用。
Person *add(Person *head, char *n, int a) {
char empty[1] = "";
Person sentinel = {0};
sentinel.name = empty;
sentinel.next = head;
Person *p = &sentinel;
while (p) {
int cmp = p->next ? strcmp(n, p->next->name) : -1;
if (cmp == 0) {
printf("Name Already Exists in List! Please retry with another name..\n");
break;
}
if (cmp < 0) {
Person *newNode = malloc( sizeof(Person) );
newNode->name = malloc( strlen(n) + 1 );
strcpy(newNode->name, n);
newNode->age = a;
newNode->next = p->next;
p->next = newNode;
break;
}
p = p->next;
}
return sentinel.next; // a possibly-updated copy of head
}
插入排序总是将新元素与 next 元素(而不是当前元素)进行比较。这使得处理第一个元素变得笨拙,特别是在列表中。我们用一个临时的&#34;哨兵&#34;来解决这个问题。我们假装的就在名单的前面。
还有其他方法。您可以在列表的开头创建新节点,然后向下滑动直到它处于适当位置。如果遇到重复项,则删除新项并修补列表。其他数据结构中的插入排序通常从尾部朝向头部进行,但是不能使用单链表。
答案 1 :(得分:1)
我写了类似的地方,我对学生ID进行了分类。你应该尝试进行交换。声明一个临时变量并用它来交换。代码就像是。
int temp,
first_name,
last_name;
temp = first_name;
first_name = last_name;
last_name = temp;
希望能给你一个想法!
编辑:对方建议的是一个好主意,插入排序。
答案 2 :(得分:0)
您的问题已经得到解答,但我想指出另一种添加节点的方法。该列表由其头节点定义。当使用元素时,头节点可以改变。 (它将在您当前的代码中更改,这会在前面添加元素。)为了反映更改,您将返回新头:
myList = add(myList, input1, input2);
这是多余的,因为您必须指定myList
两次。丢弃函数返回的结果也是合法的,因此可能会出错。如果传入指向头指针的指针,则将消除冗余。
添加(&amp; myList,input1,input2);
'&amp; will indicate that
myList`可能会改变。现在,您可以将返回值用于其他内容,例如指向新插入节点的指针,如果名称已存在,则返回null。
在前面插入一个人(无条件)看起来像这样:
Person *add_front(Person **ptr, const char *name, int age)
{
Person *p = person_new(name, age);
p->next = *ptr;
*ptr = p;
return p;
}
最后插入需要首先遍历列表:
Person *add_back(Person **ptr, const char *name, int age)
{
Person *p = person_new(name, age);
while (*ptr) {
ptr = &(*ptr)->next;
}
p->next = *ptr;
*ptr = p;
return p;
}
请注意,您不需要将空列表视为特殊情况。 Adrian的解决方案消除了具有哨兵元素的特殊情况。在这里,它被指针本身消除:ptr
首先指向调用函数中的列表头指针。当您浏览列表时,它指向前一个节点的next
指针。更新*ptr
更新了将我们带到当前节点的指针。
函数person_new
创建一个新节点。我发现将它作为一个单独的函数更加温和,您可以从其他函数调用它:
Person *person_new( const char *name, int age)
{
Person *p = malloc(sizeof(*p));
p->name = malloc(strlen(name) + 1);
strcpy(p->name, name);
p->age = age;
p->next = NULL;
return p;
}
现在,您想要的函数按字母顺序插入节点,如下所示:
Person *add(Person **ptr, const char *name, int age)
{
while (*ptr && strcmp((*ptr)->name, name) < 0) {
ptr = &(*ptr)->next;
}
if (*ptr == NULL || strcmp((*ptr)->name, name) != 0) {
Person *p = person_new(name, age);
p->next = *ptr;
*ptr = p;
return p;
}
return NULL;
}
当您按名称查找节点时,如果当前节点按字母顺序大于您要查找的名称,则可以停止搜索:
const Person *find(const Person *ptr, const char *name)
{
while (ptr) {
int cmp = strcmp(ptr->name, name);
if (cmp > 0) break;
if (cmp == 0) return ptr;
ptr = ptr->next;
}
return NULL;
}
您可以在行动here中看到代码。