Динамические структуры данных — КиберПедия 

Общие условия выбора системы дренажа: Система дренажа выбирается в зависимости от характера защищаемого...

Поперечные профили набережных и береговой полосы: На городских территориях берегоукрепление проектируют с учетом технических и экономических требований, но особое значение придают эстетическим...

Динамические структуры данных

2017-06-02 302
Динамические структуры данных 0.00 из 5.00 0 оценок
Заказать работу

 

Рассмотрим построение программы, которая имеет дело с людьми, служащими в некоторой фирме. Структура данных для служащего может включать, например, имя, возраст, подразделение, оклад. Определим структуру данных для менеджера. Во-первых, менеджер является служащим, поэтому к нему относится та же структура данных. Во-вторых, к менеджеру относятся некоторые добавочные характеристики, например, список служащих, которые входят в его группу. В данном случае в памяти необходимо определить служащих, в том числе, и менеджера. Но память с данными для менеджера должна содержать ещё список подчинённых ему служащих. Очевидно, этот список должен просто ссылаться в памяти на адреса расположения информации о служащих, чтобы не повторять ещё раз данные о служащих. Таким образом, в данном случае необходимо использовать указатели для построения структур данных (динамических структур данных).

Среди динамических структур данных можно выделить линейные структуры (списки) и структуры-деревья, например, такие:

· однонаправленные списки;

· двунаправленные списки;

· стеки;

· очереди;

· бинарные деревья.

Динамические структуры обычно состоят из двух частей. Первая часть включает содержательную информацию, а вторая необходима для построения связей с другими элементами. Эти связи строят с помощью указателей.

 

ОДНОНАПРАВЛЕННЫЕ СПИСКИ

 

Структура однонаправленного связанного списка приводится на рис. 40. На этом рисунке принято, что содержательная часть состоит из текстовой информации (Info) в виде строки. Звёздочка представляет собой указатель, с помощью которого первый элемент связывается со вторым, второй – с третьим и т.д. Конец списка указывается с помощью пустого указателя nil. Построить такую структуру можно с помощью следующего объявления:

Type

PStroka = ^Stroka;

Stroka = record

Info:string;

Sled: PStroka;

End;

Здесь вначале объявлен типизированный указатель (PStroka) с базовым типом запись (Stroka), а затем сам базовый тип. Звёздочка на рис. 40 представляет указатель Sled, а Info – содержательную информацию. Следует обратить внимание, что синтаксически разрешается вначале объявлять указатель на несуществующий базовый тип, который обязательно далее должен быть объявлен.

 

Рис. 40 Структура однонаправленного списка.

Построим теперь список, например, из трёх элементов. Пусть переменные S1, S2, S3 содержат некоторую полезную информацию в виде строк, и пусть объявлены переменные:

Var Spisok, P:PStroka;

Переменная Spisok будет использована для хранения всего списка, а P – вспомогательный указатель. Напишем такой код для решения задачи:

New(Spisok); {Начало списка}

Spisok^.Info:=S1; {Запись строки S1 в список}

New(P); {Новый элемент списка}

P^.Info:=S2; {Запись строки S2 в элемент P}

Spisok^.Sled:=P; {Подключение элемента два в список}

New(P); {Третий элемент списка}

P^.Info:=S3; Запись строки S3 в элемент P}

Spisok^.Sled^.Sled:=P; {Подключение элемента 3 в список}

P^.sled:=nil; {Конец списка}

P:=nil; {Теперь указатель P не нужен}

В соответствии с этим кодом процесс формирования списка можно представить схематично так, как изображено на рис. 41.

Рис. 41 Схематичное представление этапов построения однонаправленного связанного списка.

Связанный список даёт варианты альтернативного представления массивов. Отличие заключается в том, что количество элементов в списке заранее неизвестно, но памяти под список выделяется (на этапе выполнения программы) ровно столько, сколько требуется для записи его элементов.

Основными операциями, которые выполняются при работе с динамическими структурами данных, являются:

· добавление элемента;

· исключение элемента;

· поиск заданного элемента.

 

ДВУНАПРАВЛЕННЫЕ СПИСКИ

 

Структура двунаправленного связанного списка приводится на рис. 42. Данная структура соответствует следующему объявлению: Type PStroka = ^Stroka;

Stroka = record

Info:string;

Pred,Sled: PStroka;

End;

Рис. 42 Структура двунаправленного списка.

Для построения связей между отдельными элементами списка используются два указателя: Pred – связь с предыдущим элементом и Sled – связь с последующим элементом. Соответственно имеет место ограничение связей элементов списка и слева и справа с помощью пустого указателя nil. Построим список из трёх элементов, как в предыдущем случае и при условиях предыдущей задачи.

New(Spisok); {Начало списка}

Spisok^.Info:=S1; {Запись строки S1 в список}

Spisok^.Pred:=nil; {Ограничение связей списка слева}

New(P); {Новый элемент списка}

P^.Info:=S2; {Запись строки S2 в элемент P}

