Форум программистов, компьютерный форум CyberForum.ru

Двусвязные списки, не могу добавить узел с конца - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 11, средняя оценка - 4.91
Virusolog
1 / 1 / 0
Регистрация: 22.11.2010
Сообщений: 32
22.03.2011, 10:51     Двусвязные списки, не могу добавить узел с конца #1
Делаю лабу по динамическим структурам данным, написал функцию добавления с начала и с конца.
Но, добавление с конца не работает, я не могу найти ошибки или недочета в алгоритме, не могу отследить причину того, что при добавлении узла с конца происходит постоянное перезаписывние вида

ввод: 56
->56
ввод: 4
->4

А должно в итоге быть как ->56->4

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include <iostream>
using namespace std;
struct list {
    int data;
    list *next; // Содержит адрес области в памяти на следующий элемент
    list *prev; // Содержит адрес в области памяти на предыдущий элемент
};
// Функции для работы со списком
list *prepend(int val,list *head){
    // Создаем список, оператор new возвращает адрес выделенного фрагмента памяти
    list *pointer = new list; //выделение памяти для новой ячейки
    pointer->data = val; //запись данных в ячейку
    pointer->next = NULL; //инициализация нулем
    pointer->prev = NULL; //инициализация нулем
    // Если список пуст
    if(head == NULL){
      return pointer;
    }
    else {// Если в списке есть хотя бы одна ячейка
      pointer->next = head; //после этой ячейки должна идти бывшая первая
      head->prev = pointer;
      head = pointer; //началом списка делаем только что созданную ячейку
      return head;
    }
};
 
list *append(int val, list *head){
    list *prev,*ptr;
    // Добавить узел в конце списка
    list *pointer = new list;
    pointer->data = val;
    pointer->next = NULL;
    pointer->prev = NULL;
    // Если список пуст
    if(head == NULL){
        return pointer;
    }
    else {
        // Есть начальный адрес списка и только что созданный
        // Нужно найти адрес для последнего узла
        for(prev = head, ptr = head->next; ptr; prev = ptr, ptr = ptr->next);
 
        if(ptr == NULL)
        {
           prev->next = pointer;
           pointer->prev = prev;
           return pointer;
 
        }
    }
};
 
void printlist(list *first){
    list *ptr; //копируем начальный адрес
    for(ptr = first; ptr; ptr = ptr->next){
        cout << "->" << ptr->data;
    }
};
 
void WorkWithList(){
    // Переменная List не содержит адреса на начало списка
    // List должна содержать начальный адрес списка
    list *List = NULL;
    int value,choice;
    for(;;)
    {
    // Вспомагательное меню для работы со списком
    cout << "(1) Dobavlenie uzla v nachalo spiska\n";
    cout << "(2) Dobavlenie uzla v konets spiska\n";
    cout << "(3) Dobavlenie uzla v zadannuy pozitsiu\n";
    cout << "(4) Udalenie tekushchego uzla\n";
    cin >> choice;
    switch(choice)
    {
        case 1:
            cout << "Enter a number ";
            cin >> value;
            // Добавить узел с новым значением в начало списка
            List = prepend(value,List);
            printlist(List);
            break;
        case 2:
            cout << "Enter a number ";
            cin >> value;
            // Добавить узел с новым значением в конец списка
            List = append(value,List);
            printlist(List);
            break;
    }
    }
};
void WorkWithStack(){
};
int main(){
    // Организация меню
    cout << "Enter a number between 1 and 3: ";
    int number;
    cin >> number;
    switch(number)
    {
        case 1: WorkWithList();
        case 2: WorkWithStack();
        // case 3: WorkWithFlow();
    }
    return 0;
}
Помогите, пожалуйста.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
22.03.2011, 10:51     Двусвязные списки, не могу добавить узел с конца
Посмотрите здесь:

ДВУСВЯЗНЫЕ СПИСКИ C++
C++ ДВУСВЯЗНЫЕ СПИСКИ!!!
двусвязные списки C++
Двусвязные списки C++
Шаблонные двусвязные списки. C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Dexter
 Аватар для Dexter
284 / 144 / 16
Регистрация: 13.10.2009
Сообщений: 164
22.03.2011, 11:24     Двусвязные списки, не могу добавить узел с конца #2
Ошибка простая:

C++
1
2
3
4
5
6
7
if(ptr == NULL)
                {
                   prev->next = pointer;
                   pointer->prev = prev;
                   return pointer;
 
                }
А именно: return pointer;

В коде:
C++
1
2
3
4
5
6
7
case 2:
                        cout << "Enter a number ";
                        cin >> value;
                        // Добавить узел с новым значением в конец списка
                        List = append(value,List);
                        printlist(List);
                        break;
Вы List присваиваете результат выполнения, то есть указатель на последний элемент, который вы добавили (а он должен быть указателем на первый элемент), после чего у вас на экран должно выводится - только последний элемент.

Замените
C++
1
return pointer;
на
C++
1
return head;
Virusolog
1 / 1 / 0
Регистрация: 22.11.2010
Сообщений: 32
22.03.2011, 13:08  [ТС]     Двусвязные списки, не могу добавить узел с конца #3
Декстер, спасибо тебе огромное!!!

