Программа и учебные материалы элективного курса для

advertisement
Учебные материалы к элективным курсам по информатике для 10 - 11 классов, выпуск 1
Мендель Александр Васильевич
ПРОГРАММА И УЧЕБНЫЕ МАТЕРИАЛЫ ЭЛЕКТИВНОГО
КУРСА ПО ИНФОРМАТИКЕ ДЛЯ УЧАЩИХСЯ 10-11 КЛАССОВ
«ПОСТРОЕНИЕ СТРУКТУР ДАННЫХ С ПРИМЕНЕНИЕМ ДИНАМИЧЕСКИХ
ПЕРЕМЕННЫХ И УКАЗАТЕЛЕЙ»
ПОЯСНИТЕЛЬНАЯ ЗАПИСКА ................................................................................................................................................ 1
ТЕМАТИЧЕСКОЕ ПЛАНИРОВАНИЕ ...................................................................................................................................... 1
ТЕКСТ ПОСОБИЯ ................................................................................................................................................................. 2
ОПРЕДЕЛЕНИЕ ТИПОВ ДАННЫХ В TURBO-PASCAL ............................................................................................................ 2
ПРИМЕНЕНИЕ ДИНАМИЧЕСКИХ ПЕРЕМЕННЫХ И УКАЗАТЕЛЕЙ К ПОСТРОЕНИЮ СТРУКТУР ДАННЫХ .............................. 11
ЗАДАЧИ ............................................................................................................................................................................. 27
Пояснительная записка
Структуры данных, наряду с алгоритмами,
являются главными
составляющими компьютерных программ. Большое значение имеет оптимальное
конструирование структуры данных при реализации компьютерной модели решаемой
задачи. В курсе школьной информатики, как правило, рассматриваются статические
данные, однако в таких распространенных языках программирования как C и Pascal
имеются средства для создания динамических конструкций. Освоение способов
работы с динамическими данными позволяет строить и обрабатывать достаточно
сложные компьютерные модели, которые при этом, являются наглядными и
интуитивно понятными.
Основной задачей курса «Динамические данные и их применение к
решению задач программирования» является расширение и углубление знаний о
видах данных и способах управления ими в компьютерных программах. На примере
языка Turbo Pascal рассматриваются: динамические переменные и переменныеуказатели; некоторые структуры данных, реализуемые на их базе (одно и двусвязные
списки, стеки, очереди, двоичные деревья); алгоритмы обработки таких структур
данных; соответствующие задачи.
Программа рассчитана на учащихся имеющих навыки программирования языке
Pascal.
Объем курса: предлагаемый курс рассчитан на 20 часов
Тематическое планирование
№
п/п
1.
2.
3.
4.
5.
Темы занятий
Статические и динамические переменные. Переменныеуказатели в Turbo Pascal и их использование для работы с
динамическими переменными. Записи в Turbo Pascal.
Построение и обработка односвязных списков.
Решение задач на обработку односвязных списков.
Двусвязные списки.
Решение задач на обработку двусвязных списков.
Стеки и очереди, их реализация с использованием
динамических переменных и указателей.
Хабаровск, 2006 г.
Количество
часов
2
2
2
2
2
1
Учебные материалы к элективным курсам по информатике для 10 - 11 классов, выпуск 1
Решение задач на обработку стеков и очередей.
Двоичные деревья и алгоритмы их обработки.
Решение задач на обработку двоичных деревьев и задач
повышенной сложности
Итого
6.
7.
8.
2
4
4
20
Текст пособия
Определение типов данных в Turbo-Pascal
Стандартные простые типы данных в Turbo-Pascal
В Turbo-Pascal определены следующие основные стандартные простые типы
данных, с которыми связаны соответствующие зарезервированные слова.
Числовые
Символьные
Целый
- integer
Вещественный
- real
Байтовый
- byte
Литерный
- char
Строчный
- string
Логический
- boolean
Для каждого из перечисленных выше типов данных могут определяться
константы,
составляться
соответствующего
типа
выражения,
определяться
переменные.
Диапазоны значений для различных типов данных имеют ограничения. Integer
имеет диапазон значений от –MaxInt до MaxInt, где MaxInt – предопределенная
системой константа. Byte – 0..255. Char имеет значением один символ из таблицы
символов компьютера. String – цепочка символов длинной от 0 до 255 (строго говоря
– этот тип является структурным). Boolean имеет два значения - True (истина) и False
(ложь).
Для
перечисленных
выше
типов
данных
имеются
предопределенные
процедуры для операций ввода (кроме boolean) и вывода в текстовом виде.
Типы данных логический, целый, байтовый, литерный относятся к так
называемым перечисляемым типам, то есть таким для каждого значения которых
однозначно определены предыдущий и следующий элементы.
Раздел описаний
В Turbo-Pascal элементы, в отличие от стандартного Паскаля, могут
описываться в произвольном порядке.
Описанию элемента предшествует зарезервированное слово, указывающее его
Хабаровск, 2006 г.
2
Учебные материалы к элективным курсам по информатике для 10 - 11 классов, выпуск 1
вид. Затем следует описание элемента.
Метки
Константы
Типы
Переменные
Функции
Процедуры
Label
Const
Type
Var
Function
Procedure
Форматы описания элементов:
Метки
Label
<целое число1>[, <целое число2> и так далее];
Константы
Const
<идентификатор1>=<значение1>;
[<идентификатор2>=<значение2>;]
…………
Типы
Type
<идентификатор1>=<описание типа1>;
[<идентификатор2>=<описание типа2>;]
…………
Переменные
Var
<идентификатор11>[,<идентификатор12>, …]:<тип1>;
[<идентификатор12>[,<идентификатор22>, …]:<тип2>;]
…………
Приведем пример содержащий описания элементов некоторых типов
Program prim01;
Label
1,5;
Const
H=4.3;
Type
F=array [1..8] of real;
Var
A,b,c:integer;
X:f;
……………
Типы данных, определяемые пользователем
Язык Паскаль имеет мощные возможности для конструирования пользователем
собственных типов данных. Описание типов данных позволяет создавать такие
структуры данных, которые позволяют решать задачи оптимальными способами,
делают решение более наглядным, дают возможность установить соответствие между
Хабаровск, 2006 г.
3
Учебные материалы к элективным курсам по информатике для 10 - 11 классов, выпуск 1
структурами данных принятыми в теоретических исследованиях и реализованными в
программах.
В Паскале имеют место простые типы данных и сложные или структурные.
Сложные типы данных представляют собой набор компонентов связанных общим
именем и расположенных в смежной области памяти. Доступ к компонентам
производится с использованием индексной адресации, тогда как к простым типам
данных применяется прямая адресация1.
Основными типами структурных данных относятся массивы (array) и записи
(record).
Массивы
Массив является сложной переменной, представляющей собой связанный
общим именем набор элементов одного базового типа, доступ к компонентам которой
производится с использованием индексов.
Описание типа массив производится в разделе описаний и имеет следующий
формат.
Type
<имя типа>=array <диапазон индексов> of <имя базового типа>;
Диапазон индексов определяет количество измерений и набор значений
каждого из них. Диапазон индексов задается перечисляемым типом и является чаще
всего отрезком такого типа. Применение в качестве индексов отрезков типа Char или
определенного пользователем перечисляемого типа повышает наглядность и, в
некоторых случаях, упрощает программирование. Однако все реальные потребности
могут быть покрыты применением отрезков целого типа.
Пример
Type Ar1=array [1..20] of real;
Ar2=array ['a'..'z'] of integer;
Ar3=array [1..10,1..5] of integer;
Ar4=array [1..10] of ar1;
1
Различные способы адресации памяти будут рассмотрены ниже
Хабаровск, 2006 г.
4
Учебные материалы к элективным курсам по информатике для 10 - 11 классов, выпуск 1
Приведенный пример описывает типы одномерных массивов Ar1, Ar2,
двумерный массив Ar3 и массив Ar4, компонентами которого являются одномерные
массивы типа Ar1.
Описание переменных имеющих тип массив может выглядеть следующим
образом:
Var
A:ar1;
B:ar4;
C:ar3;
Доступ к компонентам массивов производится указанием в квадратных скобках
выражений, определяющих значение индекса.
Для приведенного выше примера
описания переменных возможны следующие способы указания индексов.
1.
A[1]:=3.5;
3.
B[5][4]:=A[3];
2.
B[6]:=A;
4.
C[2,4]:=10;
Для массива массивов возможны присваивания, приведенные во втором
примере.
Для массива имеющего в качестве базового сложный тип (B типа Ar4)
обращение к компонентам вложенного типа производится путем приписывание
справа дополнительных скобок с указанием индекса.
Пример
Program NF3;
nff1:=X
Type Ar=array[1..20] of real;
end;
Var
Begin
N,m:integer;
A:Ar;
Write('N=');
Function nff1(k:integer):real;
Var
Readln(N);
For m:=1 to N do
I:integer;
Begin
X:real;
A[m]:=nff1(m);
Begin
Writeln(A[m])
X:=1;
end
For I:=1 to k do
End.
X:=X*I;
Хабаровск, 2006 г.
5
Учебные материалы к элективным курсам по информатике для 10 - 11 классов, выпуск 1
Приведенный выше пример программы формирует и распечатывает
массив значений факториала.
Записи
Запись является сложной переменной, представляющей собой связанный
общим именем набор элементов различных базовых типов - полей, доступ к
компонентам которой производится с использованием имени поля.
Описание типа запись производится в разделе описаний и имеет следующий
формат.
Type
<имя типа>=record
<имя поля1>:<имя базового типа1>;
<имя поля2>:<имя базового типа2>;
<имя поля3>:<имя базового типа3>;
……………
end;
Правила
выбора
имени
поля
такие
же,
что
для
всех
остальных
идентификаторов.
Приведем пример описания типа запись и переменных такого типа, а так же
доступа к их компонентам.
Program prim;
a.name:='Сидоров';
Type
d[8].rost:=123;
Anket=record
d[3]:=a;
Name:string;
a.date:=12;
Rost:integer;
…………………..
Date:integer
end.
End;
Mass=array [1..20] of anket;
Var
A:anket;
D:mass;
Begin
…………………..
Хабаровск, 2006 г.
6
Учебные материалы к элективным курсам по информатике для 10 - 11 классов, выпуск 1
В приведенном примере описана запись, содержащая 3 поля и массив,
состоящий из таких же записей. Показаны правила обращения к компонентам
массива записей и записи.
Способы адресации данных
В электронных вычислительных машинах данные хранятся в памяти. Есть
различные виды памяти: постоянная (ПЗУ) и оперативная (ОЗУ), внутренняя и
внешняя, есть собственная память процессоров – регистры, кроме того, в
архитектуре современных процессоров присутствует КЭШ-память, используемая
для оптимизации выполнения вычислительных процессов. Существуют также и
разные способы обращения к данным, хранящимся в памяти: последовательный и
произвольный. Программисты, решая задачи, используют для размещения данных
те ресурсы, которые необходимы в каждом конкретном случае. Однако в любой
программе, есть данные, размещаемые в ОЗУ,
такими данными являются
переменные и константы.
Мы не будем рассматривать вопросы организации размещения в памяти
констант и доступа к ним, поскольку эти процессы определяются разработчиками
трансляторов, а не программистами. Рассмотрим, как организуется работа с
переменными.
В программах на языке программирования Паскаль переменные подлежат
обязательному описанию, при этом определяются имя (идентификатор) и тип
каждой переменной. В некоторых других языках программирования такое
описание (или декларирование) не являются обязательными, переменная может
быть введена в программу по мере необходимости, а тип ей либо будет назначен по
умолчанию, либо уточнен с помощью суффикса, приписанного после имени, либо
определен другим способом. Таким образом, любая переменная будут иметь имя и
тип.
Прямая адресация
Рассмотрим случай, когда переменная имеет простой тип. Тогда при
трансляции с именем переменной можно связать определенный адрес оперативной
памяти компьютера, а от ее типа будет зависеть, сколько ячеек памяти нужно
зарезервировать для размещения значения данных.
Хабаровск, 2006
7
Учебные материалы к элективным курсам по информатике для 10 - 11 классов, выпуск 1
В этом случае для работы с данными можно использовать команды
процессора поддерживающие прямую адресацию памяти.
Например, скопировать слово, хранящееся по адресу памяти, указанному в
регистре (1) процессора в область с адресом, указанным в регистре (2) процессора 2.
Заметим также, что этот способ можно применять и для оперирования с
переменными сложных (структурных) типов, размещаемых в памяти в тех случаях,
когда нужно оперировать всей сложной переменной, а не ее отдельными
компонентами. Таким образом, в Паскале, например, можно передать массив в
качестве аргумента процедуры или функции.
Итак, прямая адресация является самым простым и распространенным
способом организации доступа к данным в оперативной памяти компьютера.
Индексная адресация
Рассмотрим другой распространенный случай – необходимо организовать
доступ к компонентам переменной сложного (структурного) типа. К таким
переменным в Паскале относятся массивы и записи. Компоненты сложных
переменных размещаются в смежных областях памяти. С именем сложной
переменной можно связать начало области размещения компонентов – базовый
адрес. Место размещения конкретного компонента сложной переменной (элемента
массива или поля записи) можно определить, указав для него индексное смещение
от базового адреса. В этом случае можно использовать соответствующие
инструкции (команды) процессора, реализующие индексную адресацию.
Например, считать в регистр (1) процессора слово, расположенное по адресу,
вычисляемому по значению, указанному в регистре (2) процессора, с учетом
индексного смещения указанного в инструкции.
Приведенная ниже таблица иллюстрирует размещение в памяти массива A,
состоящего из элементов некоторого базового типа и записи Z, состоящей из полей
N, R, K.
Элемент
Смещение
Адрес памяти
A[1] 0*(длина
базового Начальный адрес A+0
типа)
A[2] 1*(длина
базового Начальный адрес A+длина базового типа
Для иллюстрации способов адресации памяти не будем обращаться к конкретным
типам процессоров и соответствующих им ассемблерам, вместо имен регистров будем
указывать номера в круглых скобках
2
Хабаровск, 2006
8
Учебные материалы к элективным курсам по информатике для 10 - 11 классов, выпуск 1
A[3]
……………
Z.N
Z.R
Z.K
В
типа)
2*(длина
базового Начальный адрес A+2*(длина базового
типа)
типа)
…………………………. …………………………….
0
Начальный адрес Z+0
длина N
Начальный адрес Z+длина N
длина N+длина R
Начальный адрес Z+длина N+длина R
Косвенная адресация
Паскале
применяются
различные
способы
передачи
параметров
процедурам и функциям. Это может быть передача значений, когда при вызове
процедуры или функции в памяти отводятся области для данных, используемых
этой структурой. В эти области записываются значения переменных, переданные
при вызове процедуры или функции. Другим способом передачи параметров
является передача переменных. При описании процедуры или функции перед
этими параметрами ставится слово var. При вызове процедуры или функции в этом
случае передаются адреса реальных параметров. В этом случае для обращения к
данным процессор должен прочитать их адрес, расположенный определенном
месте памяти, а затем обратиться к данным по этому адресу.
Рассмотрим пример. Фрагмент описания процедуры выглядит так:
Procedure primer (var C:integer);
Begin
………………
C:=11
end;
Вызов процедуры из программы осуществляется следующим образом:
……………………
B:=34;
primer(B);
writeln(B);
……………………
В этом случае будет напечатано число 11.
Приведенная ниже таблица иллюстрирует передачу переменной B
в
качестве фактического параметра процедуры вместо формального параметра C.
Адрес памяти
Значение в памяти
Комментарии
Адрес места хранения
адреса формальной
переменной С
Адрес
переменной B
Адрес переменной B,
переданной в качестве
фактического параметра
Хабаровск, 2006
9
Учебные материалы к элективным курсам по информатике для 10 - 11 классов, выпуск 1
…………………
………………….
……………………
Адрес
переменной B
34
Значение переменной B
до вызова процедуры primer
Значение переменной B
11
после выполнения
процедуры primer
В рассмотренном выше примере, показано, что имеют смысл такие
Адрес
переменной B
переменные, значением которых является адрес другой переменной. Такие
переменные указывают или ссылаются на другие переменные и соответственно
получили название указатели или ссылки.
Динамические переменные и указатели
Выше были описана работа с переменными, которые размещаются в памяти
компьютера при запуске программы, а так же при вызове процедуры или функции.
Они занимают память все время выполнения вычислительного процесса и не могут
быть созданы или уничтожены непосредственно в ходе вычислительного процесса.
Такие переменные называются статическим.
Кроме
статических
переменных в
Паскале
определены
так
же и
динамические, то есть такие, которые могут создаваться и уничтожаться
непосредственно в ходе вычислительного процесса.
Типы динамических переменных описываются таким же образом, как и
статических. Управление динамическими переменными и доступ к их компонентам
осуществляется посредством переменных специального типа – указателей.
Переменная типа указатель содержит информацию о размещение в памяти
динамической переменной, на которую она указывает. Кроме того, исполняющая
система устанавливает соответствие между указателем и типом переменной, на
которую он указывает и контролирует соблюдение этого соответствия в процессе
выполнения программы.
Динамическая
переменная
создается
специальной
процедурой
(new)
параметром которой является переменная типа указатель.
Описание переменной – указателя имеет следующий вид:
Type
Хабаровск, 2006
10
Учебные материалы к элективным курсам по информатике для 10 - 11 классов, выпуск 1
<имя типа - указателя>=^<имя типа - переменной>;
Пример
Type
Uk=^integer; {Описан указатель на динамическую переменную целого
типа}
Var
Dp:uk; {описана переменная – указатель}
Begin
New(Dp); {в памяти создана переменная целого типа и связана с
переменной – указателем}
Dp^:=30;
{динамической переменной присвоено значение}
Dp:=nil;
{переменная - указатель получила значение пустой
указатель, показывающее, что она не связана ни с какой переменной}
End.
Динамические переменные и указатели применяются для конструирования
различных структур данных. Чаще всего для этого используются типы данных,
определяемые пользователями на основе записей.
Применение динамических переменных и указателей к построению
структур данных
Связные списки
Связный список или просто список является линейной структурой данных,
состоящей
из
набора
однородных
(однотипных)
элементов.
Линейность
подразумевает, что элементы выстроены в линию (в ряд), каждый элемент списка
занимает определенное порядковое место и имеет не более двух соседей. В этом
случае для каждой пары соседних элементов должно быть определено, какой из
них является предыдущим, а какой следующим.
Реализация этой структуру данных требует, чтобы кроме информационных
полей элемент списка содержал также одно или несколько полей устанавливающих
связи с соседними элементами. Для конструирования таких типов данных в
Паскале применяют записи, часть полей которых являются информационными
(содержательными), а также имеются поля – указатели, используемые для задания
связей в списке.
Хабаровск, 2006
11
Учебные материалы к элективным курсам по информатике для 10 - 11 классов, выпуск 1
Количество полей – указателей определяется тем, сколько и каких связей
устанавливается между соседними элементами. Элемент списка может содержать
один указатель (только на следующий или только на предыдущий элемент), а
может содержать указатели на оба соседних элемента. Первые два варианта
соответствуют односвязным спискам, последний вариант – двусвязным.
Списки формируются из динамических переменных, которые являются их
элементами. Приведем пример описания односвязного списка и выполнения
некоторых действий с ним. Опишем типы данных:
Type
list=^element;
element=record
inf:string[20];
next:list
end;
Здесь тип list – является указателем на переменные типа element. Тип element
определяет структуру элемента списка, состоящую из информационного поля inf и
поля-указателя на следующий элемент next.
Опишем несколько статических переменных типа list, которые будем
использовать для того, чтобы зафиксировать первый и последний элементы, а
также как вспомогательные:
Var
a,b,c:list;
Создадим первый элемент списка и зафиксируем его переменной a – начало
списка, переменная b пусть указывает на конец списка:
new(a);
b:=a;
a^.inf:=’perviy’;
a^.next:=nil;
Последняя команда показывает, что элемент является последним, поскольку
указатель на следующий элемент – поле next, устанавливается пустым – nil.
Добавим к списку еще один элемент, следующий за первым:
new(b^.next);
Хабаровск, 2006
12
Учебные материалы к элективным курсам по информатике для 10 - 11 классов, выпуск 1
b:=b^.next;
b^.inf:=’vtoroy’;
b^.next:=nil;
Вторая команда в этой серии выполняет сдвиг указателя b на следующий
элемент списка (на него был установлен указатель текущего элемента).
Теперь вставим еще один элемент списка между первым и вторым, для этого
используем переменную c:
new(c);
c^.inf:=’poltora’;
c^.next:=a^.next;
a^.next:=c;
Здесь была создана новая динамическая переменная, присвоено значение ее
информационному полю, затем был установлен ее указатель на следующий
элемент и, наконец, указатель первого элемента передвинут на вновь созданный.
Добавим элемент в начало списка:
new(c);
c^.inf:=’nulevoy’;
c^.next:=a;
a:=c;
Таким образом, мы рассмотрели операции добавления элемента в начало и в
конец списка, а также вставку нового элемента между двумя соседними. Кроме
того, выяснили, что для движения по списку можно выполнять операции вида
b:=b^.next.
Хабаровск, 2006
13
Учебные материалы к элективным курсам по информатике для 10 - 11 классов, выпуск 1
a
‘perviy’
nil
b
Создание первого элемента
a
‘perviy’
b
‘vtoroy’
c
‘poltotra’
a
‘perviy’
b
‘vtoroy’
nil
Добавление элемента в конец списка
‘perviy’
nil
b
‘vtoroy’
a
‘poltotra’
c
Вставка элемента в середину
nil
‘nulevoy’
Добавление элемента в начало списка
Описанные выше структуру данных и операции над ней можно применить
при решении следующей задачи.
Задача 1. В текстовом файле содержатся значения вещественных чисел.
Сформировать и распечатать список этих значений в порядке их возрастания.
Решение. Будем формировать список из элементов, аналогичных описанным в
предыдущем примере. Поместим первое значение из файла в начало списка. Затем,
пока файл не закончился будем читать из него следующее значение и выполнять
действия в соответствии с условиями: Если первый элемент больше, чем
считанный, то поместим считанный элемент в начало списка. В противном случае
будем перемещаться по списку пока не найдем элемент больший, чем считанный
или не закончится список. Вставим новый элемент в найденную позицию.
Программа
Комментарии
program sortlist;
uses crt;
Type
Описание типов данных
list=^element;
element=record
Хабаровск, 2006
14
Учебные материалы к элективным курсам по информатике для 10 - 11 классов, выпуск 1
fn:real;
next:list
end;
Var
f:text;
Описание файловой переменной
a,b,c:list;
Описание переменных
n:real;
begin
clrscr;
Очистка экрана
assign(f,'infile1.txt');
Отождествление файловой переменной с
файлом
reset(f);
Открытие файла
readln(f,n);
Чтение первого значения
new(b);
Создание первого элемента списка
c:=b;
b^.next:=nil;
b^.fn:=n;
while not eof(f) do
Чтение данных пока файл не закончился
begin
readln(f,n);
b:=c;
b-установлен на начало списка
new(a);
Создание элемента для включения в список
a^.fn:=n;
if n>c^.fn then
Проверка позиции нового элемента
begin
a^.next:=b;
Добавление элемента в начало списка
c:=a
end
else
begin
while (b^.next^.fn>n)and(b^.next<>nil) Пока не найдена позиция или список не
do
кончился
b:=b^.next;
Двигаемся по списку
a^.next:=b^.next;
Вставляем новый элемент в найденную для
b^.next:=a
него позицию
Хабаровск, 2006
15
Учебные материалы к элективным курсам по информатике для 10 - 11 классов, выпуск 1
end
end;
b:=c;
b-установлен на начало списка
while b<>nil do
Пока список не закончился
begin
writeln(b^.fn:10:2);
Печатаем значение элемента
b:=b^.next
Переходим к следующему элементу
end
end.
Замкнутые списки
Списки можно применять для решения различных задач. Конечно, можно
использовать в качестве альтернативной структуры данных массив. Но когда дело
касается необходимости вставки элемента в середину такой структуры или же
исключения среднего элемента из массива, возникает необходимость смещения
других элементов, что требует затрат времени. Кроме того, на основе связных
списков можно строить и другие структуры данных. Рассмотрим еще одну задачу.
Задача 2. Круговая считалка. Во входном текстовом файле содержится список
имен участников игры, более 6 человек. Игроки становятся в круг. Ведущий
читает считалку, состоящую из 24 слов и на каждом 4 слове выводит игрока из
круга. Расчет продолжается со следующего игрока. Нужно напечатать имена
тех игроков, которые остались в круге.
Решение. Будем формировать список из элементов, аналогичных описанным в
предыдущей задаче. Поместим первое значение из файла в начало списка. Затем,
пока файл не закончился, будем читать из него следующее значение, и добавлять в
конец списка. После завершения данных в файле установим указатель последнего
элемента на первый элемент списка. Формирование структуры данных завершено.
Она будет выглядеть примерно, так как на рисунке. ‘Ваня’ был первым в файле, а
‘Алена’ – последней.
Хабаровск, 2006
16
Учебные материалы к элективным курсам по информатике для 10 - 11 классов, выпуск 1
‘Алена’
‘Ваня’
‘Антон’
b
‘Петя’
‘Лена’
c
‘Рома’
‘Вася’
‘Миша’
‘Юра’
Для обработки данных установим указатель b на первый элемент списка.
Организуем цикл «для», изменяя значение параметра i от 1 до 24. Если i будет
кратно 4, то исключим следующий элемент командой b^.next:=b^.next^.next, в
противном случае будем передвигать указатель b на следующего участника,
выполнив команду b:=b^.next. По завершению цикла «для» в замкнутом списке
останется на 6 элементов меньше чем было сначала.
‘Алена’
‘Антон’
‘Ваня’
c
‘Петя’
‘Лена’
b
‘Рома’
‘Вася’
‘Юра’
‘Миша’
Хабаровск, 2006
17
Учебные материалы к элективным курсам по информатике для 10 - 11 классов, выпуск 1
На рисунке ниже показано, как исключается из списка первый элемент –
‘Юра’. Для этого указатель элемента ‘Рома’ переставляется с ‘Юра’ на элемент
‘Миша’.
Распечатаем оставшиеся элементы. Очевидно, что нельзя использовать
указатель на первый элемент списка, который был установлен при начале его
формирования. Этот элемент мог быть исключен. Будем распечатывать имена
участников, начиная с того, на котором закончен расчет. Чтобы не ходить по кругу
предварительно установим указатель начала списка на участника, оказавшегося
последним при выполнении расчета. Ниже приведен текст программы для этой
задачи и комментарии к ней.
Программа
Комментарии
program ringlist;
uses crt;
type
list=^element;
Описание типа указателя на следующий
элемент
element=record
Описание типа динамических переменных
fn:string[20];
Информационное поле – имя
next:list
Поле – указатель на следующий элемент
end;
var
f:text;
Описание файловой переменной
b,c:list;
Описание статических указателей
n:string[20];
i:integer;
begin
clrscr;
assign(f,'infile2.txt');
Отождествление переменной с файлом
reset(f);
Открытие файла для чтения
readln(f,n);
Чтение первого значения
new(b);
Создание первого элемента списка
c:=b;
Указатель c устанавливается на начало
списка
Хабаровск, 2006
18
Учебные материалы к элективным курсам по информатике для 10 - 11 классов, выпуск 1
b^.fn:=n;
Присваивание значения элементу
while not eof(f) do
Пока файл не закончился
begin
readln(f,n);
Чтение следующего значения
new(b^.next);
Создание нового элемента
b:=b^.next;
Перемещение указателя b на новый элемент
b^.fn:=n;
Присваивание значения новому элементу
end;
b^.next:=c;
Замыкание списка в круг
b:=c;
Установка b на начало списка
for i:=1 to 24 do
Цикл «для»
begin
if i mod 4 =0 then
b^.next:=b^.next^.next
else b:=b^.next
Исключение 4 элемента
Смещение на следующий элемент
end;
Указатель c устанавливается на текущий
элемент
c:=b;
repeat
writeln(b^.fn);
Печать значения элемента списка
b:=b^.next
Перемещение на следующий элемент
until b=c
Проверка возвращения к началу списка
end.
Двусвязные списки
Кроме односвязных списков, можно строить также и двусвязные. В такой
структуре данных каждый элемент имеет указатели на оба соседних. То есть в
описании типа элемента добавляется еще одно поле. Например, описание может
выглядеть следующим образом:
Type
list=^element;
element=record
inf:string[20];
ukl,ukr:list
Хабаровск, 2006
19
Учебные материалы к элективным курсам по информатике для 10 - 11 классов, выпуск 1
end;
У первого элемента указатель ukl будет равен nil, а у последнего элемента
значение nil будет иметь указатель ukr.
Эту структуру даны можно применить, например, к решению задачи
«Считалка-маятник».
Стеки и очереди
Стек и очередь являются структурами данных, широко применяемыми в
стандартных алгоритмах, а также для построения моделей. Эти структуры также
как списки являются линейными и определения типов данных для них также
совпадают с теми, что применяются для односвязных списков.
Стек или магазин – линейная структура данных, имеющая одно «окно»,
применяемое для включения в него данных или «вталкивания» и для извлечения
данных или «выталкивания». Устройство стека похоже на устройство патронного
магазина для пистолета или автомата. Патроны (данные) вталкиваются в магазин
при его снаряжении и выталкиваются при перезарядке оружия. При этом первым
извлекается патрон, который был вставлен в магазин последним. Таким образом,
стек или магазин представляет собой такую структуру, в которой для данных
применяется правило «Последний вошел – первый вышел». По-английски это же
будет звучать «Last In – Fist Out» или LIFO.
В отличие от стека, очередь следует понимать в обычном бытовом смысле.
Очередь – это такая структура, в которой для данных применяется правило
«Первый вошел – первый вышел» или по-английски «First In – Fist Out»,
сокращенно FIFO. Элемент добавляется в хвост очереди, а извлекается из начала.
Рассмотрим простой пример, иллюстрирующий
применение стека для
вычислений. Пусть нужно вычислить N! – факториал числа N. По определению
1, N  0
N!  
. Для выполнения вычислений сначала поместим все
 N * ( N  1)!, N  0
