Модераторы: bsa

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Однонаправленный список, Однонаправленный список  
:(
    Опции темы
Toyamatokanava
Дата 23.9.2015, 10:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 63
Регистрация: 29.10.2012
Где: Ростов-на-Дону

Репутация: нет
Всего: нет



Задание: постройте класс,представляющий однонаправленный список элементов, каждый из которых является структурой, состоящей из двух полей: первое некая информация, а второе- указатель на следующий элемент. Класс должен содержать методы добавить элемент , удалить элемент, выдать информацию н-ного элемента, печать значений информационных полей. Вопрос в том как в однозначном списке удалять элементы? Для меня это не однозначно), направте меня, пожалуйста.)

Код

#include "stdafx.h"
#include <conio.h>
#include <iostream>
using namespace std;
struct element // структура с инфополями и адресным полем
{
    int x;//
    element *Next;
    };

class List//Класс список
{
    element *Head;//указатель на последний активный элемент или просто голова списка
    public:
    List() { Head = NULL; }//КОнструктор и инициализация указателя пустым значением
    ~List();//Деструктор
    void Add(int x);//функция добавления значений в список
    void Show(int N);//функция для отображения списка на экране
    void get(const int N); //Объявлена функция извлечения элемента
    void del(const int y);//объявлена функция удаления элемента
};
List::~List()//Деструктор вынесен за класс
{ while (Head!=NULL)//пока по адресу не пусто
{
    element *temp = Head->Next;//Временная переменная для хранения адиреса следующего элемента
    delete Head;//освобождаем адрес обозначающий начало
    Head = temp;// Меняем адрес на следующий
}
system("pause");
}
void List::Add(int x)//функция добавления элементов в список
{
    element *temp = new element;//при каждом вызове выделяется память
    temp->x = x;//записываем х в элемент структуры element (в х структуры element)
    temp->Next = Head;//Указываем, что следующий элемент это объект по адресу Head
    Head = temp;//Указываем, что последний активный элемент это только чтовведенный
}
void List::Show(int N)//Функция отображения списка на экране
{
    element *temp = Head;//Определяем указатель, который изначально равен адресу начала списка
    while (temp!=NULL)//До тех пор пока не встретит пустое значение
    {
        for (int i = 1; i < N+1; i++)
        {
            cout << i << " элемент =" << temp->x << "\n";//выведен элемент х из списка
            temp = temp->Next;//Указывем, что далее нам нужен следующий элемент
        }
    }
}


void List::get(const int p) //В качестве параметра принимается номер извлекаемого элемента
{
    element *temp = Head; //Обращаемся к началу списка
    if ((Head != NULL)) //Делаем проверку на то что список не пуст и N не превышает число его элементов
    {
        for (int i = 1; i < p ; i++) temp = temp->Next; //Меняем адрес N раз

        cout <<"элемент "<<p<<"="<< temp->x << " " << endl; //Выводим N элемент списка на экран
        system("pause");
    }
    cout << endl;
}
void main()
{
    setlocale(LC_ALL, "Russian");
    int N; //Число элементов в список
    int x; //Элементы вводимые в список
    List lst; //Переменная, тип которой список
    cout << "Введите количество элементов\n";
    cout << "N = "; cin >> N; //Указали сколько элементов вводить в список
    cout << "Введите значения полей\n";
    for (int i = 0; i<N; i++)
    {
        cout << i + 1 << " элемент ="; cin >> x; //Ввод x с клавиатуры
        lst.Add(x); //Добавление элемента в список
    }
    cout << "Однонаправленный список\n";
    lst.Show(N); //Вывод списка на экран
    int p;
    cout << "Введите номер элемента, информацию о котором хотите вывести - ";
    cin >> p;
    lst.get(p);

}

PM MAIL   Вверх
rudolfninja
Дата 23.9.2015, 10:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 341
Регистрация: 19.2.2013
Где: г. Минск

Репутация: 1
Всего: 6



Удаление происходит просто: получаете адрес элемента, который нужно удалить; запоминаете куда-нибудь указатель на следующий после него элемент; пишите delete <адрес удаляемого элемента>; а предыдущему элементу в поле Next записываете то, что запомнили во втором пункте.
Допустим, нам надо удалить элемент to_del
Код

element* curr = Head;
while(curr->next != to_del)
{
curr = curr->next; // получили элемент, который стоит перед удаляемым
}
curr->next = to_del->next;
delete to_del;

Этот код должен работать при удалении всех элементов кроме первого. Для первого надо сделать проверку, что удаляемый элемент является первым и в этом случае, просто перенаправить "голову" списка на следующий элемент, а прошлую "голову" удалить.
Код

if(to_del == Head)
{
Head = Head->next;
delete to_del;
}

Если все это объединять в одну функцию, то надо сделать return, после удаления первого элемента.

Вообще, по спискам очень много подробной разъясняющей информации в интернете. Для своего ознакомления поищите там и прочитайте пару статеек с примерами и объяснениями. Если сами не найдете, напишите, подкину ссылок.

