Рефетека.ру / Информатика и програм-ие

Реферат: Динамические структуры данных: списки

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

Введение

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

В языках программирования (Pascal, C, др.) существует и другой способ выделения памяти под данные, который называется динамическим. В этом случае память под величины отводится во время выполнения программы. Такие величины будем называть динамическими. Раздел оперативной памяти, распределяемый статически, называется статической памятью; динамически распределяемый раздел памяти называется динамической памятью (динамически распределяемой памятью).

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

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

Указатель содержит адрес поля в динамической памяти, хранящего величину определенного типа. Сам указатель располагается в статической памяти.

Адрес величины — это номер первого байта поля памяти, в котором располагается величина. Размер поля однозначно определяется типом.

Далее будем более подробно обсуждать указатели и действия с ними в языке Pascal, примеры будем приводить на Pascal и C.

Величина ссылочного типа (указатель) описывается в разделе описания переменных следующим образом:

               Var : ^;

Вот примеры описания указателей:

   Type Mas1 = Array[1..100] Of Integer;

   Var      P1 : ^Integer;

               P2 : ^String;

               Pm : ^Mas1;

Здесь P1 — указатель на динамическую величину целого типа; P2 — указатель на динамическую величину строкового типа; Pm — указатель на динамический массив, тип которого задан в разделе Type.

Сами динамические величины не требуют описания в программе, поскольку во время компиляции память под них не выделяется. Во время компиляции память выделяется только под статические величины. Указатели — это статические величины, поэтому они требуют описания.

Каким же образом происходит выделение памяти под динамическую величину? Память под динамическую величину, связанную с указателем, выделяется в результате выполнения стандартной процедуры NEW. Формат обращения к этой процедуре:

               NEW();

Считается, что после выполнения этого оператора создана динамическая величина, имя которой имеет следующий вид:

               := ^

Пусть в программе, в которой имеется приведенное выше описание, присутствуют следующие операторы:

               NEW(P1); NEW(P2); NEW(Pm);

После их выполнения в динамической памяти оказывается выделенным место под три величины (две скалярные и один массив), которые имеют идентификаторы:

   P1^, P2^, Pm^

Например, обозначение P1^ можно расшифровать так: динамическая переменная, на которую ссылается указатель P1.

Дальнейшая работа с динамическими переменными происходит точно так же, как со статическими переменными соответствующих типов. Им можно присваивать значения, их можно использовать в качестве операндов в выражениях, параметров подпрограмм и пр. Например, если переменной P1^ нужно присвоить число 25, переменной P2^ присвоить значение символа "Write", а массив Pm^ заполнить по порядку целыми числами от 1 до 100, то это делается так:

               P1^ := 25;

               P2^ := 'Write';

               For I := 1 To 100 Do Pm^[I] := I;

Кроме процедуры NEW значение указателя может определяться оператором присваивания:

               := ;

В качестве ссылочного выражения можно использовать

указатель;

ссылочную функцию (т.е. функцию, значением которой является указатель);

константу Nil.

Nil — это зарезервированная константа, обозначающая пустую ссылку, т.е. ссылку, которая ни на что не указывает. При присваивании базовые типы указателя и ссылочного выражения должны быть одинаковы. Константу Nil можно присваивать указателю с любым базовым типом.

До присваивания значения ссылочной переменной (с помощью оператора присваивания или процедуры NEW) она является неопределенной.

Ввод и вывод указателей не допускается.

Рассмотрим пример. Пусть в программе описаны следующие указатели:

               Var      D, P : ^Integer;

                           K : ^Boolean;

Тогда допустимыми являются операторы присваивания

               D := P; K := Nil;

поскольку соблюдается принцип соответствия типов. Оператор K := D ошибочен, т.к. базовые типы у правой и левой части разные.

Если динамическая величина теряет свой указатель, то она становится "мусором". В программировании под этим словом понимают информацию, которая занимает память, но уже не нужна.

Представьте себе, что в программе, в которой присутствуют описанные выше указатели, в разделе операторов записано следующее:

NEW(D); NEW(P);

{Выделено место в динамической памяти под две целые переменные. Указатели получили соответствующие значения}

D^ := 3; P^ := 5;

{Динамическим переменным присвоены значения}

P := D;

{Указатели P и D стали ссылаться на одну и ту же величину, равную 3}

WriteLn(P^, D^); {Дважды напечатается число 3}

Таким образом, динамическая величина, равная 5, потеряла свой указатель и стала недоступной. Однако место в памяти она занимает. Это и есть пример возникновения "мусора". На схеме показано, что произошло в результате выполнения оператора P := D.

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

               DISPOSE();

Например, если динамическая переменная P^ больше не нужна, то оператор

               DISPOSE(P)

удалит ее из памяти. После этого значение указателя P становится неопределенным. Особенно существенным становится эффект экономии памяти при удалении больших массивов.

В версиях Турбо-Паскаля, работающих под операционной системой MS DOS, под данные одной программы выделяется 64 килобайта памяти (или, если быть точнее, 65520 байт). Это и есть статическая область памяти. При необходимости работать с большими массивами информации этого может оказаться мало. Размер динамической памяти — много больше (сотни килобайт). Поэтому использование динамической памяти позволяет существенно увеличить объем обрабатываемой информации.

Следует отчетливо понимать, что работа с динамическими данными замедляет выполнение программы, поскольку доступ к величине происходит в два шага: сначала ищется указатель, затем по нему — величина. Как это часто бывает, действует "закон сохранения неприятностей": выигрыш в памяти компенсируется проигрышем во времени.

Пример. Дан текстовый файл размером не более 64 Кб, содержащий действительные числа, по одному в каждой строке. Переписать содержимое файла в массив, разместив его в динамически распределяемой памяти. Вычислить среднее значение элементов массива. Очистить динамическую память. Создать целый массив размером 10000, заполнить его случайными целыми числами в диапазоне от –100 до 100 и вычислить его среднее значение.

{Язык Turbo Pascal}

Program Srednee;

Const NMax = 10000;

Type Diapazon = 1..NMax;

MasInt = Array[Diapazon] Of Integer;

MasReal = Array[Diapazon] Of Real;

Var PIint : ^MasInt; PReal : ^MasReal;

I, Midint : longInt; MidReal : Real; T : Text; S : string;

Begin

   Write('Введите имя файла: '); ReadLn(S);

   Assign(T, S); Reset(T); MidReal := 0; MidInt := 0;

   Randomize;

   NEW(PReal); {Выделение памяти под вещественный массив}

   {Ввод и суммирование вещественного массива}

   While Not Eof (T) Do

   Begin ReadLn(T, PReal^[I]); MidReal := MidReal + PReal^[I] End;

   DISPOSE(PReal); {Удаление вещественного массива}

   NEW(PInt); {Выделение памяти под целый массив}

   {Вычисление и суммирование целого массива}

   For I := 1 To NMax Do

   Begin PInt^[I] := -100 + Random(201); MidInt := MidInt + PInt^[I] End;

   {Вывод средних значений}

   WriteLn('среднее целое равно: ', MidInt Div NMax);

   WriteLn('среднее вещественное равно: ', (MidReal / NMax) : 10 : 6)

End.

// Язык C++

#include < stdio.h >

#include < time.h >

#include < stdlib.h >

#include < iostream.h >

#define NMax 10000

typedef int MasInt;

typedef float MasReal;

MasInt *PInt; MasReal *PReal;

int I, n, MidInt; float MidReal; char S[255];

FILE *t; char *endptr;

void main()

{     cout > S;

      t=fopen(S, "r");

      MidReal = 0; MidInt = 0;

      randomize(); I=0;

      /*Выделение памяти под вещественный массив*/

      PReal = (MasReal*) malloc (sizeof(MasReal));

      /*Ввод и суммирование вещественного массива*/

      while (!feof(t))

       {fgets(S, 255, t); // вводим из файла строку

        PReal[I] = strtod(S, &endptr); // преобразуем введенную строку в вещественное число

   MidReal += PReal[I]; I++;}

      n=I+1;

      free (PReal); /*Удаление вещественного массива*/

      PInt = (MasInt*) malloc(sizeof(MasInt)); /*Выделение памяти под целый массив*/

      /* Вычисление и суммирование целого массива */

      for (I=0; I < NMax; I++)

       { PInt[I] = -100 + random(201);

    MidInt += PInt[I];}

      /*Вывод средних значений*/

      cout Next=First; First=Vsp;

   return First;

}

Zveno *Iz_Nachala(Zveno *First)

{ Zveno *Vsp;

   Vsp=First->Next;

   free(First);

   return Vsp;

}

Zveno *V_Spisok(Zveno *Pred, BT X)

{ Zveno *Vsp;

        Vsp = (Zveno *) malloc(sizeof(Zveno));

        Vsp->Inf=X;

        Vsp->Next=Pred->Next;

        Pred->Next=Vsp;

        return Vsp;

}

BT Iz_Spiska(Zveno *Pred)

{ BT X;

   Zveno *Vsp;

        Vsp=Pred->Next;

        Pred->Next=Pred->Next->Next;

   X=Vsp->Inf;

   free(Vsp);

   return X;

}

void Print(Zveno *First)

{ Zveno *Vsp;

   Vsp=First;

   while (Vsp)

           {cout Inf Next;}

   cout 0

        Then If S2 = Nil

             Then Begin V_Nachalo(S2, V1^.Inf); V2 := S2 End

             Else Begin V_Spisok(V2, V1^.Inf); V2 := V2^.Next End;

        If V1^.Inf < 0

        Then If S3 = Nil

             Then Begin V_Nachalo(s3, V1^.Inf); V3 := S3 End

             Else Begin V_Spisok(V3, V1^.Inf); V3 := V3^.Next End;

        V1:= V1^.Next

    End;

    WriteLn('Результирующий список из положительных элементов: '); Print(S2);

    WriteLn('Результирующий список из отрицательных элементов: '); Print(S3);

    Ochistka(S1); Ochistka(S2); Ochistka(S3);

End.

// Программа на C++

#include "SPIS.CPP"

void main()

{Zveno *S1, *S2, *S3, *V1, *V2, *V3;

 BT a; int i, n;

 clrscr();

 randomize();

 S1=NULL;

 // создаём первый элемент

 a=-100+random(201);

 S1=V_Nachalo(S1, a);

 n=1+random(20);

 // формируем список произвольной длины и выводим на печать

 V1=S1;

 for (i=2; iInf > 0)

         if (!S2)

                {S2=V_Nachalo(S2, V1->Inf); V2 = S2;}

         else {V_Spisok(V2, V1->Inf); V2 = V2->Next;};

    if (V1->Inf < 0)

        if (!S3)

               {S3=V_Nachalo(S3, V1->Inf); V3 = S3;}

        else {V_Spisok(V3, V1->Inf); V3 = V3->Next;};

    V1= V1->Next;}

  cout

Похожие работы:

  1. • Динамические структуры данных: списки
  2. • Динамические структуры данных: списки
  3. • Динамические структуры данных: списки
  4. • Динамические структуры данных: стеки
  5. • Динамические структуры данных: стеки
  6. • Динамические структуры данных: стеки
  7. • Динамические структуры данных: стеки
  8. • Динамические структуры данных: стеки
  9. • Синтаксический анализатор полиномов
  10. • Предмет и объект прикладной информатики
  11. • Динамические структуры данных
  12. • Разработка программ с использованием динамической ...
  13. • Разработка программ с использованием динамической ...
  14. • Ссылочные типы. Динамические переменные
  15. • Ответы на вопросы по курсу "Системное программирование"
  16. • Отчет по лабораторной работе №2
  17. • Разработка программы обработки экономической ...
  18. • Алгоритмический язык Паскаль
  19. • Основные понятия алгоритмического языка
Рефетека ру refoteka@gmail.com