значения N>0 в стек, а потом вычислим каждое промежуточное значение
факториала, умножая предыдущее значение на извлекаемый из стека множитель.
Хабаровск, 2006
20
Учебные материалы к элективным курсам по информатике для 10 - 11 классов, выпуск 1
Для работы с данными используем процедуры push – для проталкивания
значения в стек и pop – для выталкивания из стека.
Программа
Комментарии
program stekfactorial;
type
stek=^element;
Описание типа указателя на элемент стека
element=record
Описание типа элемента стека
fn:real;
Информационное поле
down:stek
Указатель на предыдущий элемент
end;
Var
b,c:stek;
Описание статических указателей, b – вершина стека
n,i:integer;
nf,g:real;
procedure pop(var x:real);
Процедура выталкивания значения из стека в
переменную x
Begin
c:=b;
Запомнили позицию верхнего элемента
x:=b^.fn;
Считали значение из стека
b:=b^.down;
Сместили указатель на следующий элемент в стеке
dispose(c);
Уничтожили извлеченный элемент
end;
procedure push(x:real);
Процедура помещения в стек значения x
Begin
new(c);
Создали новую переменную
c^.fn:=x;
Записали значение в новый элемент стека
c^.down:=b;
Установили указатель на предшествующий элемент
b:=c
Сдвинули указатель вершины стека
end;
Begin
readln(n);
Ввод значения переменной
i:=n;
b:=nil;
while i>=0 do
Хабаровск, 2006
Цикл «пока» для помещения значений в стек.
21
Учебные материалы к элективным курсам по информатике для 10 - 11 классов, выпуск 1
Begin
Поместить в стек 0!
if i=0 then push(1)
Проталкивание значения множителя
else push(i);
Переход к следующему значению
i:=i-1;
end;
pop(nf);
Выталкивание значения 0! в переменную nf
while b<>nil do
Пока стек не пуст
Begin
pop(g);
Выталкиваем значение множителя в переменную g
nf:=nf*g
Находим следующее значение факториала
end;
Печатаем значение результата
writeln(nf)
end.
Двоичные деревья
Двоичные деревья – это структуры данных, которые также как и списки,
стеки
и
очереди
широко
применяются
в
практике
решения
задач
программирования. Строго говоря, двоичные деревья являются одним из типов
ориентированных графов, не имеющих циклов, узлы которых связываются двумя
ребрами с двумя другими узлами графа.
Типичным примером двоичного дерева является генеалогическое дерево, в
котором узлом является человек, а ветви связывают его с его собственными
родителями. Получается структура: человек, затем его отец и мать, родители отца и
родители матери, родители родителей и так далее. Пример такого дерева приведен
на рисунке.
Ваня
Мама
Бабушка по маме
Папа
Дедушка по маме
Бабушка по папе
Дедушка по папе
Первый узел двоичного дерева называется корнем, а последние узлы, те из
которых нет ребер к следующим, называются вершинами двоичного дерева.
Хабаровск, 2006
22
Учебные материалы к элективным курсам по информатике для 10 - 11 классов, выпуск 1
Применение двоичных деревьев, не ограничивается генеалогией. К примеру,
рассмотрим арифметическое выражение 2*2+11/2. Это выражение определяет,
какие
действия
надо
выполнить
с
операндами,
а
правила
арифметики
устанавливают порядок их выполнения. Каждой операции соответствует два
операнда, а результат выполнения операции будет использован в качестве операнда
в следующем вычислении или окажется окончательным – равным значению
выражения. Для нашего выражения можно построить двоичное дерево аналогичное
генеалогическому:
+
*
2
/
11
2
2
По мере вычислений происходит преобразование (сокращение) дерева.
(3) 9,5=4+5,5
(1) 4=2*2
2
(2) 5,5=11/2
2
11
2
В скобках указан порядковый номер действия.
Описание данных для построения двоичного дерева практически совпадает
со случаем двусвязного списка. Рассмотрим следующую задачу.
Задача 3. Строкой задано арифметическое выражение, в записи которого
используются только операции сложения и умножения. Написать программу
вычисления значения этого выражения.
Решение. Задачу следует разбить на две части. Сначала построим двоичное дерево,
соответствующее выражению, затем произведем вычисление значения.
Для решения первой части опишем процедуру с параметрами – указателем
на узел и строкой, содержащей часть обрабатываемого выражения. В этой
процедуре будем выяснять, есть ли в обрабатываемом выражении символы
операций. Если операций нет, то значением узла станет строка, соответствующая
числу-операнду и узел станет вершиной дерева. Если в строке присутствуют знаки
операций, то один из них будет помещен в информационное поле узла. Затем будет
Хабаровск, 2006
23
Учебные материалы к элективным курсам по информатике для 10 - 11 классов, выпуск 1
создана пара новых узлов. Потом произойдет два рекурсивных вызова процедуры
параметрами которых будут правая и левая часть строки от знака операции и
соответствующие указатели на следующие левый и правый узел.
Для решения второй части задачи определим функцию, параметр которой
указатель на узел двоичного дерева. Если узел является вершиной, то в его
информационном поле хранится символьная запись числа, которое и станет
значение
функции.
Если
же
узел
является
промежуточным,
то
в
его
информационном поле хранится символ операции. В этом случае значение
функции будет вычисляться рекурсивно как сумма или разность функций,
вызванных с параметрами-указателями на следующие правый и левый узлы.
Программа, реализующая этот алгоритм, приведена ниже.
Программа
Комментарии
program plusminus;
type
ukaz=^uzel;
Описание типа указателя на узел дерева
uzel=record
Описание типа узла дерева
inf:string[16];
Информационное поле
ukl,ukr:ukaz
Указатели на левый и правый следующие
узлы
end;
var
a:ukaz;
Статическая переменная – указатель на
корень
s:string;
Входная строка
i:integer;
y:real;
procedure stroim(st:string; var u:ukaz);
Процедура построения дерева
var
i:integer;
begin
if (pos('-',st)=0)and(pos('+',st)=0) then
Если в строке нет символов операций
begin
u^.inf:=st;
Хабаровск, 2006
Информационное поле равно параметру st
24
Учебные материалы к элективным курсам по информатике для 10 - 11 классов, выпуск 1
u^.ukl:=nil;
Указатель на следующий nil – узел
является
u^.ukr:=nil
вершиной дерева
end
else
begin
i:=length(st);
Начиная с последнего символа
while (st[i]<>'+')and(st[i]<>'-') do
ищем знак операции
i:=i-1;
u^.inf:=st[i];
Знак операции в информационное поле
new(u^.ukl);
Новый левый узел
new(u^.ukr);
Новый правый узел
stroim(copy(st,1,i-1),u^.ukl);
Строим левую ветвь
stroim(copy(st,i+1,length(st)i),u^.ukr)
Строим правую ветвь
end
end;
function shet(u:ukaz):real;
Функция вычисления результата
begin
if u^.ukl=nil then
Если узел является вершиной
begin
val(u^.inf,y,i);
Преобразуем строку в число
shet:=y
Результат число
end
else
Иначе
case u^.inf[1] of
Если операция
'+': shet:=shet(u^.ukl)+shet(u^.ukr);
+, то результат сумма левого и правого
'-': shet:=shet(u^.ukl)-shet(u^.ukr)
-, то результат разность левого и правого
end
end;
begin
readln(s);
Вводим строку
new(a);
Создаем корень дерева
stroim(s,a);
Строим дерева
writeln(shet(a):15:5)
Печать значения функции
Хабаровск, 2006
25
Учебные материалы к элективным курсам по информатике для 10 - 11 классов, выпуск 1
end.
Файлы
По условиям олимпиадных задач, начиная с краевого тура, исходные и
выходные данные размещаются в текстовых файлах. Ниже приводятся основные
понятия, процедуры и функции для управления файлами.
Под файлом будем понимать специально организованную
специфицированную структуру данных на внешнем устройстве.
Для управления файлами определяются специальные переменные файлового
типа.
 Текстовые