Это сообщение отредактировал(а) rudolfninja - 23.9.2015, 10:42
PM MAIL Skype   Вверх
Toyamatokanava
Дата 23.9.2015, 11:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 63
Регистрация: 29.10.2012
Где: Ростов-на-Дону

Репутация: нет
Всего: нет



Цитата(rudolfninja @ 23.9.2015,  10:39)
Удаление происходит просто: получаете адрес элемента, который нужно удалить; запоминаете куда-нибудь указатель на следующий после него элемент; пишите delete <адрес удаляемого элемента>; а предыдущему элементу в поле Next записываете то, что запомнили во втором пункте.
Допустим, нам надо удалить элемент to_del
Код

element* curr = Head;
while(curr->next != to_del)
{
curr = curr->next; // получили элемент, который стоит перед удаляемым
}
curr->next = to_del->next;
delete to_del;

Этот код должен работать при удалении всех элементов кроме первого. Для первого надо сделать проверку, что удаляемый элемент является первым и в этом случае, просто перенаправить "голову" списка на следующий элемент, а прошлую "голову" удалить.
Код

if(to_del == Head)
{
Head = Head->next;
delete to_del;
}

Если все это объединять в одну функцию, то надо сделать return, после удаления первого элемента.

Вообще, по спискам очень много подробной разъясняющей информации в интернете. Для своего ознакомления поищите там и прочитайте пару статеек с примерами и объяснениями. Если сами не найдете, напишите, подкину ссылок.

Да, скиньте пожалуйста статьи, буду очень благодарен.
PM MAIL   Вверх
rudolfninja
Дата 23.9.2015, 12:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 341
Регистрация: 19.2.2013
Где: г. Минск

Репутация: 1
Всего: 6



Я в свое время по этой статье разибрался в теме списков.
Вот еще нашел, на первый взгляд нормально написано, но особо не вчитывался.
Удачи. Будут вопрсы - пишите сюда.
PM MAIL Skype   Вверх
baldina
Дата 23.9.2015, 13:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 15
Всего: 101



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

element *List::DeleteNext (element *e) {
   if (e->next) {
     element* next = e->next->next;
     delete e->next;
     e->next = next;
     return next;
   }
   else
     return 0;
}

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

void List::DeleteHead () {
   element temp;
   temp.Next = Head;
   Head = DeleteNext (&temp);
}

3. удаление последнего. ищем предпоследний, удаляем следующий за ним.
Код

void List::DeleteTail () {
   if (Head->Next == 0) // первый и есть последний
   {
      DeleteHead ();
   }
   else {

     element *e= Head;
     while (e->Next->Next != 0) 
        e = e->Next;
 
     DeleteNext (e);
   }
}


3. удаление указанного. для удаления используем нехитрый трюк: меняем значения удаляемого и следующего за ним, после чего удаляем следующий. 
Код

void List::Delete (element *e) {
   if (e == 0)
      return;

   if (e == Head) // указанный - первый
   {
      DeleteHead ();
   }
   else if (e->next == 0) // указанный - последний
   {
      DeleteTail ();
   }
   else 
   {
      e->x = e->next->x;
      DeleteNext (e);
   }
}


Добавлено через 5 минут и 29 секунд
пожалуй последнюю функцию можно сократить
Код

void List::Delete (element *e) {
   if (e == 0)
      return;
   
   if (e->next == 0) // указанный - последний
   {
      DeleteTail (); // учитывает, что последний может быть первым
   }
   else 
   {
      e->x = e->next->x;
      DeleteNext (e);
   }
}

PM MAIL   Вверх
feodorv
Дата 23.9.2015, 15:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(baldina @  23.9.2015,  13:05 Найти цитируемый пост)
после чего удаляем следующий

Я, лично, выступаю против такого подхода))) Если сказано удалить текущий элемент, то и нужно удалить текущий элемент, мало ли какие связи между элементами списка и экземплярами других классов/структур в программе образуются в процессе её развития. Но в данном случае можно себе позволить. Я, собственно, просто хочу поправить: если мы решили удалять следующий вместо текущего, то тогда это будет выглядеть приблизительно так:
Цитата(baldina @  23.9.2015,  13:05 Найти цитируемый пост)
   else 
   {
      e->x = e->next->x;
      e->next = e->next->next;
      delete e->next;
   }



Это сообщение отредактировал(а) feodorv - 23.9.2015, 19:10


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
baldina
Дата 23.9.2015, 15:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 15
Всего: 101



Цитата(feodorv @  23.9.2015,  15:00 Найти цитируемый пост)
Я, лично, выступаю против такого подхода))) Если сказано удалить текущий элемент, то и нужно удалить текущий элемент, мало ли какие связи между элементами списка и экземплярами других классов/структур в программе образуются

Здесь мы имеем дело с ADT, поэтому особенности реализации никого не должны волновать.