Добавлено через 1 час 15 минут
Появилась проблема - как добавить узел в заданную позицию?
Какие вообще шаги нужно предпринять для этого?
C++
1
2
3
4
5
6
7
8
9
10
11
12
list *insert(int val, int poz, list *head){
    list *pointer = new list;
    pointer->data = val;
    pointer->next = NULL;
    pointer->prev = NULL;
    // Если список пуст
    if(head == NULL){
        return pointer;
    }
       ....
       ....
};
Dexter
 Аватар для Dexter
284 / 144 / 16
Регистрация: 13.10.2009
Сообщений: 164
22.03.2011, 13:40     Двусвязные списки, не могу добавить узел с конца #4
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
list *insert(int val, int poz, list *head){
    list *pointer = new list;
    pointer->data = val;
    pointer->next = NULL;
    pointer->prev = NULL;
    list *node=head;
    // Если список пуст
    if(head == NULL){
        return pointer;
    }
    int i=0;
    while(i<poz&&node->next!=NULL)//идем до нужной позиции
    {
        i++;
        node=node->next;
    }
        if(node->next == NULL&&i!=poz){//если позиция больше чем количество элементов
            node->next=pointer;
            pointer->prev=node;
            return head;
        }
        else//если нужно вставить перед этим элементом
        {
            pointer->next=node;
            pointer->prev=node->prev;
            if(node->prev)node->prev->next=pointer;
            node->prev=pointer;
            if(pointer->prev)return head;//если были предыдущие, то возвращаем начало списка
            else return pointer;//если нету, то это стало головой
        }
}
А шаги такие:
1)смотрим пустой список или нет, если пустой то делаем наш элемент головой
2)Пытаемся дойти до нужной позиции,
a)если позиция оказывается больше чем наше количество элементов, то добавляем его в конец
б)если позиция внутри, то вставляем узел в нужное место, для этого определяем prev и next элементы нашего узла, prev следующего и next предыдущего

Выше показано как можно такое сделать. (первый элемент, естественно 0-ой)
Virusolog
1 / 1 / 0
Регистрация: 22.11.2010
Сообщений: 32
22.03.2011, 13:59  [ТС]     Двусвязные списки, не могу добавить узел с конца #5
Спасибо большое!
afiskon
 Аватар для afiskon
65 / 53 / 3
Регистрация: 06.09.2010
Сообщений: 254
22.03.2011, 16:10     Двусвязные списки, не могу добавить узел с конца #6
Я конечно не специалист, но разве в STL нет готового решения? Почему бы вам его не использовать?
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
22.03.2011, 16:47     Двусвязные списки, не могу добавить узел с конца #7
afiskon, слышали об изобретении велосипедов в учебной практике?
Virusolog
1 / 1 / 0
Регистрация: 22.11.2010
Сообщений: 32
22.03.2011, 17:14  [ТС]     Двусвязные списки, не могу добавить узел с конца #8
Цитата Сообщение от silent_1991 Посмотреть сообщение
afiskon, слышали об изобретении велосипедов в учебной практике?
Да, что поделаешь, такие у нас задания.

Добавлено через 16 минут
Как теперь из этого списка можно удалить текущий узел?
Как удалить заданный узел (по номеру или по значению)?

Это все,что мне непонятно на данный момент
Dexter
 Аватар для Dexter
284 / 144 / 16
Регистрация: 13.10.2009
Сообщений: 164
22.03.2011, 18:26     Двусвязные списки, не могу добавить узел с конца #9
Помогу с удалением)
Наверное перемудрил, но делал бы что-то типа такого, чтобы было похоже на предыдущее:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
list *del(int poz, list *head, int posOrval=1, int all=0)//poz - значение или позиция, head - ну тут понятно, posOrval - если 0, то удаляем по значениям, иначе удаляем по номеру позиции, all - если удалять по значению, то удалять все или только 1ое
{
    list* node=head;
    // Если список пуст
    if(head == NULL){
        return NULL;
    }
    if(posOrval)//Если не 0, то удаляем позицию
    {   
        int i=0;
        while(i<poz&&node->next!=NULL)//идем до нужной позиции
        {
            i++;
            node=node->next;
        }
        if(node->next == NULL&&i!=poz){//если позиция больше чем количество элементов
            return head;//тогда нечего удалять
        }
        else//если нашлось что удалить
        {
            if(node->prev)node->prev->next=node->next;//ссылка предыдущего на следующий
            else //удаляется первый элемент, потому нужно отдать ссылку на второй
            {
                list* temp=node->next;//временно запомним 2ой элемент
                delete node;//так как здесь ссылка на него убивается
                return temp;//отдадим его
            }
            if(node->next)node->next->prev=node->prev;//ссылка следующего на предыдущий
            delete node;//удалили узел
            return head;
        }
    }
    else//если нужно удалить по значению
    {
        int i=0;
        list* res=head;//заведем ссылочку что нужно отдать(на случай удаления 1го элемента)
        do //ну циклик по всем узлам
        {
            if(node->data==poz&&node)//если совпало значение, то удаляем по позиции =)
            {
                node=del(i,res);
                res=node;
                if(!all)break;//если выбрано все удалять, то идем цикле, иначе выходим с него
                i=-1;//-1, чтобы при прокрутке i снова стало 0, то есть мы всегда начинаем искать с начал, можно скопировать код такой-же как при удалении по позиции, но впадло
            }
            else
            node=node->next;//если удалили то первый раз топать никуда ненадо
            i++;
        } while (node);
        return res;//ну и вернем результат
    }
}
Для удаления по позиции, достаточно вызвать
C++
1
List = del(value,List);
А для удаления всех узлов со значением value
C++
1
List = del(value,List,0,1);
Virusolog
1 / 1 / 0
Регистрация: 22.11.2010
Сообщений: 32
22.03.2011, 19:35  [ТС]     Двусвязные списки, не могу добавить узел с конца #10
Декстер, спасибо огромное, буду изучать
А вот вопрос в том - как удалить текущий узел??
Ведь в первых двух функция - добавлении с конца и сначала, я нигде не юзал - текущий узел
То есть как бы не понятно стало - удалить текущий узел
Dexter
 Аватар для Dexter
