Подсчет вхождения в односвязном списке по узлам - PullRequest
0 голосов
/ 20 мая 2018

Я пишу простое приложение, которое получает list и сохраняет объекты как nodes в односвязном списке , и мы можем add(), remove(), copy() и т. Д.каждый узел в зависимости от заданного набора данных.каждый узел имеет char value, который является нашими данными, и int count, который подсчитывает вхождение связанного char.

, например, для списка, подобного

a, a, b, b, c, a

будет три узла (так как есть три разных символа):

[a,3,*next] -> [b,2,*next] -> [c,1,*next] -> nullptr

bool isAvailable() проверяет, есть ли данные в списке или нет.

Q: При вставке данных есть две опции:

  1. Данныене было введено: поэтому мы должны создать newNode с заданными данными, count=1 и *next=NULL.

  2. Данные уже введены: поэтому мы должны count++ узел, который имеет те же данные.

Я знаю, доступны ли данные данные или нет, но как я могу указать на узел с такими же данными?

Вот код:

#include "stdafx.h"
#include<iostream>
using namespace std;

class Snode
{
public:
    char data;
    int count;
    Snode *next;
    Snode(char d, int c)
    {
        data = d;
        count = c;
        next = NULL;
    }
};

class set
{
private:
    Snode *head;
public:
    set()
    {
        head = NULL;
        tail = NULL;
    }
    ~set();
    void insert(char value);
    bool isAvailable(char value);
};

set::~set()
{
    Snode *t = head;
    while (t != NULL)
    {
        head = head->next;
        delete t;
    }
}

bool set::isAvailable(char value)
{
    Snode *floatingNode = new Snode(char d, int c);
    while(floatingNode != NULL)
    {
        return (value == floatingNode);
        floatingNode->next = floatingNode;
    }
}

void set::insert(char value)
{
    Snode *newNode = new Snode(char d, int c);
    data = value;
    if (head == NULL)
    {
        newNode->next = NULL;
        head = newNode;
        newNode->count++;
    }
    else
    {
        if(isAvailable)
        {
            //IDK what should i do here +_+
        }
        else
        {
            tail->next= newNode;
            newNode->next = NULL;
            tail = newNode;
        }
    }
}

Ответы [ 2 ]

0 голосов
/ 20 мая 2018

У вас было много проблем в вашем коде, давайте посмотрим, что они:

  1. Прежде всего, Snode не обязательно должен быть class, скорее вы можете пойтис простым strcut;так как нам нужно все public. (не ошибка, а хорошая практика)
  2. Вы можете просто инициализировать count = 1 и next = nullptr, так что нет необходимости инициализировать их конструктором throw.Единственный элемент, который нужно инициализировать через конструктор, это Snod's data.
  3. Поскольку c++11 вы можете использовать ключевое слово nullptr вместо NULL, которое обозначает буквальный указатель .
  4. Функция-член bool set::isAvailable(char value) не будет работать, как вы думаете.Здесь вы излишне создали new Snode и проверяете, указывает ли он на nullptr, что не позволяет вам даже войти в цикл.Кстати, то, что вы написали в цикле, тоже неправильно.Что вы подразумеваете под return (value == floatingNode);?floatingNode - это Snode по типу;не char.

Слушайте, это правильная реализация.Поскольку мы не хотим перезаписывать голову, создадим указатель Node* и присвоим ей head.Затем перебирайте список, пока не найдете совпадение.Если не найден, мы дойдем до конца isAvailable() и вернемся false.

     inline bool isAvailable(const char& value)
     {
         Node *findPos = head;

         while(findPos != nullptr)
         {
             if(findPos -> data == value) return true;
             else findPos = findPos->next_node;
         }
         return false;
     }
