Сначала хотелось бы сказать пару слов о синтаксисе Паскаля.
Как следует понимать следующую запись? nxtP^.info.cnt?
Вспомним из чего состоит узел списка. Прежде всего из информационного поля, являющегося записью.
Доступ к полям записи ведётся через оператор . - точка.
То есть info.cnt - это нахождение значения счётчика внутри информационного контейнера.
Также в узле есть два связных поля prev и next.
Однако, прежде чем доступаться к значениям, мы должны сначала доступиться к самому узлу.
Вот как раз адрес самого узла и задаётся следующим образом nxtP^ - сам узел.
Так как узел сам является записью, то доступ к его информационному полю будет таким nxtP^.info
И соответственно погружаясь далее в поле счётчика в info записи получаем nxtP^.info.cnt
В программе нам может понадобиться подпрограмма поиска по числу в счётчике пунктов.
Вот она:
А вот набросок программы меню:Код:(*Поиск элемента в списке по данным. Если элемент не найден, то возвращается nil.*) function findNode(var A: listT; c: integer): linkT; var nxtP,resP: linkT; begin (* Инициализируем результат в nil *) resP := nil; (* Устанавливаем временный указатель на первый узел *) nxtP := A.first; (* Траверсируем вперёд, пока не закончился список *) while nxtP <> nil do begin (* Если данные счётчика достигли заданного знычения *) if nxtP^.info.cnt = c then begin (* Берём этот узел как результат и выходим из подпрограммы *) resP := nxtP; exit; end; (* Если пока не достигли траверсируем вперёд к концу списка *) nxtP := nxtP^.next; end; (* возвращаем связь узла результата *) findNode := resP; end;
Здесь оператор pos ищет первый пробел во временной строке items.Код:program menu; (* User types *) type infoT = record cnt: integer; dat: string; end; linkT = ^nodeT; nodeT = record info: infoT; next: linkT; prev: linkT; end; listT = record first: linkT; last: linkT; end; var (* Строка меню и временная строка пункты *) mStr,items: string; (* Procedures to work with list *) procedure initList(var L: listT); var nxtP, delP: linkT; begin if L.first = nil then Exit; nxtP := L.first; while nxtP <> nil do begin delP := nxtP; nxtP := nxtP^.next; Dispose(delP); end; L.first := nil; L.last := nil; end; procedure addNode(var L: listT; tmpP: linkT); begin if tmpP = nil then Exit; tmpP^.next := nil; tmpP^.prev := nil; if L.first = nil then begin L.first := tmpP; L.last := tmpP; end else begin L.last^.next := tmpP; tmpP^.prev := L.last; L.last := tmpP; end; end; (* Main program *) var list: listT; A: linkT; i: Integer; begin initList(list); clrscr; mStr := 'First Second Third Fourth Fifth'; i := 0; items := mStr+' '; while pos(' ', items) <> 0 do begin New(A); Inc(i); A^.info.cnt := i; A^.info.dat := copy(items,1,pos(' ', items)-1); items := delete(items,1,pos(' ', items)); AddNode(list, A); end; WriteLn; A := list.first; while A <> nil do begin Write(A^.info.cnt); Writeln('. '+A^.info.dat); A := A^.next; end; Writeln; end.
Позиция пробела без единицы и будет длиной первого пункта меню.
Именно это количество символов и заносится в поле dat созданного оператором New узла.
После чего первый пункт стирается из строки items вместе с пробелом.
Так как эти действия зациклены просматривается вся строка items до последнего пробела, который мы программно пришили к строке items. Также в цикле мы наращиваем поле счётчика, автоматически нумеруя пункты меню.
Вот результат:
Мне кажется, что алгоритм просто очарователен.
zen




Ответить с цитированием