C 关于实现多链接列表

C 关于实现多链接列表,c,linked-list,C,Linked List,我正在做一个类似于通讯录的项目。首先,我们在一个文本文件中有一些学生。我将实现一个多链接列表,该列表有2个头+尾指针(头+尾指针表示姓名)。这些指针显示相同的列表,但位置不同,因为我按升序添加节点,并使用双指针向后打印列表。问题是,我通过按名称和姓氏添加节点来实现列表,当我插入另一个节点时,操作成功。但我意识到,当我按她/他的“姓名”删除节点并再次打印列表时,该学生不存在,但当我按“姓氏”打印列表时,该学生确实存在。然后,我认识到我实现了两个独立的链表。我被告知只实现一个添加和删除功能。但是,如

我正在做一个类似于通讯录的项目。首先,我们在一个文本文件中有一些学生。我将实现一个多链接列表,该列表有2个头+尾指针(头+尾指针表示姓名)。这些指针显示相同的列表,但位置不同,因为我按升序添加节点,并使用双指针向后打印列表。问题是,我通过按名称和姓氏添加节点来实现列表,当我插入另一个节点时,操作成功。但我意识到,当我按她/他的“姓名”删除节点并再次打印列表时,该学生不存在,但当我按“姓氏”打印列表时,该学生确实存在。然后,我认识到我实现了两个独立的链表。我被告知只实现一个添加和删除功能。但是,如何将节点的名字指针和姓氏指针一起添加呢?我希望我能理解地解释我的问题。下面是我的代码块

我的结构:

typedef struct node {
    int birth_date;
    int zipcode;
    int phone_num;
    char first_name[50];
    char last_name[50];
    char city[50];
    char address[50];
    char email_addr[50];

    struct node* fn_next;
    struct node* fn_pre;
    struct node* ln_next;
    struct node* ln_pre;
    struct node* birdat_next;
    struct node* birdat_pre;
} NODE;

typedef struct {
    int fn_count;
    int ln_count;

    NODE* fn_head;
    NODE* ln_head;

    NODE* fn_tail;
    NODE* ln_tail;
}LIST;
我逐行读取文件并调用add函数的代码块:

while ( !feof(myfile) ) {
    NODE* pnew_stu;

    if( !(pnew_stu = (NODE*) malloc(sizeof(NODE))) ) {
        printf("ERROR NOT ENOUGH MEMORY!!!\n");
        exit(100);
    }

    fscanf(myfile,"%s", &(pnew_stu->first_name) );
    fscanf(myfile,"%s", &(pnew_stu->last_name) );
    fscanf(myfile,"%s", &(pnew_stu->email_addr) );
    fscanf(myfile,"%d", &(pnew_stu->phone_num) );
    fscanf(myfile,"%s", &(pnew_stu->address) );
    fscanf(myfile,"%s", &(pnew_stu->city) );
    fscanf(myfile,"%d", &(pnew_stu->zipcode) );

    add_Node(list,pnew_stu);
}
void add_fn_Node(LIST* list, NODE* pnew_stu) {
    NODE* temp = list->fn_head;

    if( list->fn_head == NULL ) {
        pnew_stu->fn_next = list->fn_head;
        pnew_stu->fn_pre = list->fn_head;

        list->fn_head = pnew_stu;
        list->fn_count = 1;
        return;
    }
    else {
        if ( (strcmp( pnew_stu->first_name, temp->first_name )) <= 0 ) { // Basa Ekleme Kosulu
            pnew_stu->fn_next = temp;
            pnew_stu->fn_pre = temp->fn_pre;
            temp->fn_pre = pnew_stu;

            list->fn_head = pnew_stu;
            list->fn_count++;   
            return;
        }
        else {
            while ( temp->fn_next != NULL ) { // Ortaya Ekleme Kosulu
                if ( (strcmp( pnew_stu->first_name, temp->first_name ) >= 0 ) && (strcmp( pnew_stu->first_name, temp->fn_next->first_name) < 0)) {
                    pnew_stu->fn_next = temp->fn_next;
                    pnew_stu->fn_pre = temp;
                    temp->fn_next->fn_pre = pnew_stu;
                    temp->fn_next = pnew_stu;

                    list->fn_count++;
                    return;
                }

                temp = temp->fn_next;
            }
            if ( temp->fn_next == NULL ) { // Sona Ekleme Kosulu
                temp->fn_next = pnew_stu;
                pnew_stu->fn_pre = temp;
                pnew_stu->fn_next = NULL;

                list->fn_tail = pnew_stu;
                list->fn_count++;
                return;
            }
        }
    }
}