284 / 144 / 16
Регистрация: 13.10.2009
Сообщений: 164
23.03.2011, 10:17     Двусвязные списки, не могу добавить узел с конца #11
А вот вопрос в том - как удалить текущий узел??
В этом и проблема - вы должны определиться, что у вас "текущий узел", а потом удалять его. Если имеется ввиду - удаление узла по его указателю, так это просто нужно выдернуть часть кода с той функции что я набросал.
Обычно "текущим" называют тот, который используется в данный момент (просматривается, редактируется и тд.). Но у вас на данный момент работа со всем списком, а не с какими-то отдельными узлами. Возможно имеется ввиду - удаление узла с которым вы последним работали (который добавили куда-то) но как-то не смотрится, только добавили, сразу его удалять.
В общем, вам лучше знать как оно должно выглядеть Если сможете объяснить, то мы тут уже поможем)
Virusolog
1 / 1 / 0
Регистрация: 22.11.2010
Сообщений: 32
23.03.2011, 10:36  [ТС]     Двусвязные списки, не могу добавить узел с конца #12
Совершенно верно, имеется в виду - удаление текущего узла списка, то есть узла, который только,что добавили, н-р в конце списка. Я так понимаю - нужно сделать указатель current, который будет хранить адрес последнего добавленного узла в списке.

Ладно, а как тогда его удалить, этот текущий узел в отдельной функции для удаления текущего узла н-р remove?
Dexter
 Аватар для Dexter
284 / 144 / 16
Регистрация: 13.10.2009
Сообщений: 164
23.03.2011, 12:10     Двусвязные списки, не могу добавить узел с конца #13
Ну как и писал, просто выдергивается часть кода, где само удаление:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
list *remove(list *node, list* head){
    // Если список пуст
    if(head == NULL){
        return NULL;
    }
    if(node->prev)node->prev->next=node->next;
    else //удаляется первый элемент, потому нужно отдать ссылку на второй
    {
        list* temp=node->next;
        delete node;
        return temp;
    }
    if(node->next)node->next->prev=node->prev;
    delete node;
    return head;
}
Virusolog
1 / 1 / 0
Регистрация: 22.11.2010
Сообщений: 32
24.03.2011, 13:23  [ТС]     Двусвязные списки, не могу добавить узел с конца #14
Переписал функцию удаления текущего узла
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
list *remove(list *head,list **now){
        list *ptr = NULL;
        // Если список пуст
        if(head == NULL){
          return NULL;
        }
        for(ptr=head;ptr;ptr=ptr->next)
        {
            if(*now == ptr)
            {
                ptr->next->prev = ptr->prev;
                                ptr->prev->next = ptr->next;
                *now = ptr->next;
                if(ptr == head) head = head->next;
                return head;
            }
        return head;
        }
        
};
В итоге появляется ошибка - необработанное исключение в строке
ptr->prev->next = ptr->next;
Указатели в отладчике все NULL!

вызываю функцию так
C++
1
2
List = remove(List, &now);
        printlist(List);
Добавлено через 1 час 2 минуты
Весь код
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
#include <iostream>
using namespace std;
struct list {
    int data;
    list *next; // Содержит адрес области в памяти на следующий элемент
    list *prev; // Содержит адрес в области памяти на предыдущий элемент
};
// Функции для работы со списком
list *prepend(int val,list *head, list **now){
    // Создаем список, оператор new возвращает адрес выделенного фрагмента памяти
    list *pointer = new list; //выделение памяти для новой ячейки
    pointer->data = val; //запись данных в ячейку
    // Текущий узел
    *now = pointer;
    pointer->next = NULL; //инициализация нулем
    pointer->prev = NULL; //инициализация нулем
    // Если список пуст
    if(head == NULL){
      return pointer;
    }
    else {// Если в списке есть хотя бы одна ячейка
      pointer->next = head; //после этой ячейки должна идти бывшая первая
      head->prev = pointer;
      head = pointer; //началом списка делаем только что созданную ячейку
      return head;
    }
};
 
list *append(int val, list *head, list **now){
    list *prev,*ptr;
    // Добавить узел в конце списка
    list *pointer = new list;
    pointer->data = val;
    *now = pointer;
    pointer->next = NULL;
    pointer->prev = NULL;
    // Если список пуст
    if(head == NULL){
        return pointer;
    }
    else {
        // Есть начальный адрес списка и только что созданный
        // Нужно найти адрес для последнего узла
        for(prev = head, ptr = head->next; ptr; prev = ptr, ptr = ptr->next);
 
        if(ptr == NULL)
        {
           prev->next = pointer;
           pointer->prev = prev;
           return head;
 
        }
    }
};
 
