web-dev-qa-db-fra.com

Liste simple liée en C++

Je suis sur le point de créer un lien qui peut insérer et afficher jusqu'à présent:

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

C’est ma fonction d’initialisation qui ne sera appelée que pour la première Node:

void initNode(struct Node *head, int n){
    head->x = n;
    head->next = NULL;
}

Pour ajouter la Node, et je pense que la raison pour laquelle ma liste liée ne fonctionne pas correctement est dans cette fonction:

void addNode(struct Node *head, int n){
    struct Node *NewNode = new Node;
    NewNode-> x = n;
    NewNode -> next = head;
    head = NewNode;
}

Ma fonction main:

int _tmain(int argc, _TCHAR* argv[])
{
    struct Node *head = new Node;

    initNode(head, 5);
    addNode(head, 10);
    addNode(head, 20);
    return 0;
}

Laissez-moi exécuter le programme car je pense que cela fonctionne. D'abord, j'initialise la tête Node en tant que Node comme ceci:

head = [ 5 |  NULL ]

Ensuite, j'ajoute un nouveau nœud avec n = 10 et passe la tête comme argument.

NewNode = [x | next] où prochains points en tête. Et puis je change l'endroit où head pointe sur NewNode, car NewNode est le premier nœud de LinkedList.

Pourquoi ça ne marche pas? J'apprécierais tout indice qui pourrait me faire avancer dans la bonne direction. Je pense que LinkedList est un peu difficile à comprendre.

Quand j'imprime ceci, il ne retourne que 5:

13
Kalle

C'est l'exemple le plus simple auquel je puisse penser dans ce cas et qui n'a pas été testé. Veuillez considérer que cela utilise certaines mauvaises pratiques et ne se déroule pas comme vous le feriez normalement avec C++ (initialiser des listes, séparer la déclaration et la définition, etc.). Mais ce sont des sujets que je ne peux pas couvrir ici.

#include <iostream>
using namespace std;

class LinkedList{
    // Struct inside the class LinkedList
    // This is one node which is not needed by the caller. It is just
    // for internal work.
    struct Node {
        int x;
        Node *next;
    };

// public member
public:
    // constructor
    LinkedList(){
        head = NULL; // set head to NULL
    }

    // destructor
    ~LinkedList(){
        Node *next = head;

        while(next) {              // iterate over all elements
            Node *deleteMe = next;
            next = next->next;     // save pointer to the next element
            delete deleteMe;       // delete the current entry
        }
    }

    // This prepends a new value at the beginning of the list
    void addValue(int val){
        Node *n = new Node();   // create new Node
        n->x = val;             // set value
        n->next = head;         // make the node point to the next node.
                                //  If the list is empty, this is NULL, so the end of the list --> OK
        head = n;               // last but not least, make the head point at the new node.
    }

    // returns the first element in the list and deletes the Node.
    // caution, no error-checking here!
    int popValue(){
        Node *n = head;
        int ret = n->x;

        head = head->next;
        delete n;
        return ret;
    }

// private member
private:
    Node *head; // this is the private member variable. It is just a pointer to the first Node
};

int main() {
    LinkedList list;

    list.addValue(5);
    list.addValue(10);
    list.addValue(20);

    cout << list.popValue() << endl;
    cout << list.popValue() << endl;
    cout << list.popValue() << endl;
    // because there is no error checking in popValue(), the following
    // is undefined behavior. Probably the program will crash, because
    // there are no more values in the list.
    // cout << list.popValue() << endl;
    return 0;
}

Je vous suggère fortement de lire un peu sur la programmation orientée objet et C++. Un bon point de départ pourrait être ceci: http://www.galileocomputing.de/1278?GPP=opoo

EDIT: ajout d'une fonction pop et de quelques sorties. Comme vous pouvez le constater, le programme transmet 3 valeurs 5, 10, 20 et les affiche ensuite. L'ordre est ensuite inversé car cette liste fonctionne en mode pile (LIFO, dernier entré premier sorti)

36
exilit

Vous devriez prendre la référence d'un pointeur de tête. Sinon, la modification du pointeur n'est pas visible en dehors de la fonction.

void addNode(struct Node *&head, int n){
    struct Node *NewNode = new Node;
 NewNode-> x = n;
 NewNode -> next = head;
 head = NewNode;
}
5
Blaz Bratanic

Les deux fonctions sont fausses. Tout d'abord, la fonction initNode a un nom déroutant. Il doit être nommé comme par exemple initList et ne doit pas effectuer la tâche addNode. Autrement dit, cela ne devrait pas ajouter de valeur à la liste.

En fait, la fonction initNode n'a pas de sens, car l'initialisation de la liste peut être faite lorsque la tête est définie:

Node *head = nullptr;

ou

Node *head = NULL;

Vous pouvez donc exclure la fonction initNode de votre conception de la liste.

