ANTICHAT — форум по информационной безопасности, OSINT и технологиям
ANTICHAT — русскоязычное сообщество по безопасности, OSINT и программированию.
Форум ранее работал на доменах antichat.ru, antichat.com и antichat.club,
и теперь снова доступен на новом адресе —
forum.antichat.xyz.
Форум восстановлен и продолжает развитие: доступны архивные темы, добавляются новые обсуждения и материалы.
⚠️ Старые аккаунты восстановить невозможно — необходимо зарегистрироваться заново.
 |
|

25.07.2009, 15:46
|
|
Участник форума
Регистрация: 02.12.2007
Сообщений: 132
Провел на форуме: 233095
Репутация:
21
|
|
Я понимаю листы так:
Он состоит из головы, узла с данными и хвоста. Но я не могу понять роли каждого из элементов. Ну на пример, я вижу роли так - в узле содержатся данные и адрес следующего узла. В голове содержится адрес первого узла. В хвосте содержится адрес головы или как?
В общем посидел, подумал поэкспериментировал...
Код:
#include <iostream>
using namespace std;
class List
{
public:
List* next;
int data;
};
class Head
{
public:
List* next;
};
/*class Tail
{
public:
List* last;
};*/
void main()
{
// начало списка, создание первого узла и головы
List* Node = new List;
Head* head = new Head;
//Tail* tail = new Tail;
head->next = Node;
int i = 1;
//Добавление:
while(1)
{
cout << "data #" << i << " = ";
cin >> Node->data;
i++;
if(!Node->data)
{
//tail->last = Node;
break;
}
Node->next = new List;
Node = Node->next;
}
cout << head->next->data << endl;
}
1. Правильный ли я лист создал?
2. Как мне вывести все значения в листе, начиная с головы?(данный вариант вывода показывает только одно значение с первого узла, хотя в отладке я вижу полную иерархию всех значений)
3. Если лист правильный, то можно ли его оптимизировать?
4. Что вообще нужно с хвостом делать?
Последний раз редактировалось horlyk; 25.07.2009 в 16:50..
|
|
|