list *insert(int val, int poz, list *head, list **now){
    list *pointer = new list;
    pointer->data = val;
    *now = pointer;
    pointer->next = NULL;
    pointer->prev = NULL;
    list *node=head;
    int i = 1;
    // Если список пуст
    if(head == NULL){
        return pointer;
    }
    else {
        // Если список не пуст, есть начальный адрес в памяти
        while(i<poz&&node->next!=NULL)//идем до нужной позиции
        {
                i++;
                node=node->next;
        }
                if(node->next == NULL&&i!=poz){//если позиция больше чем количество элементов
                        node->next=pointer;
                        pointer->prev=node;
                        return head;
                }
                else//если нужно вставить перед этим элементом
                {
                        pointer->next=node;
                        pointer->prev=node->prev;
                        if(node->prev)node->prev->next=pointer;
                        node->prev=pointer;
                        if(pointer->prev)return head;//если были предыдущие, то возвращаем начало списка
                        else return pointer;//если нету, то это стало головой
                }
    }
};
 
list *remove(list *head,list **now){
        list *ptr = NULL;
        // Если список пуст
        if(head == NULL){
          return NULL;
        }
        for(ptr=head;ptr;ptr=ptr->next)
        {
            if(*now == ptr)
            {
                ptr->next->prev = ptr->prev;
                ptr->prev->next = ptr->next;
                *now = ptr->next;
                if(ptr == head) head = head->next;
                return head;
            }
        return head;
        }
        
};
 
list *del(int poz,list *head,int posOrval=1,int all=0){
        list* node=head;
        // Если список пуст
        if(head == NULL){
                return NULL;
        }
        if(posOrval)//Если не 0, то удаляем позицию
        {       
                int i=0;
                while(i<poz&&node->next!=NULL)//идем до нужной позиции
                {
                        i++;
                        node=node->next;
                }
                if(node->next == NULL&&i!=poz){//если позиция больше чем количество элементов
                        return head;//тогда нечего удалять
                }
                else//если нашлось что удалить
                {
                        if(node->prev)node->prev->next=node->next;//ссылка предыдущего на следующий
                        else //удаляется первый элемент, потому нужно отдать ссылку на второй
                        {
                                list* temp=node->next;//временно запомним 2ой элемент
                                delete node;//так как здесь ссылка на него убивается
                                return temp;//отдадим его
                        }
                        if(node->next)node->next->prev=node->prev;//ссылка следующего на предыдущий
                        delete node;//удалили узел
                        return head;
                }
        }
        else//если нужно удалить по значению
        {
                int i=0;
                list* res=head;//заведем ссылочку что нужно отдать(на случай удаления 1го элемента)
                do //ну циклик по всем узлам
                {
                        if(node->data==poz&&node)//если совпало значение, то удаляем по позиции =)
                        {
                                node=del(i,res);
                                res=node;
                                if(!all)break;//если выбрано все удалять, то идем цикле, иначе выходим с него
                                i=-1;//-1, чтобы при прокрутке i снова стало 0, то есть мы всегда начинаем искать с начал, можно скопировать код такой-же как при удалении по позиции, но впадло
                        }
                        else
                        node=node->next;//если удалили то первый раз топать никуда ненадо
                        i++;
                } while (node);
                return res;//ну и вернем результат
        }
};
 
void printlist(list *first){
    list *ptr; //копируем начальный адрес
    for(ptr = first; ptr; ptr = ptr->next){
        cout << "->" << ptr->data;
    }
};
 
// Функции доступа к узлам
list *getFirst(list *head){
    return head;
};
 
list *getLast(list *head){
    list *ptr;
    if(head == NULL)
    {  
        return head; 
    }
    for(ptr=head;ptr;ptr=ptr->next)
    {
        if(ptr == NULL)
            return ptr->prev;
        
    }
};
 
list *current(list *now){
    return now;
};
 
list *next(list **now){
    list *ptr = (*now)->next;
    *now = ptr;
    return ptr;
};
 
list *prev(list **now){
    list *ptr = (*now)->prev;
    *now = ptr;
    return ptr;
};
 
list *last(list *head, list **now){
    list *ptr;
    if(head == NULL)
    {
        return NULL;
    }
    for(ptr=head;ptr;ptr=ptr->next)
    {
        if(ptr == NULL)
        *now = ptr->prev;
        return ptr->prev;
        
    }
};
 
list *first(list *head, list **now){
    *now = head;
    return head;
}
 
void printuzel(list *now){
    cout << now->data << " " << "\n";
};
 
int empty(list *head){
    if(head == NULL)
        return 1;
    else
        return 0;
};
 
int count(list *head){
    int i=0;
    list *ptr;
    if(head == NULL){
        return NULL;
    }
    for(ptr=head;ptr;ptr=ptr->next)
    {
       i++;
    }
    return i;
};
 
