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

181
16 апреля 2018, 00:18

Здравствуйте. Столкнулся с такой задачей. Нужно инициализировать односвязный список, ввести его с клавиатуры и вывести. Перепробовал все способы. Но почему-то при выводе списка выводится только первый элемент. Может кто знает как исправить?

Заранее благодарю

P.S. Данные в списке представлены в виде структуры. И заранее не известно сколько пользователь введет элементов списка

#include <iostream>
#include <Windows.h>
using namespace std;
//List #1
struct A
{
    int cyfra;
    char symbol;
};
struct List
{
    A a;
    List* next;
};
void Init(List** b)
{
    (*b) = new List;
    List *end = NULL;
    for (int i = 0; ; i++) {
        if (i == 0)
        {
            cin >> (*b)->a.cyfra >> (*b)->a.symbol;
            (*b)->next = NULL;
            end = (*b);
        }
        else {
            end->next = new List;
            cin >> end->a.cyfra >> end->a.symbol;
            end = end->next;
            end->next = NULL;
        }
        if (GetAsyncKeyState(VK_RETURN))break;
    }
}
void Print(List *b)
{
    List *print = b;
    cout << endl;
    while (print != NULL)
    {
        cout << print->a.cyfra << print->a.symbol << " ";
        print = print->next;
    }
}
void main()
{
    //Initial L prim
    List* begin = NULL;
    Init(&begin);
    cout << "List: ";
    Print(begin);
    system("pause");
}
Answer 1

Односвязные списки это очень простая штука. Главное, чтобы код, работающий с ними, был структурирован в соответствии с шагами алгоритма (КО -)).

Вашу задачу совершенно логично решает вот такой main:

int main () {
  // Получить заполненный список
  List *list = get_list();
  // поэлементно распечатать его
  cout << "List:\n";
  for (List *p = list; p; p = p->next)
    cout << p->a.cyfra << p->a.symbol << ' ';
}

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

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

List *get_list () {
  List *head = get_AList_item(), // взять первый элемент списка
       *tail = head;             // сейчас он же и последний в списке
  if (head) 
    while ((tail->next = get_AList_item())) // обратите внимание, здесь мы автоматически получаем обнуленный указатель на следующий у последнего элемента списка
      tail = tail->next;
  return head;  // тут накопили весь список
}

Думаю, что функцию (get_AList_item()), реализующую ввод данных и выделяющую память под каждый элемент вы сами легко напишете.

В качестве простого ее примера:

List * get_AList_item () {
  List *elem = new List;
  if (cin >> elem->a.cyfra >> elem->a.symbol) 
    return elem;
  delete elem;
  return 0;
}

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

Answer 2
  else {
            end->next = new List;
            end = end->next; // 
            cin >> end->a.cyfra >> end->a.symbol; // тут           
            end->next = NULL;

такой вариант пробуйте.

И еще, в любом случаи правильнее будет в конструкторе класса list сразу инициализировать next нулем, чтоб в коде каждый раз не делать это в ручную...

struct A
{
    int cyfra;
    char symbol;
};
struct List
{
    A a;
    List* next;
    List() : next(0) {a.cyfra = 0; a.symbol = '8';}
    ~List() {delete next;}
};
  void Init(List*& b)
{
    b = new List;
    List *end = b;
    while (cin >> end->a.cyfra >> end->a.symbol) {
        end->next = new List;
        end = end->next;
    }
}
void Print(List *b)
{
    List *print = b;
    cout << endl;
    while (print->next)
    {
        cout << print->a.cyfra  << " " << print->a.symbol << " ";
        print = print->next;
    }
}
int main()
{  
    List* begin = NULL;
    Init(begin);
    cout << "List: ";
    Print(begin);
    return 0;
}

Этот код работает как надо...

Answer 3
        end->next = new List;
        cin >> end->next->a.cyfra >> end->next->a.symbol;
READ ALSO
Qt С++ | Поиск виджетов

Qt С++ | Поиск виджетов

Суть: при нажатии одной кнопки на форме динамически создаются лейблы с уникальными именами При нажатии второй кнопки, должен выделять определенный...

136
Некорректная работа try\catch в цикле

Некорректная работа try\catch в цикле

Добрый день! Излагаю суть дела: есть проверка, согласно которой пользователь не должен ввести символы или ещё какую-то ерунду вместо обычного...

173
Зачем нужны динамические массивы в C++?

Зачем нужны динамические массивы в C++?

В учебниках по C++ пишут, что динамические массивы нужны, когда заранее неизвестны размеры этих массивовПотом идет объяснение, как выделять...

212
Взаимодейстие с клавиатурой на C/C++

Взаимодейстие с клавиатурой на C/C++

1-2 дня назад я задал вопрос, но не совсем корректный, поэтому сейчас я постараюсь поставить его более правильноДопустим, есть игра, в которой...

157