void add_ln_Node(LIST* list, NODE* pnew_stu) {
    NODE* temp = list->ln_head;

    if( list->ln_head == NULL ) {
        pnew_stu->ln_next = list->ln_head;
        pnew_stu->ln_pre = list->ln_head;

        list->ln_head = pnew_stu;
        list->ln_count = 1;
        return;
    }
    else {
        if ( (strcmp( pnew_stu->last_name, temp->last_name )) <= 0 ) { // Basa Ekleme Kosulu
            pnew_stu->ln_next = temp;
            pnew_stu->ln_pre = temp->ln_pre;
            temp->ln_pre = pnew_stu;

            list->ln_head = pnew_stu;
            list->ln_count++;
            return;
        }
        else {
            while ( temp->ln_next != NULL ) { // Ortaya Ekleme Kosulu
                if ( (strcmp( pnew_stu->last_name, temp->last_name ) >= 0 ) && (strcmp( pnew_stu->last_name, temp->ln_next->last_name) < 0)) {
                    pnew_stu->ln_next = temp->ln_next;
                    pnew_stu->ln_pre = temp;
                    temp->ln_next->ln_pre = pnew_stu;
                    temp->ln_next = pnew_stu;

                    list->ln_count++;

                    return;
                }
                temp = temp->ln_next;
            }
            if ( temp->ln_next == NULL ) { // Sona Ekleme Kosulu
                temp->ln_next = pnew_stu;
                pnew_stu->ln_pre = temp;
                pnew_stu->ln_next = NULL;

                list->ln_tail = pnew_stu;

                list->ln_count++;

                return;
            }
        }
    }
}
void del_fn_name(LIST* list, char* str_key) {
    NODE* temp;

    int num,counter=1,flag;

    temp = list->fn_head;

    if( list->fn_head == NULL ) {
        printf("The list is EMPTY!!!\n");
        return;
    }

    flag = search_fn(list,str_key);

    if ( flag ) {
        printf("Enter the number of student you want to delete : ");
        scanf("%d", &num);

        if( strcmp( list->fn_head->first_name, str_key ) == 0 ) { // Bastan Silme Kosulu
            if( num == counter ) {
                list->fn_head->fn_next->fn_pre = list->fn_head;
                list->fn_head = list->fn_head->fn_next;
                free(list->fn_head);

                printf("%s is deleted and the new header is %s\n", str_key, list->fn_head->first_name );
                return;
            }
            counter++;
        }
        temp = temp->fn_next;

        while ( temp->fn_next != NULL ) {
            if( strcmp( temp->first_name, str_key ) == 0 ) {
                if( num == counter ) {
                    temp->fn_pre->fn_next = temp->fn_next;
                    temp->fn_next->fn_pre = temp->fn_pre;
                    free(temp);
                    printf("%s deleted at between %s  and  %s\n", str_key, temp->fn_pre->first_name, temp->fn_next->first_name);
                    return;
                }
                counter++;
            }
            temp = temp->fn_next;
        }

        if( temp->fn_next == NULL ) { // Sondan Silme Kosulu
            if( strcmp(temp->first_name, str_key) == 0 ) {
                if( num == counter ) {
                    list->fn_tail = temp->fn_pre;
                    temp->fn_pre->fn_next = NULL;
                    free(temp);
                    printf("%s deleted at the end and new tail is %s \n", str_key, list->fn_tail->first_name );
                    return;
                }
            }
        }
    }

void del_ln_name(LIST* list, char* str_key) {
    NODE* temp;
    int num,counter=1,flag;
    temp = list->ln_head;

    if( list->ln_head == NULL ) {
        printf("The list is EMPTY!!!\n");
        return;
    }

    flag = search_ln(list,str_key);

    if ( flag ) {
        printf("Enter the number of student you want to delete : ");
        scanf("%d", &num);

        if( strcmp( list->ln_head->last_name, str_key ) == 0 ) { // Bastan Silme Kosulu
            if( num == counter ) {
                temp->ln_next->ln_pre = list->ln_head;
                list->ln_head = temp->ln_next;
                free(temp);

                printf("%s is deleted and the new header is %s\n", str_key, list->ln_head->last_name );
                return;
            }
            counter++;
        }
        temp = temp->ln_next;
        while ( temp->ln_next != NULL ) {
            if( strcmp( temp->last_name, str_key ) == 0 ) {
                if( num == counter ) {
                    temp->ln_pre->ln_next = temp->ln_next;
                    temp->ln_next->ln_pre = temp->ln_pre;
                    free(temp);

                    printf("%s deleted at between %s  and  %s\n", str_key, temp->ln_pre->last_name, temp->ln_next->last_name);
                    return;
                }
                counter++;
            }
            temp = temp->ln_next;
        }

        if( temp->ln_next == NULL ) { // Sondan Silme Kosulu
            printf("The last item %s second last item %s\n", temp->first_name, list->fn_tail->fn_pre->first_name);*/
            if( strcmp(temp->last_name, str_key) == 0 ) {
                if( num == counter ) {
                    list->ln_tail = temp->ln_pre;
                    temp->ln_pre->ln_next = NULL;
                    free(temp);

                    printf("%s deleted at the end and new tail is %s \n", str_key, list->ln_tail->last_name );
                    return;
                }
            }
        }
    }
最后是我的添加函数:

while ( !feof(myfile) ) {
    NODE* pnew_stu;

    if( !(pnew_stu = (NODE*) malloc(sizeof(NODE))) ) {
        printf("ERROR NOT ENOUGH MEMORY!!!\n");
        exit(100);
    }

    fscanf(myfile,"%s", &(pnew_stu->first_name) );
    fscanf(myfile,"%s", &(pnew_stu->last_name) );
    fscanf(myfile,"%s", &(pnew_stu->email_addr) );
    fscanf(myfile,"%d", &(pnew_stu->phone_num) );
    fscanf(myfile,"%s", &(pnew_stu->address) );
    fscanf(myfile,"%s", &(pnew_stu->city) );
    fscanf(myfile,"%d", &(pnew_stu->zipcode) );

    add_Node(list,pnew_stu);
}
void add_fn_Node(LIST* list, NODE* pnew_stu) {
    NODE* temp = list->fn_head;

    if( list->fn_head == NULL ) {
        pnew_stu->fn_next = list->fn_head;
        pnew_stu->fn_pre = list->fn_head;

        list->fn_head = pnew_stu;
        list->fn_count = 1;
        return;
    }
    else {
        if ( (strcmp( pnew_stu->first_name, temp->first_name )) <= 0 ) { // Basa Ekleme Kosulu
            pnew_stu->fn_next = temp;
            pnew_stu->fn_pre = temp->fn_pre;
            temp->fn_pre = pnew_stu;

            list->fn_head = pnew_stu;
            list->fn_count++;   
            return;
        }
        else {
            while ( temp->fn_next != NULL ) { // Ortaya Ekleme Kosulu
                if ( (strcmp( pnew_stu->first_name, temp->first_name ) >= 0 ) && (strcmp( pnew_stu->first_name, temp->fn_next->first_name) < 0)) {
                    pnew_stu->fn_next = temp->fn_next;
                    pnew_stu->fn_pre = temp;
                    temp->fn_next->fn_pre = pnew_stu;
                    temp->fn_next = pnew_stu;

                    list->fn_count++;
                    return;
                }

                temp = temp->fn_next;
            }
            if ( temp->fn_next == NULL ) { // Sona Ekleme Kosulu
                temp->fn_next = pnew_stu;
                pnew_stu->fn_pre = temp;
                pnew_stu->fn_next = NULL;

                list->fn_tail = pnew_stu;
                list->fn_count++;
                return;
            }
        }
    }
}

void add_ln_Node(LIST* list, NODE* pnew_stu) {
    NODE* temp = list->ln_head;

    if( list->ln_head == NULL ) {
        pnew_stu->ln_next = list->ln_head;
        pnew_stu->ln_pre = list->ln_head;

        list->ln_head = pnew_stu;
        list->ln_count = 1;
        return;
    }
    else {
        if ( (strcmp( pnew_stu->last_name, temp->last_name )) <= 0 ) { // Basa Ekleme Kosulu
            pnew_stu->ln_next = temp;
            pnew_stu->ln_pre = temp->ln_pre;
            temp->ln_pre = pnew_stu;

            list->ln_head = pnew_stu;
            list->ln_count++;
            return;
        }
        else {
            while ( temp->ln_next != NULL ) { // Ortaya Ekleme Kosulu
                if ( (strcmp( pnew_stu->last_name, temp->last_name ) >= 0 ) && (strcmp( pnew_stu->last_name, temp->ln_next->last_name) < 0)) {
                    pnew_stu->ln_next = temp->ln_next;
                    pnew_stu->ln_pre = temp;
                    temp->ln_next->ln_pre = pnew_stu;
                    temp->ln_next = pnew_stu;

                    list->ln_count++;

                    return;
                }
                temp = temp->ln_next;
            }
            if ( temp->ln_next == NULL ) { // Sona Ekleme Kosulu
                temp->ln_next = pnew_stu;
                pnew_stu->ln_pre = temp;
                pnew_stu->ln_next = NULL;

                list->ln_tail = pnew_stu;

                list->ln_count++;

                return;
            }
        }
    }
}
void del_fn_name(LIST* list, char* str_key) {
    NODE* temp;

    int num,counter=1,flag;

    temp = list->fn_head;

    if( list->fn_head == NULL ) {
        printf("The list is EMPTY!!!\n");
        return;
    }

    flag = search_fn(list,str_key);

    if ( flag ) {
        printf("Enter the number of student you want to delete : ");
        scanf("%d", &num);

        if( strcmp( list->fn_head->first_name, str_key ) == 0 ) { // Bastan Silme Kosulu
            if( num == counter ) {
                list->fn_head->fn_next->fn_pre = list->fn_head;
                list->fn_head = list->fn_head->fn_next;
                free(list->fn_head);

                printf("%s is deleted and the new header is %s\n", str_key, list->fn_head->first_name );
                return;
            }
            counter++;
        }
        temp = temp->fn_next;

        while ( temp->fn_next != NULL ) {
            if( strcmp( temp->first_name, str_key ) == 0 ) {
                if( num == counter ) {
                    temp->fn_pre->fn_next = temp->fn_next;
                    temp->fn_next->fn_pre = temp->fn_pre;
                    free(temp);
                    printf("%s deleted at between %s  and  %s\n", str_key, temp->fn_pre->first_name, temp->fn_next->first_name);
                    return;
                }
                counter++;
            }
            temp = temp->fn_next;
        }

        if( temp->fn_next == NULL ) { // Sondan Silme Kosulu
            if( strcmp(temp->first_name, str_key) == 0 ) {
                if( num == counter ) {
                    list->fn_tail = temp->fn_pre;
                    temp->fn_pre->fn_next = NULL;
                    free(temp);
                    printf("%s deleted at the end and new tail is %s \n", str_key, list->fn_tail->first_name );
                    return;
                }
            }
        }
    }

void del_ln_name(LIST* list, char* str_key) {
    NODE* temp;
    int num,counter=1,flag;
    temp = list->ln_head;

    if( list->ln_head == NULL ) {
        printf("The list is EMPTY!!!\n");
        return;
    }

    flag = search_ln(list,str_key);

    if ( flag ) {
        printf("Enter the number of student you want to delete : ");
        scanf("%d", &num);

        if( strcmp( list->ln_head->last_name, str_key ) == 0 ) { // Bastan Silme Kosulu
            if( num == counter ) {
                temp->ln_next->ln_pre = list->ln_head;
                list->ln_head = temp->ln_next;
                free(temp);

                printf("%s is deleted and the new header is %s\n", str_key, list->ln_head->last_name );
                return;
            }
            counter++;
        }
        temp = temp->ln_next;
        while ( temp->ln_next != NULL ) {
            if( strcmp( temp->last_name, str_key ) == 0 ) {
                if( num == counter ) {
                    temp->ln_pre->ln_next = temp->ln_next;
                    temp->ln_next->ln_pre = temp->ln_pre;
                    free(temp);

                    printf("%s deleted at between %s  and  %s\n", str_key, temp->ln_pre->last_name, temp->ln_next->last_name);
                    return;
                }
                counter++;
            }
            temp = temp->ln_next;
        }

        if( temp->ln_next == NULL ) { // Sondan Silme Kosulu
            printf("The last item %s second last item %s\n", temp->first_name, list->fn_tail->fn_pre->first_name);*/
            if( strcmp(temp->last_name, str_key) == 0 ) {
                if( num == counter ) {
                    list->ln_tail = temp->ln_pre;
                    temp->ln_pre->ln_next = NULL;
                    free(temp);

                    printf("%s deleted at the end and new tail is %s \n", str_key, list->ln_tail->last_name );
                    return;
                }
            }
        }
    }

整数
标志
计数器
用于删除重复的学生。例如,如果有三个副本,它会询问我要删除的学生人数。所以,如果我输入第2个,它就删除第二个副本。

< p>,C++中的习惯答案只是使用。它的目的就是添加具有各种访问路径(索引)的元素,并保持所有索引的同步

但是,如果您希望重新实现这个世界,并且如果您仅限于C(因为您目前提供的所有代码都是C,尽管有标记),那么我不知道有哪个库可以提供这一功能

一般来说,这个想法很简单,特别是如果一个简单的列表就足够了。正如您在节点中所注意到的,您只需要一个prev/next对索引,就可以将节点保留在其中

现在,在添加节点时,首先需要分配它,然后在每个索引中定位插入点。如果所有的都已定位,并且没有错误发生,则将其插入每个索引中的定位点,此时结构负责管理内存

类似地,删除节点时,首先需要定位节点本身,然后从每个索引中删除它。然后,您可以将其返回给调用者(
pop
-like),或者自己释放它。

这应该可以:

void add_Node(LIST* list,NODE* pnew_stu){
    add_fn_Node(list,pnew_stu);
    add_ln_Node(list,pnew_stu);
}

void remove_Node(LIST* list, NODE* pdead_stu){
    if(pdead_stu->fn_next){
        pdead_stu->fn_next->fn_pre=pdead_stu->fn_pre;
    }
    if(pnew_stu->fn_pre){
        pdead_stu->fn_pre->fn_next=pdead_stu->fn_next;
    }
    if(pnew_stu->ln_next){
        pdead_stu->ln_next->ln_pre=pdead_stu->ln_pre;
    }
    if(pnew_stu->ln_pre){
        pdead_stu->ln_pre->fn_pre=pdead_stu->ln_next;
    }
    if(list->fn_head==pdead_stu){list->fn_head=pdead_stu->fn_next;}
    if(list->ln_head==pdead_stu){list->ln_head=pdead_stu->ln_next;}
    if(list->fn_tail==pdead_stu){list->fn_tail=pdead_stu->fn_pre;}
    if(list->ln_tail==pdead_stu){list->ln_tail=pdead_stu->ln_pre;}
    list->fn_count--;
    list->ln_count--;
}
打印(搜索(type=“cliente”,codice=random.randrange(1000))) 打印(查找(type=“cliente”,codice=random.randrange(1000))) 导入系统 系统出口(1)

您的代码对于所需内容来说似乎有点复杂,但想法是正确的。我没有看到insert方法中有任何错误,但是很难遵循所有这类复制粘贴程序。您可以让每个学生同时在几个不同的列表中,但我建议使用不同的方法来避免所有这些重复,这使得引入bug非常容易

数据结构 您可以抽象出链接和列表的概念:

typedef struct TList
{
    struct TLink *first, *last;
} List;

typedef struct TLink
{
    struct TStudent *student;
    struct TLink *prev, *next;
} Link;
列表
结构是您需要的三个列表(名字、姓氏、生日)中的任意一个,而
链接
是任何一个链接。见下图

通过这种方法,用于在列表中插入/删除链接的代码与所有链接类型共享(
first\u name
last\u name
age
)。支付的价格是每个链接的额外指针,需要编写
link->student->first\u name
,而不是
link->first\u name

链接插入/删除 向列表添加链接类似于

// Adds a new link before the link `before` or as last link
// if `before` is NULL
void addLink(List *list, Link *newlink, Link *before)
{
    newlink->next = before;
    newlink->prev = before ? before->prev : list->last;
    if (newlink->next) newlink->next->prev = newlink;
                  else list->last = newlink;
    if (newlink->prev) newlink->prev->next = newlink;
                  else list->first = newlink;
}
void removeLink(List *lists, Link *link)
{
    if (link->next) link->next->prev = link->prev;
               else list->last = link->prev;
    if (link->prev) link->prev->next = link->next;
               else list->first = link->next;
}
从列表中删除链接类似于

// Adds a new link before the link `before` or as last link
// if `before` is NULL
void addLink(List *list, Link *newlink, Link *before)
{
    newlink->next = before;
    newlink->prev = before ? before->prev : list->last;
    if (newlink->next) newlink->next->prev = newlink;
                  else list->last = newlink;
    if (newlink->prev) newlink->prev->next = newlink;
                  else list->first = newlink;
}
void removeLink(List *lists, Link *link)
{
    if (link->next) link->next->prev = link->prev;
               else list->last = link->prev;
    if (link->prev) link->prev->next = link->next;
               else list->first = link->next;
}
这两个功能可用于管理所有三种类型(名字、姓氏和年龄)的列表/链接,无需任何代码重复

插入学生对象 通过这种方法,学生对象可以拥有所有的数据和许多链接对象

typedef struct TStudent
{
    char first_name[NAMESIZE];
    char last_name[NAMESIZE};
    int age;
    Link first_name_link, last_name_link, age_link;
} Student;
例如,为了在
名字列表中插入学生,代码将变为

Student *newstudent = ...
...
Link *before = first_name_list.first;
while (before != NULL &&
       strcmp(newstudent->first_name,
              before->student->first_name) > 0)
{
    before = before->next;
}
addLink(&first_name_list,
        &newstudent->first_name_link,
        before);
请注意,这个简单的循环正确地处理了代码中使用类似语句的复制粘贴(这是插入的第一个学生,最后一个,中间一个)分别处理的所有情况

这里的想法只是将
before
节点设置为列表中的第一个节点,如果必须在后面插入新节点,则继续将其移动到下一个学生

当然,要在其他两个列表中找到正确的插入点需要相同类型的循环(
last\u name\u list
age\u list
)。通过使用函数指针也可以分解插入点搜索

删除学生对象 要删除学生,当然必须从所有列表中删除学生数据,换句话说,必须删除所有三个链接。然而,这仅仅意味着调用三次
removeLink
函数:

 removeLink(&first_name_list, &student->first_name_link);
 removeLink(&last_name_list, &student->last_name_link);
 removeLink(&age_list, &student->age_link);
 free(student);

你的密码很难理解。所以我尝试了我自己的方法来实现任何关于多重链表的案例。希望能有所帮助。

听起来您的列表将按指针类型之一排序;i、 但你的姓氏指针将在你的列表中跳转。例如:
Name
H->0->1->2->3-空,和
姓氏
H
->2->0->3->1->空。是的,我说过我想要一个列表和两个不同的头指针。当然,名字和姓氏的顺序会有所不同。是的,所以你可以在一个方法中添加这些;您只需先插入一个列表,然后对第二个列表重新排序,方法就是我的问题。如何在一个函数中添加按名称和姓氏排序的节点?我不知道为什么用户“staffman”将标记改为“C++”。但是,是的,我使用C。实际上,添加或删除函数工作正常。简单的问题是我无法实现