void WorkWithList(){
    // Переменная List не содержит адреса на начало списка
    // List должна содержать начальный адрес списка
    list *List = NULL;
    list *now = NULL; // Указатель на текущий узел
    int value,choice,poz;
    for(;;)
    {
    // Вспомагательное меню для работы со списком
    cout << "(1) Добавление узла в начало списка\n";
    cout << "(2) Добавление узла в конец списка\n";
    cout << "(3) Добавление узла в заданную позицию\n";
    cout << "(4) Удаление текущего узла\n";
    cout << "(5) Удаление заданного узла(по номеру или по значению)\n";
    cout << "(6) Функции доступа к узлам\n";
    cout << "(7) Функции перемещения по списку\n";
    cout << "(8) Общие функции\n";
    cin >> choice;
    switch(choice)
    {
        case 1:
            cout << "Введите число: ";
            cin >> value;
            // Добавить узел с новым значением в начало списка
            List = prepend(value,List,&now);
            printlist(List);
            break;
        case 2:
            cout << "Введите число: ";
            cin >> value;
            // Добавить узел с новым значением в конец списка
            List = append(value,List,&now);
            printlist(List);
            break;
        case 3:
            cout << "Введите число и позицию: ";
            cin >> value;
            cin >> poz;
            // Добавить узел в заданную позицию
            List = insert(value,poz,List,&now);
            printlist(List);
            break;
        case 4:
            cout << "Удаление текущего узла ";
            // Удаление текущего узла
            List = remove(List, &now);
            printlist(List);
            break;
        case 5:
            cout << "Удаление заданного узла ";
            // Удаление заданного узла (по номеру или по значению
            cin >> value;
            List = del(value,List);
            printlist(List);
            break;
        case 6:
            cout << "Функции доступа к узлам\n";
            cout << "Возвращает указатель на первый узел\n";
            cout << "Указатель на первый узел -->> " << getFirst(List) << "\n";
            printuzel(getFirst(List));
            cout << "Возвращает указатель на текущий узел\n";
            cout << "Указатель на текущий узел -->> " << current(now) << "\n";
            printuzel(current(now));
            cout << "Возвращает указатель на последний узел\n";
            cout << "Указатель на последний узел -->> " << getLast(List) << "\n";
            printuzel(getLast(List));
            break;
        case 7:
            cout << "Функции перемещения по списку\n";
            cout << "Возвращает указатель на следующий узел и делает его текущим узлом " << next(&now) << "\n";
            //printuzel(next(&now));
            cout << "Возвращает указатель на предыдущий узел и делает его текущим узлом " << prev(&now) << "\n";
            //printuzel(prev(&now));
            cout << "Возвращает указатель на последний узел и делает его текущим узлом " << last(List,&now) << "\n";
            //printuzel(last(List,&now));
            cout << "Возвращает указатель на первый узел и делает его текущим узлом " << first(List,&now) << "\n";
            //printuzel(first(List,&now));
            break;
        case 8:
            cout << "Общие функции\n";
            cout << "Если 1, то список пуст " << empty(List) << "\n";
            cout << "Количество узлов в списке = " << count(List) << "\n";
            break;
    }
    }
};
// <---------------------------------------->
struct stack {
    int num;
    stack *next;
};
 
// Функции для работы со стеком
stack *Push(int i,stack *top){
    stack *newstack = new stack;
    newstack->num = i;
    newstack->next = top;
    return newstack;
};
 
int Pop(stack **top){
    int num = (*top)->num;
    stack *p=(*top);
    (*top) = (*top)->next;
    delete p;
    return num;
};
 
int emptystack(stack *top){
    if(top == NULL)
        return 1;
    else
        return 0;
}
 
void Print_stack(stack *top){
    if(top == NULL) return;
    cout << top->num << " ";
    return Print_stack(top->next);
};
 
void WorkWithStack(){
    stack *stk = NULL;
    int fig,chislo;
    for(;;)
    {
    // Вспомагательное меню для работы со стеком
    cout << "(1) Добавить узел с новым значением в стек\n";
    cout << "(2) Удалить узел из стека и получить его значение\n";
    cout << "(3) Проверить - стек пуст?\n";
    cin >> fig;
    switch(fig)
    {
        case 1:
            cout << "Введите число: ";
            cin >> chislo;
            stk = Push(chislo,stk);
            Print_stack(stk);
            break;
        case 2:
            cout << "Удалить узел из стека --> ";
            cout << Pop(&stk) << "\n";
            Print_stack(stk);
            break;
        case 3:
            cout << "Проверить - стек пуст?\n";
            cout << "Если 1, то стек пуст: " << emptystack(stk) << "\n";
            break;
    }
    }
 
};
 
struct queue {
    int mynum;
    queue *next;
};
 
queue *enqueue(){
    // Добавляет узел с новым значением в хвост очереди
};
 
void WorkWithFlow(){
    int vvod;
    int vvodchisla;
    queue *Queue = NULL;
    for(;;)
    {
    // Вспомагательное меню для работы с очередью
    cout << "(1) Добавить узел с новым значением в хвост очереди\n";
    cout << "(2) Удалить узел из головы очереди и получить его значение\n";
    cout << "(3) Проверить - очередь пуста?\n";
    cin >> vvod;
    switch(vvod)
    {
      case 1:
        cout << "Добавление узла в хвост очереди\n";
        cout << "Введите число: ";
        cin >> vvodchisla;
        enqueue(vvodchisla,Queue);
        break;
      case 2:
        break;
      case 3:
        break;
    }
    }
}
 
int main(){
    setlocale(LC_ALL,"Russian");
    // Организация меню
    cout << "Введите число между 1 и 3: ";
    int number;
    cin >> number;
    switch(number)
    {
        case 1: WorkWithList();
        case 2: WorkWithStack();
        case 3: WorkWithFlow();
    }
    return 0;
}
Dexter
 Аватар для Dexter
