За один просмотр выведем на экран и найдём количество отрицательных чисел в списке, созданном в 2.1.
В этом случае в начале списка есть фиктивный элемент. Так как он при просмотре не должен участвовать (фиктивный элемент не выводим и не анализируем), то переходим на второй элемент списка, то есть на первый реальный:
Q=P->next;
Напомним, что в переменной P находится адрес начала списка, то есть в нашем случае для первого списка адрес фиктивного элемента. Заметим, что при работе с обычным одномерным числовым массивом (не полем списка), объявленного, например, так:
const n=10; int a[n];
это соответствует заданию начального значения индекса одномерного массива, например: i=0;.
Как и при работе с одномерным массивом, цикл можно организовать разными способами.
Условие выхода из цикла можно записать так:
while (Q) …;,
или, что то же самое,
while (Q!=NULL)…;.
Цикл будет выполняться, пока в Q не поместим значение адресного поля последнего “правого” элемента списка, равное NULL, то есть пока не достигнем конца списка. При работе с массивом это частично напоминает оператор цикла while (i<n)…;.
|
|
Кроме такого цикла, как и при работе с массивом, можно записать цикл со счётчиком
for (int i=1; i<=n; i++)
где n —количество реальных (без фиктивного) элементов списка (в нашем примере целых чисел). Но в таком случае переменная (или константа) n должна быть объявлена как глобальная или передаваться в функцию просмотра как параметр. Кроме этого, при удалении или вставке элементов n должна быть только переменной и её надо не забыть изменить, сооответсвенно уменьшить или увеличить.
Можно использовать так называемый “вечный” цикл типа while (1), внутри которого записываем условие выхода из него и оператор break.
Внутри цикла используем информационную часть, в примере это одно число, которое обозначается Q->num. Если продолжить сравнение с одномерным массивом, то это чем то напоминает элемент списка a[i]. Для вывода на экран записываем
cout<<Q->num<<" ";.
Здесь же в цикле вместо вывода или вместе с ним может быть анализ одного или нескольких полей информационной части. Например, при работе с нашим списком для нахождения количества отрицательных чисел можно записать:
if (Q->num<0) count1++;
Для более сложного анализа одного числа из списка может понадобиться логическая функция, которая возвращает true или false, в зависимости от того, удовлетворяет ли число некоторому условию (например, является ли оно простым). Такую функцию можно составить и для нашей простой задачи:
bool Analis (int elem) {return elem<0;};
Обратим внимание на то, что из описания функции никак не видно, что она используется для работы с полем списка, то есть в ней нигде не используется ни Q->num, ни
|
|
Q->next->num. Это учитывается при вызове,который записываем, например, так:
if (Analis (Q-> num)) count1++;
Для перехода на следующий элемент списка необходимо выполнить оператор присваивания Q=Q->next;. Синтаксически он правильный, так как адрес элемента списка может находиться как в переменной Q, так и в адресном поле элемента списка (см. 1.1). С помощью этого оператора значение адресного поля (а там находится адрес следующего элемента) заносится в переменную-указатель Q. Если сравнивать с массивом, это равносильно увеличению индекса его элемента на единицу, то есть i++;. Заметим, что этот оператор продвижения по списку не зависит от информационной части его элемента.
Таким образом, с учётом сказанного вывод последовательности чисел первого списка при наличии в нём фиктивного элемента и определение количества отрицательных чисел в этом списке будет выглядеть следующим образом.
bool Analis (int elem) {return elem<0;};
void LOOK (int &count)
{
count=0;
Q=P->next; // Переход на первый реальный элемент списка
while (Q)
{ cout<<Q->num<<" "; // Вывод информационной части
if (Analis (Q->num)) count++; // Анализ информационной части
Q=Q->next; // Переход на следующий элемент
}
}