Копирование списка ссылок (C ++) - PullRequest
0 голосов
/ 02 марта 2019
struct n{//The definition of Linked List
    int x;
    struct n * next;
};
typedef struct n node;

int counter(node *r){ //Counting the node.
    int y=0;
    while(r != NULL){
        y++;
        r = r->next;
    }
    return y;       
}

//The problem is down there

void cpyLl(node *r){    //Copying link list
    int temp;
    for (int y = counter(r); y > 0 ;y--){
        temp = r -> x;
        while (r -> next != NULL){
            r = r -> next;
        } 
        r -> next = (node *)malloc(sizeof(node));
        r = r->next;
        r -> x = temp;
    }
}

int main(){
    node * root;
    root = (node *)malloc(sizeof(node));
    root -> x = 10;
    root -> next = (node *)malloc(sizeof(node));
    root -> next -> x = 20;
    root -> next -> next =(node *)malloc(sizeof(node));
    root -> next -> next -> x =30;
    root -> next -> next -> next = NULL;
    cpyLl(root);
    return 0;
}

Я пытался скопировать свой связанный список, и он вводит бесконечный цикл, когда я вызываю cpyLl ();function.

Мой ожидаемый вывод:

10 20 30 10 20 30

Я действительно использовал функцию для определения узла, но пишу ееВ основном пока. Из-за сложности кода.

Я использую Dev-C ++ 5.11.

Ответы [ 2 ]

0 голосов
/ 02 марта 2019

В cpyLl() вы не инициализируете поле next каждого нового node, который вы выделяете.malloc() не обнуляет выделенную память (если вы хотите, используйте вместо нее calloc()).

Кроме того, цикл while, который имеется в цикле for, чтобы найти последний узел всписок действительно должен быть перемещен перед вводом цикла for.Нет смысла использовать цикл while на каждой итерации цикла for, просто добавьте новый узел к предыдущему выделенному узлу.

Вместо этого попробуйте что-то вроде этого:

struct node {
    int x;
    node *next;
};

int countLinkedList(node *n, node **last = NULL) {
    int count = 0;
    if (last) *last = NULL;
    while (n) {
        ++count;
        if (last) *last = n;
        n = n->next;
    }
    return count;
}

node* makeLinkedListNode(int x) {
    node *n = new node; // (node*) malloc(sizeof(node));
    n->x = x;
    n->next = NULL;
    return n;
}

void freeLinkedList(node *n) {
    node *next;
    while (n) {
        next = n->next;
        delete n; // free(n);
        n = next;
    }
}

void copyLinkedList(node *n) {
    node *last;
    for (int y = countLinkedList(n, &last); y > 0; --y) {
        last->next = makeLinkedListNode(n->x);
        last = last->next;
        n = n->next;
    }
}

void printLinkedList(node *n) {
    while (n) {
        std::cout << n->x << " ";
        n = n->next;
    }
    std::cout << std::endl;
}

int main() {
    node *root = makeLinkedListNode(10);
    root->next = makeLinkedListNode(20);
    root->next->next = makeLinkedListNode(30);

    std::cout << "Before copy: ";
    printLinkedList(root);

    copyLinkedList(root);

    std::cout << "After copy: ";
    printLinkedList(root);

    freeLinkedList(root);
    return 0;
}

Вывод:

Before copy: 10 20 30 
After copy: 10 20 30 10 20 30 

Live Demo

При этом вам действительно следует использовать стандартные контейнеры и алгоритмы C ++ вместо этого, например:

#include <iostream>
#include <list>
#include <algorithm>
#include <iterator>

void printLinkedList(const std::list<int> &l) {
    for(int x : l) {
        std::cout << x << " ";
    }
    std::cout << std::endl;
}

int main() {
    std::list<int> l;
    l.push_back(10);
    l.push_back(20);
    l.push_back(30);

    std::cout << "Before copy: ";
    printLinkedList(l);

    std:copy_n(l.begin(), l.size(), std::back_inserter(l));

    std::cout << "After copy: ";
    printLinkedList(l);

    return 0;
}

Вывод:

Before copy: 10 20 30 
After copy: 10 20 30 10 20 30 

Live Demo

0 голосов
/ 02 марта 2019

Ваш компилятор должен предупреждать вас о неизвестном типе n in:

struct n {  //The definition of Linked List
    int x;
    n * next;
};

Над типом n неизвестно в то время, когда вы объявляете n * next;.Чтобы исправить это, вам необходимо включить struct перед n, например

struct n {  //The definition of Linked List
    int x;
    struct n * next;
};

Эта проблема также присутствует в вашем typedef, например

typedef n node;

Снова n неизвестно в это время.Вместо этого вам нужно.

typedef struct n node;

Как указывает Бруно, вы вызываете Неопределенное поведение , используя x в counter, когда оно не инициализировано, например:

int counter(node *r){ //Counting the node.

    int x;
    while(r != NULL){
        x++;             /* what is the value of x on the first iteration? */
        ...

Инициализируйте int x = 0 для исправления.

Проблемы со списком копирования

Сначала не ставьте пробелы вокруг -> в r = r->next; Оператор со стрелкой должен непосредственноподключите структуру и член.

Ваша cpyLl() функция ничего не копирует.Чтобы скопировать список, вам нужна функция, которая возвращает указатель на вновь скопированный список.Например, имеет смысл сделать:

/* cpyL1 should return a pointer to the head of the newly copied list */
node *cpyLl (node *r) {

Внутри вашей функции вам нужно выделить / создать новый первый узел и назначить первое значение данных для копии, а затем, по существу, повторить для остальных узлов, циклически повторяющихсявсе узлы создают новый выделенный узел для копирования и копирования значения.Вам нужно будет сохранить указатель на начало скопированного списка для возврата.Вам не нужно counter вообще в cpyL1.У вас есть связанный список, вы можете перебирать список, используя указатели next.например,

/* cpyL1 should return a pointer to the head of the newly copied list */
node *cpyLl (node *r) {

    node *copy = NULL, *p;  /* pointers for new list - initialized NULL */

    if (!r) {   /* validate r is not NULL */
        fputs ("error: list to copy is empty.\n", stderr);
        return NULL;
    }

    copy = malloc (sizeof *copy);   /* allocate 1st node of copy */
    if (!copy) {
        perror ("malloc-copy");
        return NULL;
    }
    p = copy;
    p->x = r->x;

    while (r->next) { /* copy all nodes from r to copy */
        p->next = malloc (sizeof *p->next); /* allocate each node */
        if (!p->next) {     /* validate the allocation */
            perror ("malloc-p->next");
            return copy;    /* return partial copy of list */
        }
        r = r->next;        /* advance to next node */
        p = p->next;

        p->x = r->x;        /* set node value */
        p->next = NULL;
    }

    return copy;    /* return pointer to newly copied list */
}

( примечание: вы должны ПРОВЕРЯТЬ каждое выделение.)

Теперь, если вы просто хотите скопировать определенный узел, вы можете выполнять итерацию, пока не найдетезначение или адрес и просто скопируйте один узел.

Поместив его целиком и добавив список печати и функцию свободного списка, вы можете сделать что-то похожее на:

#include <stdio.h>
#include <stdlib.h>

struct n {   //The definition of Linked List
    int x;
    struct n *next;
};
typedef struct n node;

int counter (node *r)   //Counting the node.
{
    int y = 0;
    while (r != NULL) {
        y++;
        r = r->next;
    }
    return y;
}

/* cpyL1 should return a pointer to the head of the newly copied list */
node *cpyLl (node *r) {

    node *copy = NULL, *p;  /* pointers for new list - initialized NULL */

    if (!r) {   /* validate r is not NULL */
        fputs ("error: list to copy is empty.\n", stderr);
        return NULL;
    }

    copy = malloc (sizeof *copy);   /* allocate 1st node of copy */
    if (!copy) {
        perror ("malloc-copy");
        return NULL;
    }
    p = copy;
    p->x = r->x;

    while (r->next) { /* copy all nodes from r to copy */
        p->next = malloc (sizeof *p->next); /* allocate each node */
        if (!p->next) {     /* validate the allocation */
            perror ("malloc-p->next");
            return copy;    /* return partial copy of list */
        }
        r = r->next;        /* advance to next node */
        p = p->next;

        p->x = r->x;        /* set node value */
        p->next = NULL;
    }

    return copy;    /* return pointer to newly copied list */
}

void prnlist (node *l)
{
    while (l) {
        printf (" %d", l->x);
        l = l->next;
    }
    putchar ('\n');
}

void freelist (node *l)
{
    while (l) {
        node *victim = l;
        l = l->next;
        free (victim);
    }
}

int main (void) {

    node *root, *p, *copy = NULL;
    root = malloc (sizeof *root);

    /* first node */
    if (!root) {    /* validate EVERY allocation */
        perror ("malloc-root");
        return 1;
    }
    root->x = 10;

    p = root;   /* assign pointer to root */

    /* second node */
    p->next = malloc (sizeof *p->next);
    if (!p->next) {    /* validate EVERY allocation */
        perror ("malloc-p->next");
        return 1;
    }
    p = p->next;
    p->x = 20;

    /* third node */
    p->next = malloc (sizeof *p->next);
    if (!p->next) {    /* validate EVERY allocation */
        perror ("malloc-p->next");
        return 1;
    }
    p = p->next;
    p->x = 30;
    p->next = NULL; /* set p->next to NULL */

    copy = cpyLl(root); /* copy root list to copy */
    if (!copy) {
        fputs ("error: copy is NULL\n", stderr);
        return 1;
    }

    puts ("\noriginal list:\n");
    prnlist (root);
    puts ("\ncopy of list:\n");
    prnlist (copy);

    freelist (root);    /* don't forget to free what you allocate */
    freelist (copy);

    return 0;
}

ПримерИспользование / Вывод

$ ./bin/structfwd

original list:

 10 20 30

copy of list:

 10 20 30

Использование памяти / проверка ошибок

Не забудьте проверить использование памяти для любых ошибок.

$ valgrind ./bin/structfwd
==12148== Memcheck, a memory error detector
==12148== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==12148== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==12148== Command: ./bin/structfwd
==12148==

original list:

 10 20 30

copy of list:

 10 20 30
==12148==
==12148== HEAP SUMMARY:
==12148==     in use at exit: 0 bytes in 0 blocks
==12148==   total heap usage: 6 allocs, 6 frees, 96 bytes allocated
==12148==
==12148== All heap blocks were freed -- no leaks are possible
==12148==
==12148== For counts of detected and suppressed errors, rerun with: -v
==12148== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
...