284 / 144 / 16
Регистрация: 13.10.2009
Сообщений: 164
24.03.2011, 13:40     Двусвязные списки, не могу добавить узел с конца #15
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
list *remove(list *head,list **now){
    list *ptr = NULL;
    // Если список пуст
    if(head == NULL){
        return NULL;
    }
    for(ptr=head;ptr;ptr=ptr->next)
    {
        if(*now == ptr)
        {
            if(ptr->next)ptr->next->prev = ptr->prev;//Если у нас нету предыдущего, то была раньше ошибка
            if(ptr->prev)ptr->prev->next = ptr->next;//аналогично со следующим
            *now = ptr->next;
            if(ptr == head) head = head->next;
            return head;
        }
    }
    return head;//было в цикле, потому выходило сразу после первого значения
};
Virusolog
1 / 1 / 0
Регистрация: 22.11.2010
Сообщений: 32
26.03.2011, 12:27  [ТС]     Двусвязные списки, не могу добавить узел с конца #16
Декстер, спасибо тебе огромное за твою помощь!!!
Я смог доделать лабу по спискам, стекам и очередям.

Только,вот в программе не работают вот эти четыре маленькие функции
*** Функции перемещения по списку***:
next – возвращает указатель на следующий узел и делает его текущим узлом;
prev – возвращает указатель на предыдущий узел и делает его текущим узлом;
last – возвращает указатель на последний узел и делает его текущим узлом;
first – возвращает указатель на первый узел и делает его текущим

Вот весь код. Указанные выше функции почему то работают неправильно
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
#include <iostream>
using namespace std;
struct list {
    int data;
    list *next; // Содержит адрес области в памяти на следующий элемент
    list *prev; // Содержит адрес в области памяти на предыдущий элемент
};
// Функции для работы со списком
list *prepend(int val,list *head, list **now){
    // Создаем список, оператор new возвращает адрес выделенного фрагмента памяти
    list *pointer = new list; //выделение памяти для новой ячейки
    pointer->data = val; //запись данных в ячейку
    // Текущий узел
    *now = pointer;
    pointer->next = NULL; //инициализация нулем
    pointer->prev = NULL; //инициализация нулем
    // Если список пуст
    if(head == NULL){
      return pointer;
    }
    else {// Если в списке есть хотя бы одна ячейка
      pointer->next = head; //после этой ячейки должна идти бывшая первая
      head->prev = pointer;
      head = pointer; //началом списка делаем только что созданную ячейку
      return head;
    }
};
 
list *append(int val, list *head, list **now){
    list *prev,*ptr;
    // Добавить узел в конце списка
    list *pointer = new list;
    pointer->data = val;
    *now = pointer;
    pointer->next = NULL;
    pointer->prev = NULL;
    // Если список пуст
    if(head == NULL){
        return pointer;
    }
    else {
        // Есть начальный адрес списка и только что созданный
        // Нужно найти адрес для последнего узла
        for(prev = head, ptr = head->next; ptr; prev = ptr, ptr = ptr->next);
 
        if(ptr == NULL)
        {
           prev->next = pointer;
           pointer->prev = prev;
           return head;
 
        }
    }
};
 
list *insert(int val, int poz, list *head, list **now){
    list *pointer = new list;
    pointer->data = val;
    *now = pointer;
    pointer->next = NULL;
    pointer->prev = NULL;
    list *node=head;
    int i = 1;
    // Если список пуст
    if(head == NULL){
        return pointer;
    }
    else {
        // Если список не пуст, есть начальный адрес в памяти
        while(i<poz&&node->next!=NULL)//идем до нужной позиции
        {
                i++;
                node=node->next;
        }
                if(node->next == NULL&&i!=poz){//если позиция больше чем количество элементов
                        node->next=pointer;
                        pointer->prev=node;
                        return head;
                }
                else//если нужно вставить перед этим элементом
                {
                        pointer->next=node;
                        pointer->prev=node->prev;
                        if(node->prev)node->prev->next=pointer;
                        node->prev=pointer;
                        if(pointer->prev)return head;//если были предыдущие, то возвращаем начало списка
                        else return pointer;//если нету, то это стало головой
                }
    }
};
 
list *remove(list *head,list **now){
        list *ptr = NULL;
        // Если список пуст
        if(head == NULL){
                return NULL;
        }
        for(ptr=head;ptr;ptr=ptr->next)
        {
                if(*now == ptr)
                {
                        if(ptr->next)ptr->next->prev = ptr->prev;//Если у нас нету предыдущего, то была раньше ошибка
                        if(ptr->prev)ptr->prev->next = ptr->next;//аналогично со следующим
                        *now = ptr->next;
                        if(ptr == head) head = head->next;
                        return head;
                }
        }
        return head;//было в цикле, потому выходило сразу после первого значения
};
 
