Простой связанный список в С++

Я собираюсь создать привязку, которая может вставляться и отображаться до сих пор:

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

Это моя функция инициализации, которая будет вызываться только для первого Node:

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

Чтобы добавить Node, и я думаю, что причина, по которой мой связанный список не работает правильно, находится в этой функции:

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

Моя main функция:

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

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

Позвольте мне запустить программу, поскольку я думаю, что она работает. Сначала я инициализирую голову Node как Node следующим образом:

head = [ 5 |  NULL ]

Затем я добавляю новый node с n = 10 и передаю главу в качестве аргумента.

NewNode = [x | next], где следующие точки на голове. И затем я меняю место, где head указывает на NewNode, так как NewNode является первым node в LinkedList сейчас.

Почему это не работает? Я был бы признателен за любые намеки, которые могли бы заставить меня двигаться в правильном направлении. Я думаю, LinkedList немного сложно понять.

Когда я печатаю это, он возвращает только 5:

Ответ 1

Это самый простой пример, который я могу придумать в этом случае, и он не тестировался. Пожалуйста, учтите, что это использует некоторые плохие практики и не идет так, как вы обычно поступаете с C++ (инициализация списков, разделение объявления и определения и т.д.). Но это темы, которые я не могу здесь охватить.

#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;
}

Я настоятельно рекомендую вам прочитать немного о C++ и объектно-ориентированном программировании. Хорошая отправная точка может быть такой: http://www.galileocomputing.de/1278?GPP=opoo

РЕДАКТИРОВАТЬ: добавил поп-функцию и некоторые выходные данные. Как вы видите, программа выдвигает 3 значения 5, 10, 20, а затем выдает их. После этого порядок меняется на обратный, потому что этот список работает в режиме стека (LIFO, Last in First out)

Ответ 2

Вам следует взять указатель на голову. В противном случае модификация указателя не будет видна вне функции.

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

Ответ 3

Обе функции ошибочны. Прежде всего функция initNode имеет запутанное имя. Он должен называться как, например, initList и не должен выполнять задачу addNode. То есть, он не должен добавлять значение в список.

На самом деле, нет смысла в функции initNode, потому что инициализация списка может быть выполнена при определении головы:

Node *head = nullptr;

или

Node *head = NULL;

Таким образом, вы можете исключить функцию initNode из вашего дизайна списка.

Также в вашем коде нет необходимости указывать расширенное имя типа для структуры Node, которая должна указывать ключевое слово struct before name Node.

Функция addNode должна изменить исходное значение головы. В реализации функции вы изменяете только копию головы, переданную в качестве аргумента функции.

Функция может выглядеть так:

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

Или, если ваш компилятор не поддерживает новый синтаксис инициализации, вы можете написать

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

Или вместо указателя на указатель вы можете использовать ссылку на указатель на Node. Например,

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

Или вы можете вернуть обновленную голову из функции:

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

И в main напишите:

head = addNode(head, 5);

Ответ 4

Функция addNode должна иметь возможность изменять head. Как теперь написано, просто изменяется локальная переменная head (параметр).

Изменение кода на

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

решит эту проблему, потому что теперь параметр head передается по ссылке, и вызываемая функция может мутировать его.

Ответ 5

head определяется внутри основного следующим образом.

struct Node *head = new Node;

Но вы меняете голову только в функциях addNode() и initNode(). Изменения не отражаются на главном.

Сделайте объявление головы глобальным и не передавайте его функциям.

Функции должны быть следующими.

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;
}

Ответ 6

Я присоединяюсь к битве. С тех пор я написал C. Кроме того, здесь нет полных примеров. Код OP в основном C, поэтому я пошел вперед и включил его в GCC.

Проблемы были рассмотрены ранее; указатель next не продвигался. В этом суть проблемы.

Я также воспользовался возможностью, чтобы сделать предлагаемое редактирование; вместо двух функций на malloc, я помещал его в initNode(), а затем использовал initNode() to malloc оба (malloc - это "C новый", если вы это сделаете). Я изменил initNode(), чтобы вернуть указатель.

#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 );

}

компиляция: gcc -o ll ll.c

выход:

Node @ 0x9e0050 : 20
Node @ 0x9e0030 : 10
Node @ 0x9e0010 : 5

Ответ 7

Ниже приведен пример связанного списка

    #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();
    }

Ответ 8

Использование:

#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();
}

Ответ 9

Я думаю, что, чтобы удостовериться, что в каждом списке node указано значение indeep, метод addNode должен быть таким:

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);
}

Ответ 10

В коде есть ошибка:

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

Это необходимо так:

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

    delete temp;
}

Ответ 11

Вот моя реализация.

#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;
}

enter image description here

Ответ 12

#pragma once
#include "SKBStringList.h"

SKBStringList::SKBStringList()
{ 
    _Head = NULL;
    _Tail = NULL;
}

SKBStringList::~SKBStringList()
{
    _Head = NULL;
    _Tail = NULL;
}

void SKBStringList::Append(const char* iData)
{
    SKBStringData *pNewData = new SKBStringData(iData);

    if(_Head == NULL)
    {
        _Head = pNewData;
        _Tail = pNewData;
    }
    else
    {
        _Tail->SetLink(pNewData);
        _Tail = pNewData;
    }

    return;
}

void SKBStringList::Remove(const int iPos)  
{
    if(iPos < 0 || _Head == NULL)             // empty list
    {
        return ;
    }

    SKBStringData* pCurrData = _Head;
    for(int i =0; i < iPos-1; i++)
    {
        pCurrData = pCurrData->GetLink();
    }
    pCurrData->SetLink(pCurrData->GetLink()->GetLink());
    delete pCurrData;
    return;
}

void SKBStringList:: Find(const char* iData,int &oPos)
{
    if(_Head == NULL || iData == NULL)
    {
        return;
    }

    int nStatus = -1;
    int nCount  = 0;
    SKBStringData* pCurrData = _Head;
    while(pCurrData->GetData() != NULL)
    {
        if(pCurrData->GetData() == iData)
        {
            nStatus = 0;
            break;
        }
        else
        {
            nCount++;
            pCurrData = pCurrData->GetLink();
        }
    }


    if(nStatus == 0)
    {
        oPos = nCount; 
    }
    else
    {
        oPos = -1;
    }

    return ;
}