我正在开发一个类似于地址簿的项目。首先,我们在一个文本文件中有许多学生。我将实现一个多链表,该列表有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;
}
}
}
}
整数flag
和counter
用于删除重复的学生。例如,如果有三个重复项,它会询问我要删除的学生人数。因此,如果我输入数字2,则删除第二个副本。
答案 0 :(得分:8)
print(search(type =“cliente”,codice = random.randrange(1000))) print(find(type =“cliente”,codice = random.randrange(1000))) 导入系统 sys.exit(1)
您的代码似乎有点复杂,但是这个想法是正确的。我没有看到插入方法中的任何错误,但很难遵循所有这种copy'n粘贴程序。你可以让每个学生同时在几个不同的列表中,但我建议使用不同的方法来避免所有这些重复,这很容易引入错误。
你可以抽象出链接和列表的想法:
typedef struct TList
{
struct TLink *first, *last;
} List;
typedef struct TLink
{
struct TStudent *student;
struct TLink *prev, *next;
} Link;
List
结构是您需要的三个列表中的任何一个(名字,姓氏,出生日期),Link
是任何链接。见下图......
使用此方法,用于在列表中插入/删除链接的代码将与所有链接类型共享(first_name
,last_name
,age
)。支付的价格是每个链接的额外指针,需要写link->student->first_name
而不是link->first_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;
}
这两个函数可用于管理所有三种类型(first_name,last_name和age)的列表/链接,而不需要任何代码重复。
使用这种方法,学生对象可以拥有所有数据和许多链接对象
typedef struct TStudent
{
char first_name[NAMESIZE];
char last_name[NAMESIZE};
int age;
Link first_name_link, last_name_link, age_link;
} Student;
例如,为了first_name
列表的顺序插入学生,代码变为
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);
请注意,这个简单的循环正确处理代码中的所有情况,而不是使用类似语句的copy'n粘贴(这是第一个插入的学生,最后一个,中间的一个)。
这里的想法只是将before
节点设置为列表中的第一个节点,并在必须插入新节点后继续将其移动到下一个学生。
当然,在其他两个列表(last_name_list
和age_list
)中找到正确的插入点需要相同类型的循环。通过使用函数指针也可以考虑插入点搜索。
要删除Student
当然必须从所有列表中删除学生数据,换句话说,必须删除所有三个链接。然而,这仅仅意味着调用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);
答案 1 :(得分:0)
在C ++中,惯用的答案就是使用Boost.MultiIndex。它完全是为了添加具有各种访问路径(索引)的元素并保持所有索引同步。
但是,如果您希望重新实现这个世界,并且如果您仅限于C(因为到目前为止您提供的所有代码都是C,尽管有标记),那么我不知道任何可以提供此代码的库。
一般来说,这个想法很简单,特别是如果一个简单的列表就足够了。正如您在节点中所指出的那样,您只需按索引保留节点的上一个/下一个对。
现在,在添加节点时,首先需要分配它,然后在每个索引中找到插入点。如果找到所有,并且没有发生错误,则将其插入每个索引中的定位点,结构现在负责管理内存。
同样,在删除节点时,首先需要找到节点本身,然后从每个索引中删除它。然后将其返回给调用者(pop
- 像)或自己释放。
答案 2 :(得分:0)
这应该有效:
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--;
}
答案 3 :(得分:0)
您的代码很难理解。所以我尝试了自己的方式来实现有关多链接列表的任何案例。 http://www.fansonnote.com/2012/02/multi-linked-list/希望它会有所帮助。