list *del(int poz,list *head,int posOrval=1,int all=0){
        list* node=head;
        // Если список пуст
        if(head == NULL){
                return NULL;
        }
        if(posOrval)//Если не 0, то удаляем позицию
        {       
                int i=0;
                while(i<poz&&node->next!=NULL)//идем до нужной позиции
                {
                        i++;
                        node=node->next;
                }
                if(node->next == NULL&&i!=poz){//если позиция больше чем количество элементов
                        return head;//тогда нечего удалять
                }
                else//если нашлось что удалить
                {
                        if(node->prev)node->prev->next=node->next;//ссылка предыдущего на следующий
                        else //удаляется первый элемент, потому нужно отдать ссылку на второй
                        {
                                list* temp=node->next;//временно запомним 2ой элемент
                                delete node;//так как здесь ссылка на него убивается
                                return temp;//отдадим его
                        }
                        if(node->next)node->next->prev=node->prev;//ссылка следующего на предыдущий
                        delete node;//удалили узел
                        return head;
                }
        }
        else//если нужно удалить по значению
        {
                int i=0;
                list* res=head;//заведем ссылочку что нужно отдать(на случай удаления 1го элемента)
                do //ну циклик по всем узлам
                {
                        if(node->data==poz&&node)//если совпало значение, то удаляем по позиции =)
                        {
                                node=del(i,res);
                                res=node;
                                if(!all)break;//если выбрано все удалять, то идем цикле, иначе выходим с него
                                i=-1;//-1, чтобы при прокрутке i снова стало 0, то есть мы всегда начинаем искать с начал, можно скопировать код такой-же как при удалении по позиции, но впадло
                        }
                        else
                        node=node->next;//если удалили то первый раз топать никуда ненадо
                        i++;
                } while (node);
                return res;//ну и вернем результат
        }
};
 
void printlist(list *first){
    list *ptr; //копируем начальный адрес
    for(ptr = first; ptr; ptr = ptr->next){
        cout << "->" << ptr->data;
    }
};
 
// Функции доступа к узлам
list *getFirst(list *head){
    return head;
};
 
list *getLast(list *head){
    list *ptr;
    if(head == NULL)
    {  
        return head; 
    }
    for(ptr=head;ptr;ptr=ptr->next)
    {
        if(ptr == NULL)
            return ptr->prev;
        
    }
};
 
list *current(list *now){
    return now;
};
 
list *next(list **now){
    list *ptr = (*now)->next;
    *now = ptr;
    return ptr;
};
 
list *prev(list **now){
    list *ptr = (*now)->prev;
    *now = ptr;
    return ptr;
};
 
list *last(list *head, list **now){
    list *ptr;
    if(head == NULL)
    {
        return NULL;
    }
    for(ptr=head;ptr;ptr=ptr->next)
    {
        if(ptr == NULL)
        *now = ptr->prev;
        return ptr->prev;
        
    }
};
 
list *first(list *head, list **now){
    *now = head;
    return head;
}
 
void printuzel(list *now){
    cout << now->data << " " << "\n";
};
 
int empty(list *head){
    if(head == NULL)
        return 1;
    else
        return 0;
};
 
int count(list *head){
    int i=0;
    list *ptr;
    if(head == NULL){
        return NULL;
    }
    for(ptr=head;ptr;ptr=ptr->next)
    {
       i++;
    }
    return i;
};
 
void WorkWithList(){
    // Переменная List не содержит адреса на начало списка
    // List должна содержать начальный адрес списка
    list *List = NULL;
    list *now = NULL; // Указатель на текущий узел
    int value,choice,poz;
    for(;;)
    {
    // Вспомагательное меню для работы со списком
    cout << "(1) Добавление узла в начало списка\n";
    cout << "(2) Добавление узла в конец списка\n";
    cout << "(3) Добавление узла в заданную позицию\n";
    cout << "(4) Удаление текущего узла\n";
    cout << "(5) Удаление заданного узла(по номеру или по значению)\n";
    cout << "(6) Функции доступа к узлам\n";
    cout << "(7) Функции перемещения по списку\n";
    cout << "(8) Общие функции\n";
    cin >> choice;
    switch(choice)
    {
        case 1:
            cout << "Введите число: ";
            cin >> value;
            // Добавить узел с новым значением в начало списка
            List = prepend(value,List,&now);
            printlist(List);
            break;
        case 2:
            cout << "Введите число: ";
            cin >> value;
            // Добавить узел с новым значением в конец списка
            List = append(value,List,&now);
            printlist(List);
            break;
        case 3:
            cout << "Введите число и позицию: ";
            cin >> value;
            cin >> poz;
            // Добавить узел в заданную позицию
            List = insert(value,poz,List,&now);
            printlist(List);
            break;
        case 4:
            cout << "Удаление текущего узла ";
            // Удаление текущего узла
            List = remove(List, &now);
            printlist(List);
            break;
        case 5:
            cout << "Удаление заданного узла ";
            // Удаление заданного узла (по номеру или по значению
            cin >> value;
            List = del(value,List);
            printlist(List);
            break;
        case 6:
            cout << "Функции доступа к узлам\n";
            cout << "Возвращает указатель на первый узел\n";
            cout << "Указатель на первый узел -->> " << getFirst(List) << "\n";
            printuzel(getFirst(List));
            cout << "Возвращает указатель на текущий узел\n";
            cout << "Указатель на текущий узел -->> " << current(now) << "\n";
            printuzel(current(now));
            cout << "Возвращает указатель на последний узел\n";
            cout << "Указатель на последний узел -->> " << getLast(List) << "\n";
            printuzel(getLast(List));
            break;
        case 7:
            cout << "Функции перемещения по списку\n";
            cout << "Возвращает указатель на следующий узел и делает его текущим узлом " << next(&now) << "\n";
            printuzel(next(&now));
            cout << "Возвращает указатель на предыдущий узел и делает его текущим узлом " << prev(&now) << "\n";
            printuzel(prev(&now));
            cout << "Возвращает указатель на последний узел и делает его текущим узлом " << last(List,&now) << "\n";
            printuzel(last(List,&now));
            cout << "Возвращает указатель на первый узел и делает его текущим узлом " << first(List,&now) << "\n";
            printuzel(first(List,&now));
            break;
        case 8:
            cout << "Общие функции\n";
            cout << "Если 1, то список пуст " << empty(List) << "\n";
            cout << "Количество узлов в списке = " << count(List) << "\n";
            break;
    }
    }
};
// <---------------------------------------->
struct stack {
    int num;
    stack *next;
};
 