P^.Pred:=Spisok; {Связь с предыдущим элементом}

Spisok^.Sled:=P; {Подключение элемента два в список}

New(P); {Третий элемент списка}

P^.Info:=S3; Запись строки S3 в элемент P}

P^.Pred:=Spisok^.Sled; {Связь с предыдущим элементом}

Spisok^.Sled^.Sled:=P; {Подключение элемента 3 в список}

P^.sled:=nil; {Конец списка}

P:=nil;

На основе двунаправленного списка возможно формирование кольцевых связанных списков, когда самый первый элемент списка ссылается на последний элемент, а последний – на первый элемент.

 

СТЕКИ, ОЧЕРЕДИ

 

Предполагается, что элементы в списках могут добавляться и извлекаться в произвольном порядке. Существуют списки с заранее заданными процедурами добавления и извлечения элементов. Это стеки и очереди. Очередью называется однонаправленный или двунаправленный связанный список с процедурой работы FIFO – First In, First Out (первым пришёл, первым ушёл). В списках типа очередь элемент добавляется в конец списка, а извлекается из начала списка. Стек – связанный список с процедурой работы LIFO – Last In, First Out (последним пришёл, первым ушёл). Элементы стека добавляются в конец списка и извлекаются из конца списка.

Идентифицируется очередь с помощью двух указателей: запоминается начало очереди и конец списка. Стек можно идентифицировать одним указателем, помечая дно стека с помощью nil.

 

БИНАРНЫЕ ДЕРЕВЬЯ

 

Содержательную информацию часто требуется как-то ранжировать. С целью ранжирования информации вводится понятие ключа. Например, в шахматных программах очередные ходы помечают с помощью числовых критериев оценки текущей позиции. Одним из способов представления ранжированной информации является бинарное дерево.

Бинарное дерево, по определению, - это иерархическая структура, схематично представляемая, например так, как на рис. 43.

Рис. 43. Структура бинарного дерева.

Бинарное дерево имеет узлы, в которые может входить одна ветвь, а выходить не более двух (бинарное). Верхняя вершина не имеет входа и называется корнем. Построить бинарное дерево можно следующим образом. Пусть имеется набор числовых оценок для некоторого ключа, например, такой: 35, 86, 49, 27, 31, 56, 62, 44, 29, 26, 33, 88. Примем, что вправо по ходу дерева, начиная от корня, значение ключа увеличивается, а влево – уменьшается. Тогда получим структуру дерева, представленную на рис. 43. Структуру бинарного дерева синтаксически можно объявить следующим образом:

Type

PDerevo=^Derevo;

Derevo=record

Key:word;

Info: string;

Left,Right: Pderevo;

End;

В заключение рассмотрим такую задачу. Пусть требуется построить очередь для данных, содержащихся в текстовом файле A.txt. Можно записать:

Program Prim;

Type PStroka = ^Stroka;

Stroka = record

Info:string;

Sled: PStroka;

End;

Var T:TextFile;

P,Pbegin,Pend:PStroka;

S:string;

Begin

New(Pbegin);

Pend:=Pbegin;

P:=Pbegin;

AssignFile(T,’A.txt’);

Reset(T);

While not eof(T) do begin

Readln(T,S);

P^.Info:=S;

Pend^.Sled:=P;

Pend:=P;

New(P);

End;

Pend^.sled:=nil;

Dispose(P);

CloseFile(T);

End.

Здесь указаталь Pbegin является идентификатором начала очереди, поэтому ему ещё до начала цикла выделяется память. Указатель Pend необходим для запоминания последнего элемента очереди. Вспомогательный указатель P позволяет обеспечить циклические вычисления. Цикл построен так, что указатель Pend постоянно продвигается по списку, обеспечивая добавление очередного элемента в конец очереди.

 

ПРИМЕР 19

 

Среда Delphi содержит встроенный класс TList, с помощью которого можно создавать однонаправленные списки. Этот класс предназначен для организации списка указателей на размещенные в адресном пространстве какие-либо структуры данных и обеспечивает эффективную работу с элементами списка. Доступ к отдельному элементу списка осуществляется посредством индексированного свойства Items[Index]. Нумерация элементов начинается с нуля. Элементы списка можно добавлять в конец списка с помощью метода Add или в середину, используя метод Insert. Можно реализовать сортировку элементов с помощью метода Sort. Однако, так как заранее состав структуры, на которую указывают указатели списка неизвестен, необходимо методу Sort передавать адрес разрабатываемой программистом процедуры попарного сравнения каких-либо полей, входящих в состав структуры отдельного элемента списка. Список создается посредством стандартного конструктора Create. Соответственоо необходимо обеспечить его удаление в приложении с помощью деструктора Free.

В примере 19 реализуется запись в список TList некоторой структуры данных, представляющей собой следующий тип (Type), используемый для рисования окружностей:

PMyList = ^AList;

AList = record

numP: Integer;

xP,yP:integer;

r:integer;

Col: TColor;

end;

