Рекурсивная обработка списков1 Структуры и алгоритмы обработки данных, 1 Лекция 3 Рекурсивная обработка списков 1.Представление и реализация линейных списков 2.Иерархические (нелинейные) списки
Рекурсивная обработка списков2 Реализация линейных списков {Ссылочное представление в динамической памяти } type {El базовый тип элементов списка (описан в Global)} Link = ^ Node;{ссылка на звено в цепи} Node = record{звено цепи ( списка ): } Info: El;{ - содержимое (элемент списка) } Next: Link ;{ - ссылка на следующее звено } end {Node}; L_list = Link; {Л-список}
Рекурсивная обработка списков3 {1} function Null (x: L_list): Boolean; {список пуст} {2}function Head (x: L_list): El; {селектор «голова» списка; отказ, если x – пустой список} {3} function Tail (x: L_list): L_list; {селектор «хвост» списка; отказ, если x – пустой список} {4} function Cons (x: El; y: L_list): L_list; {конструктор; отказ, если исчерпана память} Реализация линейных списков
Рекурсивная обработка списков4 {1} function Null (x: L_list): Boolean; begin Null:= (x = nil); end {Null}; {2} function Head (x: L_list): El; begin if Null(x) then begin WriteLn; WriteLn(' ! Head(Nil) '); Halt; end else Head := x ^. Info; end {Head}; Реализация линейных списков
Рекурсивная обработка списков5 {3} function Tail (x: L_list): L_list; begin if Null(x) then begin WriteLn; WriteLn(' ! Tail(Nil) '); Halt; end else Tail := x ^. Next ; end {Tail}; Реализация линейных списков
Рекурсивная обработка списков6 {4} function Cons (x: El; y: L_list): L_list; var p : L_list; begin if MaxAvail >= SizeOf (Node) then begin New(p); p ^. Info := x; p ^. Next := y; Cons := p; end else begin WriteLn; WriteLn(' ! Исчерпана память '); Halt; end; end {Cons};
Рекурсивная обработка списков7 Замечание к реализации Cons Остается доступ к части нового списка через ссылку y. Ср. y := Cons (x, y); и z := Cons (x, y); x:x: y:y: p:p: Cons: г л аз г
Рекурсивная обработка списков8 Выполняются ли аксиомы для базовых функций при такой реализации? A3) Head(Cons(x, y)) = x; x:x: б Cons: б y:y: ро
Рекурсивная обработка списков9 A4) Tail(Cons(x, y)) = y; x:x: б Cons: б y:y: ро Tail: Пусть z := Tail(Cons(x, y)). Значения z и y совпадают.
Рекурсивная обработка списков10 A5) Cons(Head(z), Tail(z)) = z. Значения z и Cons не совпадают ! Списки z и Cons идентичны. Cons: б z:z: ро Tail: б б
Рекурсивная обработка списков11 Особенности реализации Concat(y, z) = if Null(y) then z else Cons(Head(y), Concat(Tail(y), z)). Пример Concat((a b), (c d)) = Cons(a, Concat((b), (c d))). Concat((b), (c d)) = Cons(b, Concat(Nil, (c d))). Concat(Nil, (c d)) = (c d). Concat((b), (c d)) = Cons(b, (c d)) = (b c d). Concat((a b), (c d)) = Cons(a, (b c d)) = (a b c d). Замечания: 1. Список y разбирается и затем собирается даже если список z пуст. 2. Функция Cons вызывается Size(y) раз.
Рекурсивная обработка списков12 Функция Concat на языке Паскаль function Concat (y, z: L_list): L_list; begin if Null (y) then Concat := z else Concat := Cons (Head (y), Concat (Tail (y), z)); end
Рекурсивная обработка списков13 Пример Concat((a b), (c d)) y:y: Concat: z:z: cd b a a b Concat с Copy a b Concat2: c d
Рекурсивная обработка списков14 Copy (x) if Null (x) then Nil else Cons (Head (x), Copy (Tail(x))); function Copy (x: L_list): L_list; begin if Null (x) then Copy := nil else Copy := Cons (Head (x), Copy (Tail(x))); end {Copy};
Рекурсивная обработка списков15 function Concat (y, z: L_list): L_list; begin if Null (y) then Concat := Copy (z) else Concat := Cons (Head (y), Concat (Tail (y), z)); end Функция Concat c Copy на языке Паскаль
Рекурсивная обработка списков16 Процедура Conc – аналог операции x := x y procedure Conc (var x : L_list; y: L_list); begin if Null (x) then x := y else Conc(x.Next, y); end Итерация if x = nil then x := y else begin q := x; while q.Next nil do q := q.Next ; q.Next := y end
Рекурсивная обработка списков17 Иерархические списки См. 1.7 в учебном пособии Рекурсивное определение типа данных S_expr (El), использующее данное ранее определение линейного списка (типа L_list): ::= |, ::=.
Рекурсивная обработка списков18 Примеры Полная записьСокращенная запись a Nil (a. (b. (c. Nil))) (a. ((b. (c. Nil)). (d. (e. Nil)))) a ( ) (a b c) (a (b c) d e) (a (b c) ( (d e (f) ) g) h)(a (b c) ( (d e (f) ) g) h)
Рекурсивная обработка списков19 Размеченное объединение множеств A = {1, 3, 5}; B = {2, 3, 4, 5}; A U B = {1, 2, 3, 4, 5}; A B = {1 A, 2 B, 3 A, 3 B, 4 B, 5 A, 5 B }; A B = {(1, A), (2, B), (3, A), (3, B), (4, B), (5, A), (5, B)}; (e, t) A B (e A) or (e B), t {a, b} t – tag (тэг, ярлык, этикетка) Если (e A),то t = a Если (e B), то t = b A B = (A {a}) U (B {b} ) ::=
Рекурсивная обработка списков20 Особенности реализации ::= |, ::=. ::= | ::= Nil ::= ::= (. ) ::= Сначала анализ: атом – список Затем: пустой список?
Рекурсивная обработка списков21 Представление type { El – базовый тип для атомов (описан в Global)} Ref_S_expr = ^ S_expr; {ссылка на S-выражение} S_expr = record { S-выражение:} case Tag: (Atomic, Pair) of Atomic: (Atm: El); {атомарное} Pair: (Hd, Tl: Ref_S_expr){пара} end {S_expr}; H_list = Ref_S_expr;{иерархический список} Итак, H_list это ссылка на S_expr. Пустой список – ссылка nil. Если H_list nil, тогда анализировать «атом – не атом».
Рекурсивная обработка списков22 Замечание к графическому изображению списка Более точным было бы изображение элемента списка с явным указанием поля тэга. : или Atomic Pair Atm: El Tl : Ref_S_expr Hd : Ref_S_expr Tag A A
Рекурсивная обработка списков23 aed cb Замечание к графическому изображению списка
Рекурсивная обработка списков24 Copy (x) if Null (x) then Nil else if Atom (x) then x else Cons (Copy ( Head (x)), Copy (Tail(x)) ); {8} function Copy (x: H_list): H_list; begin if Null (x) then Copy := nil else if Atom (x) then Copy := Make_Atom (x ^.Atm) else Copy := Cons (Copy (Head (x)), Copy (Tail(x))); end {Copy};
Рекурсивная обработка списков25 Процедура вывода списка с обрамляющими его скобками {4} procedure Write_H_list (S: H_list); begin {пустой список выводится как () } if Null (x) then Write(' ( ) ') else if Atom (x) then Write (' ', x ^. Atm) else {непустой список} begin Write (' ( '); Write_List (x); Write (' ) ') end; end {Write_H_list};
Рекурсивная обработка списков26 Процедура вывода списка без обрамляющих скобок {5} procedure Write_List (x: Ref_S_expr); begin if not Null (x) then begin Write_H_list (Head (x)); Write_List (Tail (x)) end; end {Write_List}
Рекурсивная обработка списков27 КОНЕЦ ЛЕКЦИИ