// Функции для работы со стеком
stack *Push(int i,stack *top){
    stack *newstack = new stack;
    newstack->num = i;
    newstack->next = top;
    return newstack;
};
 
int Pop(stack **top){
    int num = (*top)->num;
    stack *p=(*top);
    (*top) = (*top)->next;
    delete p;
    return num;
};
 
int emptystack(stack *top){
    if(top == NULL)
        return 1;
    else
        return 0;
}
 
void Print_stack(stack *top){
    if(top == NULL) return;
    cout << top->num << " ";
    return Print_stack(top->next);
};
 
void WorkWithStack(){
    stack *stk = NULL;
    int fig,chislo;
    for(;;)
    {
    // Вспомагательное меню для работы со стеком
    cout << "(1) Добавить узел с новым значением в стек\n";
    cout << "(2) Удалить узел из стека и получить его значение\n";
    cout << "(3) Проверить - стек пуст?\n";
    cin >> fig;
    switch(fig)
    {
        case 1:
            cout << "Введите число: ";
            cin >> chislo;
            stk = Push(chislo,stk);
            Print_stack(stk);
            break;
        case 2:
            cout << "Удалить узел из стека --> ";
            cout << Pop(&stk) << "\n";
            Print_stack(stk);
            break;
        case 3:
            cout << "Проверить - стек пуст?\n";
            cout << "Если 1, то стек пуст: " << emptystack(stk) << "\n";
            break;
    }
    }
 
};
 
struct queue {
    int mynum;
    queue *next;
};
 
void Print_queue(queue *watch)
{
    if (watch==NULL) 
        return;
    cout << watch->mynum << " ";
    return Print_queue(watch->next);
};
 
void enqueue(int mynum, queue **watch){
    // РЕКУРСИЯ
    // Добавляет узел с новым значением в хвост очереди
    if ((*watch)==NULL)
    {
        (*watch)= new queue;
        (*watch)->mynum = mynum;
        (*watch)->next = NULL;
        return;
    }
    return enqueue(mynum,&(*watch)->next);
};
 
int dequeue(queue *watch){
    if (watch->next->next==NULL)
    {
        int mynum=watch->next->mynum;
        delete watch->next;
        watch->next=NULL;
        return mynum;
    }
    return dequeue(watch->next);
}
 
int emptyqueue(queue **rck){
  if ((*rck)==NULL)
    return 1;
  else
    return 0;
};
 
void WorkWithFlow(){
    int vvod;
    int vvodchisla;
    queue *Queue = NULL;
    for(;;)
    {
    // Вспомагательное меню для работы с очередью
    cout << "(1) Добавить узел с новым значением в хвост очереди\n";
    cout << "(2) Удалить узел из головы очереди и получить его значение\n";
    cout << "(3) Проверить - очередь пуста?\n";
    cin >> vvod;
    switch(vvod)
    {
      case 1:
        cout << "Добавление узла в хвост очереди\n";
        cout << "Введите число: ";
        cin >> vvodchisla;
        enqueue(vvodchisla,&Queue);
        Print_queue(Queue);
        break;
      case 2:
        cout << "Удаление узла из головы очереди и получение его значения --> ";
        cout << dequeue(Queue) << "\n";
        Print_queue(Queue);
        break;
      case 3:
        cout << "Если 1, то очередь пуста " << emptyqueue(&Queue) << "\n";
        Print_queue(Queue);
        break;
    }
    }
}
 
int main(){
    setlocale(LC_ALL,"Russian");
    // Организация меню
    cout << "Введите число между 1 и 3: ";
    int number;
    cin >> number;
    switch(number)
    {
        case 1: WorkWithList();
        case 2: WorkWithStack();
        case 3: WorkWithFlow();
    }
    return 0;
}
Посмотри, пожалуйста

Добавлено через 1 час 31 минуту
Я что-то не понимаю
Если мы делаем текущим узлом н-р следующий узел, то почему значение расположенное по адресу текущего узла не меняется?

Добавлено через 59 минут
При вызове пункта меню функции перемещения по списку - работа программы прекращается
и отладчик указывает что здесь данные NULL!
C++
1
2
3
void printuzel(list *now){
    cout << now->data << " " << "\n";
};
Добавлено через 2 часа 23 минуты
вроде должно работать, но увы

Добавлено через 19 часов 2 минуты
Не смог найти ошибку, подскажите, ребят пожалуйста - в какую сторону копать?
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
02.04.2011, 12:40     Двусвязные списки, не могу добавить узел с конца
Еще ссылки по теме:

Очереди и Двусвязные списки! C++
Двусвязные списки в с++ C++
Линейные двусвязные списки C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Virusolog
1 / 1 / 0
Регистрация: 22.11.2010
Сообщений: 32
02.04.2011, 12:40  [ТС]     Двусвязные списки, не могу добавить узел с конца #17
Да блин, снова вернулся к этому коду.
Не работают эти 4 функции, я уже изрядно устал искать ошибку
Yandex
Объявления
02.04.2011, 12:40     Двусвязные списки, не могу добавить узел с конца
Ответ Создать тему
Опции темы

Текущее время: 10:27. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru