I'm trying to merge two linked lists. They each have headers which contain a beginning and ending node. This is the function. It returns a header with the new merged linked list; it takes as parameters two linked lists that will be merged.
I can't find what I am doing wrong. When return the merged header and use a function to print linked lists from its header it prints in loop two nodes forever. All the functions used in the code are working well; already tested in the rest of the software.
header * merge_lists (header * h1, header * h2) {
header * h3 = init_header();
node * curr1 = h1->first;
node * curr2 = h2->first;
node * result;
while (1) {
if (curr1 == NULL && curr2 == NULL) break;
if (curr1 == NULL){
result = curr2;
curr2 = curr2->next;
}
else if (curr2 == NULL){
result = curr1;
curr1 = curr1->next;
}
else if (curr1->name[0] > curr2->name[0]){
result = curr1;
curr1 = curr1->next;
}
else if (curr1->name[0] <= curr2->name[0]) {
result = curr2;
curr2 = curr2->next;
}
insert_beginning(h3, result);
}
return h3;
}
void print_list (header * head) {
node * current = head->first;
while (current != NULL){
printf("%s %d\n", current->name, current->age);
current = current->next;
}
}
void insert_beginning (header * head, node * new_node) {
if (head->quantity == 0){
head->first = new_node;
head->last = new_node;
head->quantity++;
return;
}
new_node->next = head->first;
head->first = new_node;
new_node->next->prev = new_node;
head->quantity++;
}
typedef struct node_struct {
char name[30];
int age;
struct node_struct * prev;
struct node_struct * next;
} node;
Your insert code appears to have at least one bug:
void insert_beginning (header * head, node * new_node) {
if (head->quantity == 0){
head->first = new_node;
head->last = new_node;
head->quantity++;
return;
}
// NOTE/BUG: this links new_node to itself
#if 0
head->first = new_node;
new_node->next = head->first;
// NOTE/FIX: this is the correct way
#else
new_node->next = head->first;
head->first = new_node;
#endif
// NOTE/BUG?: what about end of list?
#if 0
new_node->next->prev = new_node;
#else
if (new_node->next != NULL)
new_node->next->prev = new_node;
#endif
head->quantity++;
}
UPDATE:
The first bug I just copied wrong in post, I am sorry.
Okay, fair enough.
But the second one: there is no way
new_node->next
will beNULL
at this point since it will always be inserted at beginning and will always already have another node next.
That's indirectly part of the problem, I think.
I've gotten your code to work and produced a test program. I had to create some of the missing functions and structs.
I coded up a different merge function: merge_lists2
. One of the big differences is that it doesn't just do (eg) curr1 = curr1->next
but calls a new function that shifts off the first element [if needed] that removes all old next/prev
links.
This is done in a new function list_shift
. In particular, see the NOTE/BUG
comment in that function.
Anyway, here's the updated and working code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node_struct {
char name[30];
int age;
struct node_struct *prev;
struct node_struct *next;
} node;
typedef struct header_struct {
node *first;
node *last;
int quantity;
} header;
void
print_list(header * head, const char *sym)
{
node *current = head->first;
printf("%s [fwd]:\n", sym);
while (current != NULL) {
printf(" %s %d\n", current->name, current->age);
current = current->next;
}
}
void
print_rlist(header * head, const char *sym)
{
node *current = head->last;
printf("%s [rev]:\n", sym);
while (current != NULL) {
printf(" %s %d\n", current->name, current->age);
current = current->prev;
}
}
void
insert_beginning(header * head, node * new_node)
{
#if 1
new_node->prev = NULL;
#endif
if (head->quantity == 0) {
head->first = new_node;
head->last = new_node;
head->quantity++;
return;
}
// NOTE/BUG: this links new_node to itself
#if 0
head->first = new_node;
new_node->next = head->first;
// NOTE/FIX: this is the correct way
#else
new_node->next = head->first;
head->first = new_node;
#endif
// NOTE/BUG?: what about end of list?
#if 0
new_node->next->prev = new_node;
#else
if (new_node->next != NULL)
new_node->next->prev = new_node;
#endif
head->quantity++;
}
void
insert_string(header * h, const char *str)
{
node *ptr = calloc(1, sizeof(*ptr));
strcpy(ptr->name, str);
insert_beginning(h, ptr);
}
header *
init_header(void)
{
header *h = calloc(1, sizeof(*h));
return h;
}
header *
merge_lists1(header * h1, header * h2)
{
header *h3 = init_header();
node *curr1 = h1->first;
node *curr2 = h2->first;
node *result;
while (1) {
if (curr1 == NULL && curr2 == NULL)
break;
if (curr1 == NULL) {
result = curr2;
curr2 = curr2->next;
}
else if (curr2 == NULL) {
result = curr1;
curr1 = curr1->next;
}
else if (curr1->name[0] > curr2->name[0]) {
result = curr1;
curr1 = curr1->next;
}
else if (curr1->name[0] <= curr2->name[0]) {
result = curr2;
curr2 = curr2->next;
}
insert_beginning(h3, result);
}
return h3;
}
node *
list_shift(header * h, node * cur)
{
do {
// bug out if we do _not_ yet need to dequeue an element from this list
if (cur != NULL)
break;
// bug out if we're at the end of the list
cur = h->first;
if (cur == NULL)
break;
// fix the head chain pointer
h->first = cur->next;
// fix the tail chain pointer
if (cur == h->last)
h->last = NULL;
cur->prev = NULL;
// NOTE/BUG: the smoking gun -- adding this fixed things
cur->next = NULL;
} while (0);
return cur;
}
header *
merge_lists2(header * h1, header * h2)
{
header *h3 = init_header();
node *curr1 = NULL;
node *curr2 = NULL;
node *result;
while (1) {
curr1 = list_shift(h1, curr1);
curr2 = list_shift(h2, curr2);
if ((curr1 == NULL) && (curr2 == NULL))
break;
if (curr1 == NULL) {
result = curr2;
curr2 = NULL;
}
else if (curr2 == NULL) {
result = curr1;
curr1 = NULL;
}
else if (curr1->name[0] > curr2->name[0]) {
result = curr1;
curr1 = NULL;
}
else {
result = curr2;
curr2 = NULL;
}
insert_beginning(h3, result);
}
return h3;
}
// main -- main program
int
main(int argc, char **argv)
{
char *cp;
--argc;
++argv;
for (; argc > 0; --argc, ++argv) {
cp = *argv;
if (*cp != '-')
break;
switch (cp[1]) {
default:
break;
}
}
header *h1 = init_header();
insert_string(h1, "jkl");
insert_string(h1, "def");
print_list(h1, "h1");
print_rlist(h1, "h1");
#if 1
header *h2 = init_header();
insert_string(h2, "ttt");
insert_string(h2, "ghi");
insert_string(h2, "abc");
print_list(h2, "h2");
print_rlist(h2, "h2");
#endif
#if 0
header *h3 = merge_lists1(h1, h2);
print_list(h3, "h3");
print_rlist(h3, "h3");
#endif
#if 1
header *h3 = merge_lists2(h1, h2);
print_list(h3, "h3");
print_rlist(h3, "h3");
#endif
return 0;
}
Side note: You're only comparing the first character of the strings, so you may want to use strcmp
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.