I am working on a project which is similar to an address book. Firstly we have a number of students in a text file. I am going to implement a multi linked list which this list have 2 head+tail pointer (head+tail pointer for name,surname). These pointers show the same list but different locations because I am adding the nodes in ascending order and use double pointers to print the list backwards. The problem is I implemented the list by adding nodes by name and surname and the operation goes successfully when I insert another one. But I realized that when I deleted a node by her/his "name" and print the list again the student doesn't exist, but when I print the list by "surname" the student does exist. Then I recognize that I was implemented two separate linked lists. I was told to implement only ONE add and remove function. But how can I add a node by its first name pointers and surname pointers together? I hope I explained my issue understandably. Here are my blocks of code.
My structures:
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;
The code block where I read the file line by line and call the add functions:
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);
}
And finally my add functions:
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;
}
}
}
}
My delete functions:
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_k开发者_StackOverflow社区ey, list->ln_tail->last_name );
return;
}
}
}
}
The integers flag
and counter
are for deleting the duplicate students. For example, if there are three duplicates it asks me to which number of student I want to delete. So if I enter number 2 it deletes the second duplicate.
print(search(type="cliente", codice=random.randrange(1000))) print(find(type="cliente", codice=random.randrange(1000))) import sys sys.exit(1)
Your code seems a bit complex for what is needed but the idea is correct. I don't see any error in the insert method but it's quite hard to follow all this sort of copy'n paste program. You can have each students in several different lists at the same time, but I'd suggest using a different approach to avoiding all this duplication that makes very easy to introduce bugs.
Data structure
You could abstract the idea of link and list:
typedef struct TList
{
struct TLink *first, *last;
} List;
typedef struct TLink
{
struct TStudent *student;
struct TLink *prev, *next;
} Link;
The List
structure is any of the three lists you need (first name, last name, birthdate) and Link
is any of the links. See the following picture...
With this approach the code for inserting/removing a link in a list is shared with all link types (first_name
, last_name
, age
). The price to pay is an extra pointer for each link and the need to write link->student->first_name
instead of link->first_name
.
Link insertion/deletion
Adding a link to a list is something like
// 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;
}
and removing a link from a list is something like
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;
}
These two function can be used to manage lists/links of all three types (first_name, last_name and age) without any code duplication.
Insertion of a Student object
With this approach the student object can have all the data and many links objects
typedef struct TStudent
{
char first_name[NAMESIZE];
char last_name[NAMESIZE};
int age;
Link first_name_link, last_name_link, age_link;
} Student;
For example to insert the student in order for the first_name
list the code becomes
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);
Please note that this simple loop handles correctly all cases that in your code are instead handled separately with copy'n paste of similar statements (this is the first student inserted, the last, one in the middle).
The idea here is just to set the before
node to the first in the list and keeping moving it to next student if the new one must be inserted after instead.
Of course the same kind of loop is needed to find the correct insertion point in the other two lists (last_name_list
and age_list
). Factoring out also the insertion point search would be possible by using function pointers.
Deletion of a Student object
To delete a Student
of course the student data must be removed from all the lists, in other words all three links must be removed. This however simply means calling three times the removeLink
function:
removeLink(&first_name_list, &student->first_name_link);
removeLink(&last_name_list, &student->last_name_link);
removeLink(&age_list, &student->age_link);
free(student);
The idiomatic answer, in C++, is simply to use Boost.MultiIndex. It is meant exactly for the purpose of adding elements with various access paths (indexes) and keeping all indexes synchronized.
If you wish to reimplement the world, however, and if you are limited to C (since all the code you presented so far is C, despite the tag), then I do not know of any library that can provide this.
Generally speaking, the idea is simple enough, especially if a simple list is sufficient. As you noted in your node, you simply need a prev/next pair by index you wish to keep the node in.
Now, when adding a node, you first need to allocate it, then to locate the point of insertion in each of the index. If all are located, and no error occurs, then you insert it at the located point in each index, and the structure is now responsible for managing the memory.
Similarly, when removing a node, you first need to locate the node itself, then remove it from each of the index. Then either you return it to the caller (pop
-like) or free it yourself.
this should work:
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--;
}
精彩评论