25.07.2009, 18:32
|
|
Постоянный
Регистрация: 03.06.2009
Сообщений: 385
Провел на форуме: 3178262
Репутация:
389
|
|
Смысл в том, ч то у нас есть элемент, в котором
Код:
Односвязный список
info - тело несущее информацию
after - адрес следующего элемента
Код:
Двусвязный список
befor - адрес предидущего элемента
info - тело несущее информацию
after - адрес следующего элемента
тогда зная адрес первого элемента - можно обрататиться к цепочки. Когда after = NULL - значит конец цепочки
Чтобы получить нужный элемент, мы начиная с первого в цикле прыгаем на адрес следуеющего элемента => количество прыжков = индекс эелмента
Пример на C - работа с односвязным списком:
Код:
#include <iostream>
#include <cstdlib>
#define length 20
void create(char filename[]);
void open(char filename[], struct s_item *item[]);
int find(struct s_item *item[]);
int add_item(struct s_item item, int position);
int del_item(int position);
int erase_item();
int show_items();
struct s_item
{
int id;
char name[length];
};
struct p_item
{
struct s_item info;
struct p_item *next;
};
struct p_item *first;
struct p_item *counter;
int main()
{
system("chcp 1251");
printf("\n");
struct s_item item;
char menu;
char filename[length];
int high;
int size;
int position;
first = NULL;
while(true)
{
printf("Введите номер действия :\n");
printf("========================\n");
printf("1 - Добавить\n");
printf("2 - Вставить\n");
printf("3 - Удалить\n");
printf("4 - Очистить\n");
printf("5 - Вывести\n");
printf("6 - Выход\n\n");
printf("Номер = "); scanf("%i", &menu);
printf("\n");
if (menu == 1 || menu == 2)
{
printf("Введите номер товара : "); scanf("%i", &item.id);
printf("Введите наименование товара : "); scanf("%s", &item.name);
printf("\n");
}
switch(menu)
{
case 1:
position = -1;
add_item(item, position);
break;
case 2:
printf("Введите позицию вставки : "); scanf("%i", &position);
printf("\n");
add_item(item, position);
break;
case 3:
printf("Введите позицию удаления : "); scanf("%i", &position);
printf("\n");
del_item(position);
break;
case 4:
erase_item();
break;
case 5:
show_items();
break;
case 6:
return EXIT_SUCCESS;
break;
default:
return EXIT_SUCCESS;
break;
}
}
return EXIT_SUCCESS;
}
int erase_item()
{
struct p_item *now;
counter = first;
while (counter != NULL)
{
now = counter->next;
counter->next = NULL;
free(counter);
counter = now;
}
first = NULL;
}
int add_item(struct s_item item, int position)
{
struct p_item *now;
struct p_item *tmp;
now = (p_item *) malloc(sizeof(p_item));
if (now == NULL)
{
printf("Not enough memory to allocate buffer\nProgramm halted...\n");
} else {
now->info = item;
now->next = NULL;
if (first == NULL)
{
first = now;
} else {
switch (position)
{
case -1:
counter = first;
while (counter->next != NULL)
{
counter = counter->next;
}
counter->next = now;
break;
case 0:
tmp = first;
first = now;
now = tmp;
first->next = now;
printf("%i - %i = %i", first->next, now, now->next);
break;
default:
counter = first;
for (int i = 2; i <= position; i++)
{
counter = counter->next;
if (counter == NULL)
{
printf("Position not in array!\n");
return 0;
}
}
now->next = counter->next;
counter->next = now;
break;
}
return 1;
}
}
return 0;
}
int del_item(int position)
{
struct p_item *now;
if (first == NULL)
{
return 0;
} else {
if (position > -1)
{
if (position == 0)
{
now = first;
first = first->next;
} else {
counter = first;
now = counter->next;
for (int i = 2; i <= position; i++)
{
counter = counter->next;
now = counter->next;
if (now == NULL)
{
printf("Position not in array!\n");
return 0;
}
}
counter->next = now->next;
now->next = NULL;
}
free(now);
} else {
counter = first;
now = counter->next;
while (now->next != NULL)
{
counter = counter->next;
now = counter->next;
}
free(now);
counter->next = NULL;
}
return 1;
}
return 0;
}
int show_items()
{
counter = first;
if (first == NULL)
{
printf("Записей нет!\n\n");
} else {
printf("Вывод товара\n");
printf("=============\n");
while(counter != NULL)
{
printf("Номер товара = %i\n", counter->info.id);
printf("Наименование товара = %s\n", counter->info.name);
printf("\n");
counter = counter->next;
}
printf("\n");
}
}
Последний раз редактировалось FireFenix; 25.07.2009 в 18:54..
|
|
|

25.07.2009, 19:16
|
|
Участник форума
Регистрация: 02.12.2007
Сообщений: 132
Провел на форуме: 233095
Репутация:
21
|
|
FireFenix, спасибо, но мне пока сложно большие примеры разбирать. В книге тоже не маленький, потому и много сложностей.
Если не сложно - разберите прогу что я написал с ответами на вопросы тобишь доработкой.
Спасибо.
|
|
|

25.07.2009, 20:19
|
|
Постоянный
Регистрация: 16.08.2006
Сообщений: 640
Провел на форуме: 1354067
Репутация:
599
|
|
ты представь состав из вагонов. как понять, что вагон начинает состав? у него нет предыдущего вагона.
как понять, что вагон последний - у него нет следующего.
так и со списками. голова и хвост - это логические описание конкретного элемента списка. это не отдельный тип элемента списка. в этом собсно суть.
в твоем примере нужен только класс лист. переименуй его в ListItem. он сожержит данные и указатель на следующий элемент.
Добавь еще один класс - List. он как раз управляет элементами и содержит поле ListItem* head;
Если кратко получишь такое
Код:
class ListItem{
public:
ListItem(int _data){
data = _data;
next = 0;
};
int data;
ListItem* next;
};
class List{
public:
void add(int data){
getTail()->next = new ListItem(data);
};
bool find(int data);
bool del(int data);
private:
ListItem* getTail(){
ListItem* item = head;
while(item->next){
item = item->next;
}
return item;
};
ListItem* head;
};
Последний раз редактировалось Ra$cal; 25.07.2009 в 21:15..
|
|
|