<имя файловой переменной>:text;
 Типизированные
<имя файловой переменной>:file of <имя базового типа>;
 Не типизированные
<имя файловой переменной>:file;
 Отождествление файловой переменной с физическим файлом производится
процедурой
assign(<имя файловой переменной>,<спецификация файла>).
 Открытие файла производится процедурами
reset(<имя файловой переменной>) для чтения
rewrite(<имя файловой переменной>) для записи.
 Чтение данных из файла производится процедурами
read(<имя файловой переменной>,<список ввода>)
readln(<имя файловой переменной>,<список ввода>) – только для чтения
из текстового файла.
 Запись данных в файл производится процедурами
write(<имя файловой переменной>,<список вывода>)
writeln(<имя файловой переменной>,<список вывода>) – только для
записи в текстовый файл.
 Функция eof(<имя файловой переменной>) имеет значение "истина" если
достигается конец файла и "ложь" в противном случае.
 Закрытие файла производиться процедурой close(<имя файловой переменной>).
Общий порядок работы с файлами
Хабаровск, 2006
26
Учебные материалы к элективным курсам по информатике для 10 - 11 классов, выпуск 1
1. Если необходимо описывается нестандартный файловый тип.
2. Описываются переменные файлового типа.
3. Выполняется отождествление файловой переменной с физическим файлом
процедурой assign.
4. Файл открывается процедурами rewrite или reset для записи или для чтения
данных.
5. Выполняется чтение или запись данных в файл.
6. Файл закрывается процедурой close.
Задачи
1. Используйте алгоритм построения сортированного списка для решения
задачи сортировки файла с помощью трех лент.
2. Решите задачу – считалку. Параметры: входной файл содержит количество
слов считалки и список имен. Результат – список участников в порядке
выбывания.
3. Решите задачу о расстановке быков на корабле. Быков ставят в круг и
выбрасывают за борт каждого k-того. Входные данные: количество ваших
быков; количество чужих быков; количество быков, которых следует
выбросить за борт, число k. Результат: номера позиций, на
которые не
следует ставить ваших быков.
4. Напишите программу считалка-маятник. Используйте двусвязный список.
5. Напишите программу – калькулятор для вычисления выражений с
операциями умножения и деления.
6. Дополните программу калькулятор обработкой скобок, использованных при
составлении арифметических выражений.
7. Напишите программу – калькулятор, обрабатывающую арифметические
выражения, составленные с использованием всех знаков всех операций и
скобок.
Дополнительные задачи
Задача 1.
Даны чашечные весы и разновес, состоящий из N гирь. Вес каждой
гири Mi, i=1,2,..,N. На правой чаше весов установлен груз весом P. Найти такой
набор гирь, если он существует, который, при установке на левую чашу весов,
уравновешивал бы весы.
Хабаровск, 2006
27
Учебные материалы к элективным курсам по информатике для 10 - 11 классов, выпуск 1
Задача 2.
Пусть гири из разновеса можно устанавливать на обе чаши весов.
Необходимо найти наборы гирь из разновеса, которые при установке на правую
(где находится груз) и на левую (пустую) чаши весов приводили бы весы в
состояние равновесия.
Задача 3.
Напишите программу, которая бы печатала все возможные
разбиения множества из N элементов на K непересекающихся подмножеств.
Задача 4.
Даны две емкости A и B литров соответственно. Имеется
водопроводный кран и раковина (для выливания воды не на пол, а чтобы сухо
было). Можно переливать воду из одной емкости в другую и наоборот, наполнять
и опустошать каждую емкость. Необходимо найти такую последовательность,
если она есть, названных действий, не превышающую N операций, в результате
выполнения которой в одной из емкостей было бы отмерено ровно C литров.
Задача 5.
В пивном баре работает вороватый бармен, имеющий остатки
совести. Для получения "левого" дохода он разбавляет пиво. Однако совесть ему не
позволяет разбавлять пиво более чем на одну четверть. В баре имеются краны с
пивом и водой, раковина и две емкости (A и B миллилитров соответственно).
Написать программу, которая позволяет найти последовательность
переливаний для того чтобы отмерять в одной из емкостей С миллилитров пива
разбавленного не более чем на четверть, если это возможно менее чем за 10
операций. Ограничения: пиво в раковину выливать нельзя, разбавленное пиво
выливать обратно в бочку тоже нельзя. Если последовательность найти не
удалось, то выдавайте сообщение: "Лучше обсчитай!"
Задача 6.
В математическом ночном клубе проводится лотерея входных
билетов. Билет считается выигрышным, если сумма цифр его N - разрядного
номера является простым числом. Простое число такое, которое делится без
остатка только на 1 и на само себя. Найти номера всех выигрышных билетов.
Хабаровск, 2006
28
Related documents
Download