De même, dans votre code, il n'est pas nécessaire de spécifier le nom du type élaboré pour la structure Node, c'est-à-dire spécifier le mot clé struct avant name Node.

La fonction addNode doit changer la valeur initiale de head. Dans votre réalisation de fonction, vous ne changez que la copie de head transmise en argument à la fonction.

La fonction pourrait ressembler à:

void addNode(Node **head, int n)
{
    Node *NewNode = new Node {n, *head};
    *head = NewNode;
}

Ou si votre compilateur ne supporte pas la nouvelle syntaxe d'initialisation, vous pouvez écrire

void addNode(Node **head, int n)
{
    Node *NewNode = new Node;
    NewNode->x = n;
    NewNode->next = *head;
    *head = NewNode;
}

Ou au lieu d'utiliser un pointeur à pointeur, vous pouvez utiliser une référence pour pointer vers un nœud. Par exemple,

void addNode(Node * &head, int n)
{
    Node *NewNode = new Node {n, head};
    head = NewNode;
}

Ou vous pouvez retourner une tête mise à jour à partir de la fonction:

Node * addNode(Node *head, int n)
{
    Node *NewNode = new Node {n, head};
    head = NewNode;
    return head;
}

Et dans main, écrivez:

head = addNode(head, 5);
3
Vlad from Moscow

Je vais rejoindre la mêlée. Cela fait trop longtemps que je n’ai pas écrit C. Par ailleurs, il n’existe pas d’exemples complets ici. Le code de l'OP est fondamentalement C, alors j'ai décidé de le faire fonctionner avec GCC. 

Les problèmes étaient couverts auparavant; le pointeur next n'était pas avancé. C'était le noeud de la question. 

