Широко известна
схема цикла «линейный поиск», которая имеет следующий вид:
Код:
Взять_первую_ситуацию;
WHILE ~ситуации_закончились & ~искомое_найдено DO Взять_следующую_ситуацию END;
IF ~ситуации_закончились THEN (* Искомое найдено *) END
При работе над проектом Oberon Vision (аналог Turbo Vision — библиотеки для создания псевдографического интерфейса пользователя) оказалось, что элементы меню, окна и прочее удобно организовывать в двунаправленные кольца (то есть двунаправленные списки, в которых первый и последний элементы также взаимно связаны).
Код:
TYPE Control* = POINTER TO ControlDesc;
ControlDesc* = RECORD
parent*: Control; (* Указатель на непосредственный родительский элемент *)
children*: Control; (* Указатель на первый дочерний элемент *)
prev*, next*: Control; (* Указатели на братские элементы для организации двунаправленного кольца *)
caption*: ARRAY 256 OF CHAR
END;
Одна из подзадач заключается в нахождении среди братских элементов (sibling elements), включая и сам элемент, элемента с определённым свойством. Например, необходимо найти элемент меню, у которого внутри строкового поля caption была бы определённая буква, перед которой стоит символ "&" (элемент "Save &As..." должен отреагировать на букву "A"). Это нужно для того, чтобы при нажатии на ту или иную клавишу, срабатывал соответствующий элемент меню.
У меня получился такой код:
Код:
PROCEDURE MenuKeyDown*(c: Control; key: G.Key);
VAR p: Control; (* Поиск осуществляется среди братских элементов 'c', включая его самого. *)
br: Control; (* Элемент-барьер *)
found: BOOLEAN;
BEGIN
...
p := c.prev;
br := p;
REPEAT
p := p.next;
found := MenuHotkey(p(Menu), CHR(key.sym))
UNTIL found OR (p = br);
IF found THEN
p.do.click(p)
END;
...
END MenuKeyDown;
Как видите, данный код не соответствует вышеупомянутой схеме линейного поиска. Как решить данную задачу более правильно?