25.07.2009, 21:40
|
|
Участник форума
Регистрация: 02.12.2007
Сообщений: 132
Провел на форуме: 233095
Репутация:
21
|
|
Ra$cal, спасибо, буду разбираться.
|
|
|

26.07.2009, 16:21
|
|
Участник форума
Регистрация: 02.12.2007
Сообщений: 132
Провел на форуме: 233095
Репутация:
21
|
|
и кстати, нашел интересную инфу о листах, главное очень понятно и толково рассказано.
линк
Там в нескольких шагах рассказано все.
З.Ы. Что значит к примеру такое объявление, выделенное красным цветом, тоесть две звездочки и для чего оно нужно?:
void POSTROENIE (node **phead)
Последний раз редактировалось horlyk; 26.07.2009 в 16:26..
|
|
|

26.07.2009, 17:08
|
|
Постоянный
Регистрация: 24.03.2009
Сообщений: 670
Провел на форуме: 2868783
Репутация:
414
|
|
void POSTROENIE (node **phead)
косвенная адресация (указатель на указатель), можно использовать для работы с массивами.
|
|
|

26.07.2009, 18:26
|
|
Участник форума
Регистрация: 02.12.2007
Сообщений: 132
Провел на форуме: 233095
Репутация:
21
|
|
А преимущество в чем?
|
|
|

26.07.2009, 18:54
|
|
Постоянный
Регистрация: 16.08.2006
Сообщений: 640
Провел на форуме: 1354067
Репутация:
599
|
|
только так можно сделать многомерные массивы аля матрица
на счет описания. сложно оценить. в списке я не вижу никаких трудностей. то что ты стал мутить с классами - проблема не в списке. проблема в использовании ООП. ты создал отдельные классы для сущностей, которые не отличаются ничем в поведении. все равно что создавать класс для числа 1, другой класс для числа 2, итд. Так что стоит внимательнее перечитать, что пишут про выделение классов. Все таки их разделяют не именам, а по поведению. Если поведение не отличается - делается переменная этого класса, имеющая имя, которое характеризует назначение этого объекта. вот если бы хвост например не мог содержать число 555, а голова число 777, то тут есть повод выделить доп классы, потому как поля вроде как одинаковые, но поведение отличается.
ps: стиль именования в статье ужасен просто аж ппц. и постоянные размыеновавния. как будто человек не знает про "->"
Последний раз редактировалось Ra$cal; 26.07.2009 в 19:04..
|
|
|

26.07.2009, 20:21
|
|
Участник форума
Регистрация: 02.12.2007
Сообщений: 132
Провел на форуме: 233095
Репутация:
21
|
|
Сообщение от Ra$cal
только так можно сделать многомерные массивы аля матрица
на счет описания. сложно оценить. в списке я не вижу никаких трудностей. то что ты стал мутить с классами - проблема не в списке. проблема в использовании ООП. ты создал отдельные классы для сущностей, которые не отличаются ничем в поведении. все равно что создавать класс для числа 1, другой класс для числа 2, итд. Так что стоит внимательнее перечитать, что пишут про выделение классов. Все таки их разделяют не именам, а по поведению. Если поведение не отличается - делается переменная этого класса, имеющая имя, которое характеризует назначение этого объекта. вот если бы хвост например не мог содержать число 555, а голова число 777, то тут есть повод выделить доп классы, потому как поля вроде как одинаковые, но поведение отличается.
ps: стиль именования в статье ужасен просто аж ппц. и постоянные размыеновавния. как будто человек не знает про "->"
Ну про код - согласен, но картинки сделали более понятным представление головы и дальнейшее построение списка.
З.Ы. Сейчас пишу прогу по созданию листа. Уже реализовал заполнение листа данными, вывод данных на экран, поиск во всем листе и вывод найденных данных на экран и удаление всего листа. Теперь хочу реализовать добавление в средину (или куда-то еще, то есть сдвиг) узла в лист и удаление одного узла.
З.Ы.Ы Можно плз примерчик многомерными массивами(с использованием **указателя)
З.Ы.Ы.Ы Еще раз спасибо за объяснения
|
|
|
|
 |
|
|
Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
|
|
|
|