J'ai également profité de l'occasion pour faire un montage suggéré; au lieu d'avoir deux fonctions pour malloc, je l'ai mis dans initNode() et ensuite utilisé initNode() en malloc les deux (malloc est "le nouveau C si vous voulez). J'ai changé initNode() pour retourner un pointeur.

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

// required to be declared before self-referential definition
struct Node;

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

struct Node* initNode( int n){
    struct Node *head = malloc(sizeof(struct Node));
    head->x = n;
    head->next = NULL;
    return head;
}

void addNode(struct Node **head, int n){
 struct Node *NewNode = initNode( n );
 NewNode -> next = *head;
 *head = NewNode;
}

int main(int argc, char* argv[])
{
    struct Node* head = initNode(5);
    addNode(&head,10);
    addNode(&head,20);
    struct Node* cur  = head;
    do {
        printf("Node @ %p : %i\n",(void*)cur, cur->x );
    } while ( ( cur = cur->next ) != NULL );

}

compilation: gcc -o ll ll.c

sortie:

Node @ 0x9e0050 : 20
Node @ 0x9e0030 : 10
Node @ 0x9e0010 : 5
2
Dan Farrell

La fonction addNode doit pouvoir changer head. Dans son libellé actuel, change simplement la variable locale head (un paramètre).

Changer le code en

void addNode(struct Node *& head, int n){
    ...
}

résoudrait ce problème car maintenant le paramètre head est passé par référence et la fonction appelée peut le muter.

2
6502

head est défini à l'intérieur de la propriété principale comme suit.

struct Node *head = new Node;

Mais vous changez la tête dans les fonctions addNode() et initNode() uniquement. Les changements ne sont pas répercutés sur le principal.

Faites la déclaration de la tête en tant que globale et ne la passez pas aux fonctions.

Les fonctions devraient être les suivantes.

void initNode(int n){
    head->x = n;
    head->next = NULL;
}

void addNode(int n){
    struct Node *NewNode = new Node;
    NewNode-> x = n;
    NewNode->next = head;
    head = NewNode;
}
2
Deepu

Ci-dessous un exemple de liste de liens 

    #include <string>
    #include <iostream>

    using namespace std;


    template<class T>
    class Node
    {
    public:
        Node();
        Node(const T& item, Node<T>* ptrnext = NULL);
        T value;
        Node<T> * next;
    };

    template<class T>
    Node<T>::Node()
    {
        value = NULL;
        next = NULL;
    }
    template<class T>
    Node<T>::Node(const T& item, Node<T>* ptrnext = NULL)
    {
        this->value = item;
        this->next = ptrnext;
    }

    template<class T>
    class LinkedListClass
    {
    private:
        Node<T> * Front;
        Node<T> * Rear;
        int Count;
    public:
        LinkedListClass();
        ~LinkedListClass();
        void InsertFront(const T Item);
        void InsertRear(const T Item);
        void PrintList();
    };
    template<class T>
    LinkedListClass<T>::LinkedListClass()
    {
        Front = NULL;
        Rear = NULL;
    }

    template<class T>
    void LinkedListClass<T>::InsertFront(const T  Item)
    {
        if (Front == NULL)
        {
            Front = new Node<T>();
            Front->value = Item;
            Front->next = NULL;
            Rear = new Node<T>();
            Rear = Front;
        }
        else
        {
            Node<T> * newNode = new Node<T>();
            newNode->value = Item;
            newNode->next = Front;
            Front = newNode;
        }
    }

    template<class T>
    void LinkedListClass<T>::InsertRear(const T  Item)
    {
        if (Rear == NULL)
        {
            Rear = new Node<T>();
            Rear->value = Item;
            Rear->next = NULL;
            Front = new Node<T>();
            Front = Rear;
        }
        else
        {
            Node<T> * newNode = new Node<T>();
            newNode->value = Item;
            Rear->next = newNode;
            Rear = newNode;
        }
    }
    template<class T>
    void LinkedListClass<T>::PrintList()
    {
        Node<T> *  temp = Front;
        while (temp->next != NULL)
        {
            cout << " " << temp->value << "";
            if (temp != NULL)
            {
                temp = (temp->next);
            }
            else
            {
                break;
            }
        }
    }

    int main()
    {
        LinkedListClass<int> * LList = new LinkedListClass<int>();
        LList->InsertFront(40);
        LList->InsertFront(30);
        LList->InsertFront(20);
        LList->InsertFront(10);
        LList->InsertRear(50);
        LList->InsertRear(60);
        LList->InsertRear(70);
        LList->PrintList();
    }
2
Saurabh Raoot

Utilisation:

#include<iostream>

using namespace std;

struct Node
{
    int num;
    Node *next;
};

Node *head = NULL;
Node *tail = NULL;

void AddnodeAtbeggining(){
    Node *temp = new Node;
    cout << "Enter the item";
    cin >> temp->num;
    temp->next = NULL;
    if (head == NULL)
    {
        head = temp;
        tail = temp;
    }
    else
    {
        temp->next = head;
        head = temp;
    }
}

void addnodeAtend()
{
    Node *temp = new Node;
    cout << "Enter the item";
    cin >> temp->num;
    temp->next = NULL;
    if (head == NULL){
        head = temp;
        tail = temp;
    }
    else{
        tail->next = temp;
        tail = temp;
    }
}

void displayNode()
{
    cout << "\nDisplay Function\n";
    Node *temp = head;
    for(Node *temp = head; temp != NULL; temp = temp->next)
        cout << temp->num << ",";
}

void deleteNode ()
{
    for (Node *temp = head; temp != NULL; temp = temp->next)
        delete head;
}

int main ()
{
    AddnodeAtbeggining();
    addnodeAtend();
    displayNode();
    deleteNode();
    displayNode();
}
1
Abdulhakim Zeinu

Je pense que, pour être sûr que le lien indeep de chaque noeud de la liste, la méthode addNode doit être comme ceci:

void addNode(struct node *head, int n) {
  if (head->Next == NULL) {
    struct node *NewNode = new node;
    NewNode->value = n;
    NewNode->Next = NULL;
    head->Next = NewNode;
  }
  else 
    addNode(head->Next, n);
}

Dans un code, il y a une erreur:

void deleteNode ()
{
    for (Node * temp = head; temp! = NULL; temp = temp-> next)
        delete head;
}

Il faut donc:

for (; head != NULL; )
{
    Node *temp = head;
    head = temp->next;

    delete temp;
}
1
Vladimir Popov

Voici ma mise en œuvre.

#include <iostream>

using namespace std;

template< class T>
struct node{
    T m_data;
    node* m_next_node;

    node(T t_data, node* t_node) :
        m_data(t_data), m_next_node(t_node){}

    ~node(){
        std::cout << "Address :" << this << " Destroyed" << std::endl;
    }
};

template<class T>
class linked_list {
public:
    node<T>* m_list;

    linked_list(): m_list(nullptr){}

    void add_node(T t_data) {
        node<T>* _new_node = new node<T>(t_data, nullptr);
        _new_node->m_next_node = m_list;
        m_list = _new_node;
    }


    void populate_nodes(node<T>* t_node) {
        if  (t_node != nullptr) {
            std::cout << "Data =" << t_node->m_data
                      << ", Address =" << t_node->m_next_node
                      << std::endl;
            populate_nodes(t_node->m_next_node);
        }
    }

    void delete_nodes(node<T>* t_node) {
        if (t_node != nullptr) {
            delete_nodes(t_node->m_next_node);
        }
        delete(t_node);
    }

};


int main()
{
    linked_list<float>* _ll = new linked_list<float>();

    _ll->add_node(1.3);
    _ll->add_node(5.5);
    _ll->add_node(10.1);
    _ll->add_node(123);
    _ll->add_node(4.5);
    _ll->add_node(23.6);
    _ll->add_node(2);

    _ll->populate_nodes(_ll->m_list);

    _ll->delete_nodes(_ll->m_list);

    delete(_ll);

    return 0;
}

Sortie ici

0
Indre Lemur