Здесь numP - номер окружности, xP,yP - координаты центра окружности, r - радиус, Col - цвет.

Интерфейс и возможности приложения можно увидеть, изучая вариант решения данного примера (рис. 44). Окружности рисуются, используя обработчик Image1MouseDown.

 

Рис. 44. Вариант решения примера 19.

Данное приложение состоит из трех модулей: основная форма, вспомогательная форма для ввода цвета рисования и третья форма служит для поиска и рисования заданного элемента. Ниже приводится текст программы основного модуля.

unit UnitList;

Interface

uses Windows, Messages, SysUtils, Variants, Classes,

Graphics, Controls, Forms,

Dialogs, StdCtrls, ExtCtrls, Buttons,UnitSearch;

Type

TForm1 = class(TForm)

Edit1: TEdit;

Label1: TLabel;

Label2: TLabel;

Image1: TImage;

Button1: TButton;

Bevel1: TBevel;

Button2: TButton;

Button3: TButton;

BitBtn1: TBitBtn;

Bevel2: TBevel;

Button4: TButton;

procedure FormCreate (Sender: TObject);

procedure FormClose (Sender: TObject;

var Action: TCloseAction);

procedure Edit1KeyPress (Sender: TObject;

var Key: Char);

procedure Image1MouseDown (Sender: TObject; Button:

TMouseButton; Shift: TShiftState; X, Y: Integer);

procedure Button1Click (Sender: TObject);

procedure Button2Click (Sender: TObject);

procedure Button3Click (Sender: TObject);

procedure Button4Click (Sender: TObject);

public

MyList: TList;

end;

PMyList = ^AList;

AList = record

numP: Integer;

xP,yP:integer;

r:integer;

Col: TColor;

end;

var Form1: TForm1;

ARecord: PMyList;

kZap:integer=0;

Implementation

uses UnitColor;

{$R *.dfm}

procedure TForm1.FormCreate (Sender: TObject);

begin

MyList:= TList.Create;

Image1.Canvas.Pen.Width:= 2;

end;

procedure TForm1.FormClose (Sender: TObject;

var Action: TCloseAction);

begin

Dispose(ARecord);

MyList.Free;

end;

procedure TForm1.Edit1KeyPress (Sender: TObject;

var Key: Char);

begin