В void set::insert(char value) ваша логика верна, но реализация неверна.Ниже приводится правильная реализация. (Надеюсь, комментарии помогут вам понять.
void insert(const char& value)
{
    if(head == nullptr) // first case
    {
        Node *newNode = new Node(value);
        newNode->next_node = head;
        head = newNode;
    }
    else if(isAvailable(value)) // if node available
    {
        Node *temp = head;
        while(temp->data != value)  // find the node
            temp = temp->next_node;
        temp->count += 1;           // and count it by 1
    }
    else                            // all new nodes
    {
        Node *temp = head;
        while(temp->next_node != nullptr) // to find the null point (end of list)
            temp = temp->next_node;

        temp = temp->next_node = new Node(value); // create a node and assign there
    }
}
Ваш деструктор не удалит все, что вы создали.Это будет UB, так как вы удаляете только что созданный Snode t (то есть Snode *t = head;).Ниже приведена правильная реализация. (Снимите комментарий с сообщения об отладке, чтобы понять.)
   ~set()
    {
        Node* temp = head;
        while( temp != nullptr )
        {
            Node* next = temp->next_node;
            //std::cout << "deleting \t" << temp->data << std::endl;
            delete temp;
            temp = next;
        }
        head = nullptr;
    }

И последнее, но не менее важное, присвоение имени (set) того, что выесть здесь и то, что код делает точно, оба разные.Это больше похоже на простой связанный список без дубликатов.Это, однако, хорошо, чтобы поиграться с указателями и списками.

Чтобы сделать код или итерацию более эффективными, вы можете сделать что-то вроде следующего.В isAvailable(), в случае совпадения значения /, если вы нашли node, вы также можете просто увеличить его счетчик.Тогда в insert() вы можете подумать, если node является не доступной деталью.

Надеюсь, это было полезно.См. DEMO


#include <iostream>

// since you wanna have all of Node in public, declare as struct
struct Node
{
    char data;
    int count = 1;
    Node*  next_node = nullptr;
    Node(const char& a) // create a constrcor which will initilize data
        : data(a) {}    // at the time of Node creation
};

class set
{
private:
    Node *head;             // need only head, if it's a simple list
public:
    set()   :head(nullptr) {}   // constructor set it to nullptr
    ~set()
    {
        Node* temp = head;
        while( temp != nullptr )
        {
            Node* next = temp->next_node;
            //std::cout << "deleting \t" << temp->data << std::endl;
            delete temp;
            temp = next;
        }
        head = nullptr;
    }

    inline bool isAvailable(const char& value)
    {
        Node *findPos = head;

        while(findPos != nullptr)
        {
            if(findPos -> data == value) return true;
            else findPos = findPos->next_node;
        }
        return false;
    }

    void insert(const char& value)
    {
        if(head == nullptr) // first case
        {
            Node *newNode = new Node(value);
            newNode->next_node = head;
            head = newNode;
        }
        else if(isAvailable(value)) // if node available
        {
            Node *temp = head;
            while(temp->data != value)  // find the node
                temp = temp->next_node;
            temp->count += 1;           // and count it by 1
        }
        else                            // all new nodes
        {
            Node *temp = head;
            while(temp->next_node != nullptr) // to find the null point (end of list)
                temp = temp->next_node;

            temp = temp->next_node = new Node(value);
        }
    }

    void print() const      // just to print
    {
        Node *temp = head;
        while(temp != nullptr)
        {
            std::cout << temp->data << " " << temp->count << "\n";
            temp = temp->next_node;
        }
    }
};


int main()
{
    ::set mySet;

    mySet.insert('a');
    mySet.insert('a');
    mySet.insert('b');
    mySet.insert('b');
    mySet.insert('c');
    mySet.insert('a');

    mySet.print();

    return 0;
}
0 голосов
/ 20 мая 2018

Я знаю, доступны ли данные данные, но как я могу указать на узел с такими же данными?

Вам нужно будет начать с заголовка спискаи итерируйте по списку, следуя указателям next, пока не найдете узел с тем же значением data.Как только вы это сделаете, у вас есть указатель на узел с теми же данными.

Некоторые другие заметки для вас:

bool set::isAvailable(char value)
{
   Snode *floatingNode = new Snode(char d, int c);
   while(floatingNode != NULL)
   {
       return (value == floatingNode);
       floatingNode->next = floatingNode;
   }
}
  1. Почему эта функциявыделить new Snode?Для этого нет никаких причин, просто инициализируйте указатель floatingNode, чтобы он указывал на head.

  2. Эта функция всегда возвращается после просмотра только первого узла в связанномсписок - это не то поведение, которое вы хотите.Вместо этого он должен возвращать true только в том случае, если (значение == плавающий узел);в противном случае он должен оставаться внутри цикла while, чтобы можно было продолжить просмотр и последующих узлов.Только после того, как он выпадает из цикла while (потому что плавающий узел, наконец, становится NULL), он должен возвращать false.

  3. Если вам нужно было немного изменить isAvailable(), чтобы вместо возврата true или false, он вернул либо floatingPointer, либо NULL, у вас будет механизм поиска указателя на узел с совпадающими данными.

Например:

// Should return either a pointer to the Snode with data==value,
// or NULL if no such Snode is present in the list 
Snode * set::getNodeWithValueOrNullIfNotFound(char value) const
{
   [...]
}

void set::insert(char value)
{
   Snode * theNode = getNodeWithValueOrNullIfNotFound(value);
   if (theNode != NULL)
   {
      theNode->count++;
   }
   else
   {
      [create a new Snode and insert it]
   }
}
...