Цитата(feodorv @  23.9.2015,  15:00 Найти цитируемый пост)
если мы решили удалять следующий вместо текущего, то тогда это будет выглядеть приблизительно так

нет, будет выглядеть как надо: DeleteNext(e) удаляет next->e

Добавлено через 6 минут и 44 секунды
однако исходя из void del(const int y), где y - явно порядковый номер, все несколько проще))
PM MAIL   Вверх
volatile
Дата 23.9.2015, 16:44 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(baldina @  23.9.2015,  15:13 Найти цитируемый пост)
Здесь мы имеем дело с ADT, поэтому особенности реализации никого не должны волновать.

Вы перемещаете данные, поэтому эта особенность может как раз волновать.
Указатели на элементы в вызывающей программе (если таковые были), становятся не валидными.
std::list например гарантирует валидность итераторов при удалении/добавлении, чем и ценен.
мне кажется это хотел сказать feodorv
(кроме того операция копирования может быть сама по себе дорога)

зы
по коду вроде верно.

PM MAIL   Вверх
feodorv
Дата 23.9.2015, 19:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(baldina @  23.9.2015,  15:13 Найти цитируемый пост)
нет, будет выглядеть как надо: DeleteNext(e) удаляет next->e

Прошу прощения, туплю)))
baldina, красиво, конечно, но я всё равно против smile 

Это сообщение отредактировал(а) feodorv - 23.9.2015, 19:27


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Toyamatokanava
Дата 24.9.2015, 18:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 63
Регистрация: 29.10.2012
Где: Ростов-на-Дону

Репутация: нет
Всего: нет



Я вот чего не пойму.  Допустим у нас есть 5 элементов в списке. Мы вызывая temp=temp-》next листаем до 4-го. Как мы вернемся назад, ведь список даже не кольцевой?
PM MAIL   Вверх
baldina
Дата 25.9.2015, 02:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 15
Всего: 101



Цитата(Toyamatokanava @  24.9.2015,  18:13 Найти цитируемый пост)
Как мы вернемся назад

зачем?
PM MAIL   Вверх
baldina
Дата 25.9.2015, 02:43 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 15
Всего: 101



Цитата(volatile @  23.9.2015,  16:44 Найти цитируемый пост)
Вы перемещаете данные, поэтому эта особенность может как раз волновать.

такой момент есть, но он касается типа перемещаемых данных. для int мне показалось безопасным smile

в общем случае лучше использовать swap, но это имхо усложнит понимание для ТС
сам факт манипуляции данными внутри этой структуры мне кажется не слишком важным, т.к. если копирование затруднено, то должна вызывает сомнение и функция add(). кстати, вас не смущает, что vector может перемещать элементы и не сохраняет итераторы? это вопрос требований к типу, а список славен не только итераторами (которых в нашем классе кстати нет). что вы думаете насчет наличия в классе двух разных функций удаления с разными гарантиями?

ломать копья тут нечего, задача сферическая, а любое решение будет иметь потенциальные недостатки.
в данном случае хотелось показать, что необязательно бегать по списку. но за такую возможность надо платить, да))
PM MAIL   Вверх
baldina
Дата 25.9.2015, 03:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 15
Всего: 101



Цитата(volatile @  23.9.2015,  16:44 Найти цитируемый пост)
std::list например гарантирует валидность итераторов при удалении/добавлении, чем и ценен.
мне кажется это хотел сказать feodorv

признаться не понял сразу истинный смысл)) да, согласен, указатели на элементы списка могут перестать указывать куда надо, это действительно может быть проблемой. 
злоупотребление указателями на внутренние структуры имхо неплохая попытка выстрелить себе в ногу.
PM MAIL   Вверх
Toyamatokanava
Дата 25.9.2015, 08:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 63
Регистрация: 29.10.2012
Где: Ростов-на-Дону

Репутация: нет
Всего: нет



Цитата(baldina @ 25.9.2015,  02:10)
Цитата(Toyamatokanava @  24.9.2015,  18:13 Найти цитируемый пост)
Как мы вернемся назад

зачем?

Допустим у нас есть список и программка зашла в бесконечный цикл, которые предлагает нам либо вывести список, либо удалить какой-то элемент, либо вывести на экран определенный элемент. Допустим мы вывели элемент n из общего количества элементов N,где n<N и программка вернулась в наш бесконечный цикл. Если после этого выбрать вариант вывести на экран список, то нужно же как-то вернуться на самый первый указатель списка? Возможно вопрос пришел в связи явным непониманием темы, поправьте пожалуйста.
PM MAIL   Вверх
Toyamatokanava
Дата 25.9.2015, 09:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 63
Регистрация: 29.10.2012
Где: Ростов-на-Дону

Репутация: нет
Всего: нет



Или проще. Ввели 5 элементов. Далее вывели на экран  их, значит temp будет указывать на 0 после вывода. Допустим мы хотим вывести 3 элемент, как указатель вернуть назад?
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.1119 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.