if not (key in ['0'..'9',#8]) then key:=#0;

end;

procedure TForm1.Image1MouseDown (Sender: TObject;

Button: TMouseButton; Shift: TShiftState;

X, Y: Integer);

begin

New(ARecord);

ARecord^.xP:= x;

ARecord^.yP:= y;

if length(Edit1.Text)=0 then Edit1.Text:='0';

ARecord^.R:= StrToInt(Edit1.Text);

inc(kZap);

ARecord^.numP:=kZap;

Form2.ShowModal;

ARecord^.Col:=Form2.NewColor;

MyList.Add(ARecord);

with Image1.Canvas, ARecord^ do begin

Pen.Color:= ARecord^.Col;

Ellipse (xP - R, yP - R, xP + R, yP + R);

TextOut(xP-Font.Size div 2,

yP+Font.Height div 2, IntToStr(numP));

end;

end;

procedure TForm1.Button1Click (Sender: TObject);

begin

Image1.Canvas.Brush.Color:=clWhite;

Image1.Canvas.Rectangle(0,0,

Image1.Width,Image1.Height);

end;

function CompareX (Item1, Item2: Pointer): Integer;

begin

Result:=PMyList(Item1)^.xP-PMyList(Item2)^.xP;

end;

procedure TForm1.Button2Click(Sender: TObject);

var i:integer;

begin

MyList.Sort(@CompareX);

for i:= 0 to (MyList.Count - 1) do begin

ARecord:=MyList.Items[i];

ARecord^.numP:=i+1;

end;

end;

procedure TForm1.Button3Click(Sender: TObject);

var i:integer;

begin

for i:= 0 to (MyList.Count - 1) do begin

ARecord:= MyList.Items[i];

with Image1.Canvas, ARecord^ do begin

Pen.Color:= Col;

Ellipse (xP - R, yP - R, xP + R, yP + R);

TextOut(xP-Font.Size div 2,

yP+Font.Height div 2, IntToStr(numP));

end;

end;

end;

procedure TForm1.Button4Click(Sender: TObject);

begin

Form3.Show;

end;

End.

В основном модуле строится список, который может быть отсортирован по координате xP. Все элементы отсортированного списка вновь нумеруются в соответствии с увеличением значений координаты xP. Далее приводится программный код второго модуля. В этом модуле используется новый компонент TColorBox, который обеспечивает ввод требуемого цвета.

unit UnitColor;

Interface

uses Windows, Messages, SysUtils, Variants, Classes,

Graphics, Controls, Forms,

Dialogs, StdCtrls, Buttons, ExtCtrls;

Type

TForm2 = class(TForm)

ColorBox1: TColorBox;

Label1: TLabel;

procedure ColorBox1Change(Sender: TObject);

public

NewColor:TColor;

end;

var Form2: TForm2;

Implementation

{$R *.dfm}

procedure TForm2.ColorBox1Change (Sender: TObject);

begin

NewColor:=ColorBox1.Selected;

close;

end;

End.

Интерфейс второй формы представлен на рис. 45. После выбора цвета осуществляется автоматический возврат в основную форму.

Рис. 45. Форма 2 к примеру 19.

Программный код третьего модуля приводится ниже.

unit UnitSearch;

Interface

uses Windows, Messages, SysUtils, Variants, Classes,

Graphics, Controls, Forms,

Dialogs, StdCtrls, Buttons, ExtCtrls;

Type

TForm3 = class(TForm)

Label1: TLabel;

Edit1: TEdit;

BitBtn1: TBitBtn;

Button1: TButton;

Bevel1: TBevel;

Bevel2: TBevel;

procedure Edit1KeyPress (Sender: TObject;

var Key: Char);

procedure Button1Click (Sender: TObject);

end;

var Form3: TForm3;

Implementation

uses UnitList, UnitColor;

{$R *.dfm}

procedure TForm3.Edit1KeyPress (Sender: TObject;

var Key: Char);

begin

if length(Edit1.Text)=0 then Edit1.Text:='0';

if not (key in ['0'..'9',#8]) then key:=#0;

end;

procedure TForm3.Button1Click (Sender: TObject);

var k,i:integer;

begin

if length(Edit1.Text)=0 then Edit1.Text:='0';

k:=StrToInt(Edit1.Text);

if (k = 0) or (k > kZap) then begin

ShowMessage(

'Неверно задан номер точки');

exit;

end;

for i:= 0 to (Form1.MyList.Count - 1) do begin

ARecord:= Form1.MyList.Items[i];

if ARecord^.numP=k then begin

with Canvas, ARecord^ do begin

Pen.Color:= Col;

Ellipse (xP - R, yP - R, xP + R, yP + R);

TextOut(xP-Font.Size div 2,

yP+Font.Height div 2, IntToStr(numP));

end;

break;

end;

end;

end;

End.

В данном модуле предусмотрено рисование окружности не на элементе Image, а непосредственно на канве формы, которая представлена на рис. 46.

 

Рис. 46. Форма 3 к примеру 19.

Модуль UnitSearch позволяет организовать поиск заданного элемента в сформированном связанном списке.

В данном проекте необходимо обратить внимание, как происходит работа, если приложение состоит из нескольких форм. Обычно имеется главная и вспомогательные формы. Вызов других форм организуются с помощью кнопок или меню посредством метода Show (активная форма) или ShowModal (неактивная форма). Например, в данной программе выше используются следующие вызовы других форм: Form2.ShowModal, Form3.Show.

 

ПРОЦЕДУРНЫЙ ТИП

 

Выше рассматривались указатели, которые позволяли работать с переменными. Однако есть указатели, обеспечивающие работу с процедурами и функциями. Такие указатели представляют собой ссылки на адреса расположения подпрограмм и являются переменными процедурного типа. Объявляется процедурный тип следующим образом:

Type P1:Procedure; P2:Procedure(var X,Y:real);

P3:Function(X:integer):double;

Var Q2:P2; Q3:P3;

Далее в программе может быть объявлено несколько функций с одним параметром, как указано в P3, например:

Function Sum(X:integer):double;

Funcnion Mult(X:integer):double;

Можно записать следующие операторы:

Q3:=Sum; Y:=Q3(8); Q3:=Mult; Y:=Q3(Z); Q2:=nil;

В качестве значения переменной процедурного типа не могут использоваться стандартные подпрограммы из модуля System.

Процедурный тип используется очень широко при описании событий в классах, в которых он представляет указатели на методы.

ПРОГРАММНЫЕ ЕДИНИЦЫ DLL

 

DLL означает Dynamic Link Library (динамически компонуемая библиотека). DLL – это библиотеки, подключаемые к другим программным единицам во время их выполнения. Удобство их состоит в том, что ресурсы библиотек могут использоваться одновременно несколькими программами. Применение DLL не зависит от языка, на котором она написана. DLL составляют основу архитектуры Windows. Модель программирования на основе DLL позволяет добиться модульности всех элементов системы, а модульность операционной системы – предоставить программисту более динамичный и открытый интерфейс.

Dll формируются и компилируются, независимо от использующих их программ, в которых будут только обращения к подпрограммам библиотек. В отличие от модуля Unit, Dll может передавать другим программным единицам только подпрограммы, хотя сама может иметь практически те же элементы, что и, например, программа-проект.

Заголовок DLL состоит из зарезервированного слова Library и имени библиотеки. Имя библиотеки совпадает с именем файла, в который записывается её программный код. Раздел экспортирования начинается с зарезервированного слова Exports. Секция инициализации начинается с ключевого слова begin, а заканчивается end с точкой. Назначение её такое же, как у аналогичной секции модуля Unit. Эта секция может отсутствовать. Остальные разделы могут присутствовать в любом количестве, как и в других программных единицах.

При создании Dll необходимо в репозитории выбрать соответствующий пункт (рис. 6). Правила написания этой программной единицы такие же, что и у программы-проекта. Отдельные части библиотеки можно поместить в модули. Основное отличие заключается в разделе экспортирования. Только подпрограммы, объявленные в этом разделе, могут быть использованы другими программными единицами.

Экспортируемые подпрограммы должны иметь внутреннее в DLL имя и могут иметь необязательное внешнее имя, которое используется как альтернатива при импортировании, например, Exports Subroutine1 name AddC, Subroutine2;

 

ПРИМЕР 20

 

Пусть требуется построить библиотеку подпрограмм работы с комплексными числами и выполнить, например, сложение двух комплексных чисел, используя эту библиотеку. Пусть в библиотеке будет содержаться пока одна функция сложения двух чисел.

Так как необходимо ввести новый тип, декларация которого требуется в двух программных единицах (основной модуль, библиотека), создадим дополнительный модуль DeclComplex, содержащий только одно объявление типа. Данный пример дополним ещё одной формой, в которой представим сведения о программе (рис. 48). Основную форму для этого примера можно представить так, как изображено на рис. 47.

 

Рис. 47 Форма примера 20.

Рис. 48 Дополнительная форма примера 20.

При разработке данного приложения вначале необходимо построить библиотеку. Затем необходимо создать проект с формой рис. 47. Далее последовательно добавить в этот проект модуль с формой рис 48 и модуль с объявлением типа Complex.

Ниже приводятся тексты кодов используемых программных единиц.

unit prim20; {Модуль с основной формой.}

Interface

uses Windows, Messages, SysUtils, Classes, Graphics,

Controls, Forms, Dialogs, StdCtrls, Buttons,

ExtCtrls, Menus, DeclComplex, About;

Type

TMainForm = class(TForm)

Bevel1: TBevel;

Bevel2: TBevel;

Edit1: TEdit;

Label1: TLabel;

Edit2: TEdit;

Label2: TLabel;

Label4: TLabel;

Edit5: TEdit;

Edit6: TEdit;

Edit3: TEdit;

Edit4: TEdit;

Label3: TLabel;

Label5: TLabel;

Label6: TLabel;

Label7: TLabel;

Label8: TLabel;

Label9: TLabel;

Label10: TLabel;

Label11: TLabel;

MainMenu1: TMainMenu;

Calc: TMenuItem;

About: TMenuItem;

ExitPoint: TMenuItem;

Input: TMenuItem;

procedure Edit1KeyPress (Sender: TObject;

var Key: Char);

procedure CalcClick (Sender: TObject);

procedure ExitPointClick (Sender: TObject);

procedure InputClick (Sender: TObject);

procedure AboutClick (Sender: TObject);

end;

var MainForm: TMainForm;

Function AddC(X,Y:Complex):Complex;

external 'MyDLL.dll';

Implementation

{$R *.DFM}

procedure TMainForm.Edit1KeyPress

(Sender: TObject; var Key: Char);

begin

if not (key in ['0'..'9','-',#8]) then key:=#0;

end;

procedure TMainForm.CalcClick(Sender: TObject);

var X,Y,Z:Complex;

begin

X.Re:=StrToInt(Edit1.Text);

X.Im:=StrToInt(Edit2.Text);

Y.Re:=StrToInt(Edit3.Text);

Y.Im:=StrToInt(Edit4.Text);

Z:=AddC(X,Y);

Edit5.Text:= FormatFloat('0.00',Z.Re);

Edit6.Text:= FormatFloat('0.00',Z.Im);

end;

procedure TMainForm.ExitPointClick(Sender: TObject);

begin

Close;

end;

procedure TMainForm.InputClick(Sender: TObject);

begin

Edit1.SetFocus;

end;

procedure TMainForm.AboutClick(Sender: TObject);

begin

AboutForm.ShowModal;

end;

End.

unit About; {Модуль с дополнительной формой.}

Interface

Uses

Windows, Classes, Graphics, Forms,

Controls, StdCtrls, Buttons, ExtCtrls;

Type

TAboutForm = class(TForm)

Panel1: TPanel;

OKButton: TBitBtn;

ProgramIcon: TImage;

ProductName: TLabel;

Department: TLabel;

Copyright: TLabel;

Comments: TLabel;

end;

var AboutForm: TAboutForm;

Implementation

{$R *.DFM}

End.

unit DeclComplex; {Модуль с объявлением типа Complex.}

Interface

Type

Complex=record

Re,Im:Real;

end;

Implementation

End.

Library MyDLL; {Программа DLL.}

uses SysUtils, Classes, DeclComplex;

function AddC(X,Y:complex):complex;

Begin

With result do begin

Re:=X.Re+Y.Re;

Im:=X.Im+Y.Im;

end;

end;

Exports AddC;

begin

End.

Импортирование подпрограмм другими программными единицами возможно в статическом (неявном) или динамическом (явном) режимах. Если используется статическое импортирование подпрограммы, то задаётся заголовок такой подпрограммы с командой External. Если DLL является Windows-библиотекой или, например написанной на C++, то необходимо указать соглашения о вызовах. Например,

Procedure Proc1(var x:Variant);

Cdecl;External 'CDLL.dll';

В этом примере из библиотеки CDLL.dll, написанной на C++ (указано соглашение этого языка о передаче данных Cdecl).

При статическом импортировании сама библиотека вызывается операционной системой при первом к ней обращении и выгружается, когда потребность в ней отпадает.

При динамическом импортировании библиотека грузится непосредственно внутри той программной единицы, которой она необходима. После того, как надобность в библиотеке исчезнет, её нужно выгрузить. Для загрузки используется стандартная функция LoadLibrary (API-функция) с единственным параметром типа PChar, задающим имя библиотеки, например,

Var Handle:HModule;

....

Handle:=LoadLibrary(‘MyDll.dll’);

Для выгрузки DLL используется следующая подпрограмма:

FreeLibrary(Handle);

Для работы с библиотекой необходимо получить адрес требуемой функции (или процедуры). При этом используется API-функция GetProcAdress(Handle: HModule, lpProcName: LPCSTR): FARPROC, которая ищет подпрограмму, указанную именем lpProcName. В качестве результата возвращается указатель на функцию (или процедуру) или nil. Полученный указатель должен быть далее приведен к нужному типу. Например, возможен такой вариант:

Unit uCallDll;

Interface

......

type TAddC = Function(X,Y:Complex):Complex;

TForm1=class(TForm)

.......

private {Добавим в описание формы}

DLLHandle: HModule;

ExternalMyFunctionPointer:TFarProc;

ExternalMyFunction: TAddC;

........

Implementation

.........

procedure TForm1.Button1Click(Sender:TObject);

......

DLLHandle:= LoadLibrary(‘MyDll.dll’);

ExternalMyFunctionPointer:= GetProcAdress(DLLHandle,

PChar(‘AddC’));

ExternalMyFunction:= TAddC(ExternalMyFunctionPointer);

....

В данном примере вполне работоспособном опущены некоторые операторы, с помощью которых проверяется, удачно или нет выполнено то или иное действие по получению ресурсов.

ТЕХНОЛОГИИ ПРОГРАММИРОВАНИЯ

 

Ниже будут рассмотрены некоторые стандартные для Windows технологии программирования. Вообще, технология представляет собой набор методов и способов, позволяющих получить требуемые результаты. Поэтому знание различных подходов в программировании позволит разрабатывать профессионально законченные и надежно работающие приложения. Выше были рассмотрены технологии, например, построения циклических вычислительных процессов, построения динамически компонуемых библиотек и т.д. Далее рассмотрим более сложные технологии.

 

ПОТОКИ ДАННЫХ

 

Потоки – достаточно мощное средство при реализации операций ввода или вывода данных, располагающихся на различных носителях. Потоки представляют собой специальные объекты, которые строятся с помощью наследников абстрактного класса TStream. Этот класс содержит методы, в которых заложены операции чтения, записи, изменения текущего положения указателя данных, открытия и закрытия потока. Поскольку для разных носителей реализация указанных выше операций зависит от конкретной реализации устройства, построено несколько специальных классов. Наиболее часто используются потоки TFileStream, THandleStream для работы с файлами на диске и TMemoryStream – для работы с памятью. TFileStream используется, когда необходимо работать с именем файла, THandleStream используется, например с файлами Windows, когда определяется дескриптор файла.

Любая работа, например с файловым потоком начинается с его построения, используя стандартный конструктор Create(const Filename:string; Mode:Word). Параметр Filename задает имя файла, а параметр Mode – режимы создания (fmCreate), чтения (fmOpenRead), записи (fmOpenWrite) или одновременного чтения и записи (fmOpenReadWrite) файла. С помощью операции логического или (or) к указанному параметру можно добавить режим совместного использования, например fmShareExclusive – файл недоступен для открытия другими приложениями. При этом поток работает с файлом без учета типа хранящихся в нем данных.

Для чтения и записи данных при работе с потоком используются методы Read и Write, содержащие по два параметра: переменная, куда считываются байты и количество байтов.

 

ПРИМЕР 21

 

Пусть заданы некоторые совокупности целых чисел. Требуется построить, используя эти данные, диаграммы (или графики). Данные берутся из файлов. С помощью, например, StringGrid можно вводить новые данные или корректировать значения точек и записывать в файлы. Работу с файлами необходимо реализовать с помощью потоков.

В данном примере нам понадобятся три новых компонента. Для визуализации данных воспольуемся диаграммами, которые можно построить с помощью компонента TСhart со страницы Additional палитры компонентов. Данный компонент имеет множество настроек и позволяет представлять одновременно несколько диаграмм. В данном случае из множества настроек выберем минимум. Представляемые данные в виде серий задаются с помощью рядов целых чисел (Series). Для создания таких рядов необходимо после размещения компонента на форме щелкнуть на нем правой кнопкой мыши. В появившемся выпадающем меню выбрать пункт Edit Chart – откроется редактор с двумя вкладками. Щелкнуть мышкой на вкладке Chart. С помощью кнопки Add построим, например, три ряда (Series) точек и для каждого ряда выберем вариант графика, цвет и подпись. На форме появятся объекты типа TBarSeries. Далее на вкладке Series выбрать страницу Data Source и установить Random Values (для построения графиков с помощью случайных точек). Все свойства можно редактировать в инспекторе объектов.

Для демонстрации возможностей файловых потоков нам понадобятся два диалоговых стандартных компонента со страницы Dialogs: OpenDialog – выбор открываемого файла и SaveDialog – выбор сохраняемого файла. Основная настройка этих элементов заключается в задании расширения выбираемых файлов (DefaultExt – задать CHR – тип файлов, с которыми работает компонент TChart) и фильтра (Filter). Чтобы задать фильтр в файловых диалогах, из инспектора объектов необходимо выйти в FilterEditor и набрать в каждом компоненте по две строчки (табл. 15).

Таблица 15

FilterEditor

Filter Name Filter
Chart files (*.chr) *.chr
Any file (*.*) *.*

 

Для открытия диалога вызывается метод Execute, а при выходе возвращается имя файла в свойстве FileName.

Вариант решения примера 21 приводится на рис. 49.

Рис. 49 Вариант решения примера 21.

В примере используется ряд обработчиков событий. Обработчик FormCreate задает первоначальные значения для исходных данных, которые при необходимости можно записать в файл (кнопка “Запись”, обработчик SaveButtonClick) или проигнорировать, загрузив данные из файла (кнопка “Файл”, обработчик OpenButtonClick). Кроме того, запоминаются в массиве Se (объявлен в секции формы private) настройки цвета диаграмм и вызывается обработчик (UpdateButtonClick, кнопка “Изменить”), который строит эти диаграммы. С помощью свернутых списков Combos запоминаются варианты графиков (или диаграмм). Использование обработчиков ComboChange и ChBoxMarksClick позволяет выбрать соответственно желаемый вид диаграммы или промаркировать их (при необходимости можно записать в файл свой выбор). Из всего многообразия графиков в данном случае выбраны четыре: линейный, столбиковый, поверхность, точки (занесены в списки используемых трех элементов TComboBox). Для удобства коррекции данных в строковой таблице подключается маска ввода в виде обработчика StringGrid1GetEditMask. Ниже приводится текст программы.

unit Prim21;

Interface

uses SysUtils, Windows, Messages, Classes, Graphics,

Controls, Forms, Dialogs, Grids, StdCtrls, TeEngine,

Series, ExtCtrls, TeeProcs, Chart, Menus, Buttons;

Type

TForm1 = class(TForm)

Chart1: TChart;

Series1: TBarSeries;

Series2: TBarSeries;

Series3: TBarSeries;

Panel1: TPanel;

ChBoxMarks: TCheckBox;

UpdateButton: TButton;

StringGrid1: TStringGrid;

ComboBox1: TComboBox;

ComboBox2: TComboBox;

ComboBox3: TComboBox;

OpenDialog1: TOpenDialog;

SaveDialog1: TSaveDialog;

OpenButton: TButton;

SaveButton: TButton;

BitBtn1: TBitBtn;

procedure FormCreate (Sender: TObject);

procedure UpdateButtonClick (Sender: TObject);

procedure StringGrid1GetEditMask (Sender: TObject;

ACol, ARow: Longint; var Value: string);

procedure ChBoxMarksClick (Sender: TObject);

procedure ComboChange (Sender: TObject);

procedure OpenButtonClick (Sender: TObject);

procedure SaveButtonClick (Sender: TObject);

Private

Combos: array [0..2] of TComboBox;

CurrentFile: string;

Se:array [1..3] of TColor;

end;

var Form1: TForm1;

Implementation

{$R *.DFM}

procedure TForm1.FormCreate (Sender: TObject);

var I, J: Integer;

begin

with StringGrid1 do begin

for I:=1 to 5 do Cells[I,0]:=

Format('Группа %d', [I]);

for J:=1 to 3 do Cells[0,J]:=

Format('Серия %d', [J]);

Randomize;

for I:= 1 to 5 do

for J:= 1 to 3 do

Cells [I, J]:= IntToStr(Random(100));

end;

Combos [0]:= ComboBox1;

Combos [1]:= ComboBox2;

Combos [2]:= ComboBox3;

for I:= 0 to 2 do begin

Combos[I].ItemIndex:= 1;

Se[I+1]:=Chart1.Series[I].SeriesColor;

end;

UpdateButtonClick(self);

end;

procedure TForm1.UpdateButtonClick (Sender: TObject);

var I, J: Integer;

begin

for I:= 1 to 3 do begin

Chart1.Series[I-1].Clear;

for J:= 1 to 5 do Chart1.Series [I-1].Add(

StrToInt(StringGrid1.Cells[J,I]),'', Se[I]);

end;

end;

procedure TForm1.StringGrid1GetEditMask (Sender:

TObject; ACol, ARow: Longint; var Value: string);

begin

Value:= '09;0';

end;

procedure TForm1.ChBoxMarksClick (Sender: TObject);

var I: Integer;

begin

for I:= 1 to 3 do

Chart1.Series[I-1].Marks.Visible:=

ChBoxMarks.Checked;

end;

procedure TForm1.ComboChange (Sender: TObject);

var I: Integer;

SeriesClass: TChartSeriesClass;

NewSeries: TChartSeries;

begin

for I:= 2 downto 0 do Chart1.Series[I].Free;

for I:= 0 to 2 do begin

case Combos [I].ItemIndex of

0: SeriesClass:= TLineSeries;

1: SeriesClass:= TBarSeries;

2: SeriesClass:= TAreaSeries;

else SeriesClass:= TPointSeries;

end;

NewSeries:= SeriesClass.Create(self);

NewSeries.ParentChart:= Chart1;

NewSeries.Title:=Format('Серия %d', [I+1]);

end;

ChBoxMarksClick(self);

UpdateButtonClick(self);

end;

procedure TForm1.OpenButtonClick (Sender: TObject);

var ReadStream: TFileStream;

I, J, Value: Integer;

begin

if OpenDialog1.Execute then begin

CurrentFile:= OpenDialog1.Filename;

Caption:=’ ПРИМЕР 20 (Данные файла '+

CurrentFile+')';

try

ReadStream:= TFileStream.Create(CurrentFile,

fmOpenRead);

for I:= 1 to 5 do

for J:= 1 to 3 do begin

ReadStream.Read(Value, SizeOf(Integer));

StringGrid1.Cells[I,J]:= IntToStr(Value);

end;

ReadStream.Read(Value, SizeOf(Integer));

ChBoxMarks.Checked:= Boolean(Value);

for I:= 0 to 2 do begin

ReadStream.Read(Value, SizeOf(Integer));

Combos[I].ItemIndex:= Value;

ReadStream.Read(Value, SizeOf(Integer));

Se[i+1]:= Value;

end;

finally

ReadStream.Free;

end;

ChBoxMarksClick(self);

ComboChange(self);

UpdateButtonClick(self);

end;

end;

procedure TForm1.SaveButtonClick (Sender: TObject);

var SaveStream: TFileStream;

I, J, Value: Integer;

begin

if SaveDialog1.Execute then begin

CurrentFile:= SaveDialog1.Filename;

Caption:=’ ПРИМЕР 20 (Данные файла ' +

CurrentFile+')';

try

SaveStream:= TFileStream.Create(CurrentFile,

fmOpenWrite or fmCreate);

for I:= 1 to 5 do

for J:= 1 to 3 do begin

Value:= StrToIntDef(

Trim(StringGrid1.Cells[I,J]), 0);

SaveStream.Write(Value,SizeOf(Integer));

end;

Value:= Integer(ChBoxMarks.Checked);

SaveStream.Write(Value,SizeOf(Integer));

for I:= 0 to 2 do begin

Value:= Combos [I].ItemIndex;

SaveStream.Write(Value,SizeOf(Integer));

SaveStream.Write(Se[i+1],SizeOf(Integer));

end;

finally

SaveStream.Free;

end;

end;

end;

End.

Работа с потоками реализована в обработчиках OpenButtonClick и SaveButtonClick, в которых соответсвенно выполняется чтение файла в поток ReadStream и запись потока SaveStream в файл. Компонент TChart работает с собственным типом бинарных файлов. Пототоки ReadStream и SaveStream корректно записывают и воспроизводят информацию. В данном случае информация складывается из целых чисел в следующей последовательности: точки графиков, признак меток (преобразуется в булевый тип из числа), виды графиков и их цвета.

 

ПРИМЕР 22

 

В данном примере рассмотрим работу с потоками в памяти (TmemoryStream).

Пусть вводится информация о некоторых спортивных соревнованиях. Примем для упрощения, что необходимо ввести порядковый номер участника и время, которое он показал. Эту информацию далее необходимо отсортировать в порядке возрастания по времени и записать в файл. Пусть показанное участниками соревнования время колеблется от 20 до 35 минут и пусть оно генерируется в программ


Поделиться с друзьями:

Особенности сооружения опор в сложных условиях: Сооружение ВЛ в районах с суровыми климатическими и тяжелыми геологическими условиями...

Поперечные профили набережных и береговой полосы: На городских территориях берегоукрепление проектируют с учетом технических и экономических требований, но особое значение придают эстетическим...

Двойное оплодотворение у цветковых растений: Оплодотворение - это процесс слияния мужской и женской половых клеток с образованием зиготы...

Индивидуальные очистные сооружения: К классу индивидуальных очистных сооружений относят сооружения, пропускная способность которых...



© cyberpedia.su 2017-2024 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!

0.572 с.