Оглавление Работа с двунаправленным списком. Описание: в исходнике


---- Исходный текст  ----
Program Mina;
uses un4, crt;
begin { ************* Начало главной программы ************** }
 textattr:= $1f; clrscr;
writeln(' +---------- Условия задачи: -------------+');
writeln(' | Даны действительные A[1],A[2],...A[N]  |');
writeln(' | (N - четное). Найти min(A[1]*A[N/2+1], |');
writeln(' | A[2]*A[N/2+2],... A[N/2]*A[N])         |');
writeln(' | Использовать двунаправленный список    |');
writeln(' +----------------------------------------+');
writeln;
 writeln(' Выберите вариант заполнения: ');
 writeln(' 1 - с клавиатуры, 2 - случайные числа');
 repeat
 cc1:= readkey;
 until cc1 in ['1','2']; {чтобы запретить ввод других символов}
 case cc1 of
 '1': VvodSpiska(LeftHead,RightHead);
 '2': Zapoln;
 end;
 if Pusto(LeftHead.Next) then halt(1);
 ControlPrav(RightHead); writeln;
 write(' В списке ',count,' элемент');
 case count mod 10 of
 1:writeln('.');
 2..4:writeln('а.');
 0,5..9:writeln('ов.');
 end;
 writeln;
 mini:= MinSpis(LeftHead,poradok);
 writeln(' Результат (Min)= ',mini:10:2,' (В ',count div 2 - poradok,
 '-й паре).');
 readln;
 { чтобы результат остался на экране - ожидаю нажатия клав Enter}
 textattr:= $07; clrscr;
end.

---------- Модуль с описаниями ----------
Unit un4;
interface {интерфейсная часть модуля содержит описания элементов программы (типов, констант,
переменных, ЗАГОЛОВКИ подпрограмм) которые должны быть доступны в других модулях
(в том числе в главной программе)}

Const KP=8;

Type PElem = ^TElem; {указатель на элемент двунаправленного списка}
     TElem = record  {элемент двунаправленного списка}
     Number: double;  {поле для хранения вещественного числа}
     Next: PElem;   {указатель (на следующий элемент списка)}
     Prev: PElem;   {указатель (на предыдущий элемент списка)}
     end;

Var d1,LeftHead, { используя эту переменную будем двигаться по списку слева-направо}
RightHead:  { используя эту переменную будем двигаться по списку справа-налево }
TElem;
count,NN,poradok: integer; cc1: char; mini: double;

Function Pusto(PP: Pointer):Boolean;         { описание подпрограмм см ниже }
Procedure ControlSpiska(var Lev,Prav:TElem);
Procedure ControlPrav(Nac:TElem);
Procedure VvodSpiska(var Lev,Prav:TElem);
Function MinSpis(Lev: TElem; var poradok:integer):double;
Procedure Zapoln;

implementation {эта часть (реализация) содержит описания, которые не нужны другим модулям}

uses crt; {предложение USES содержит список модулей, необходимых для компиляции описаний,
           размещенных в этой части модуля (implementation). Интерфейс тоже может
           содержать предложение USES, если необходимо. Необходимость определяется при
           компиляции (компилятор сообщает, что какие-то детали описания неизвестны)}

Function Pusto(PP: Pointer):Boolean; { Если указатель PP=nil - печатает сообщение и
 возвращает true }
begin
 if PP=nil then
     begin writeln(' Список пустой. Жми Enter'); readln;
       Pusto := true;
       textattr:= $07; clrscr; {устанавливает цвет фона и символов (перед выходом из проги)}
     end else Pusto:= false;
end;

Procedure ControlSpiska(var Lev,Prav:TElem);
{Показывает содержимое списка и организует левые связи (.Prev)}
var ele,e2: PElem;
begin  clrscr; {чистит экран}
   count:= 0; {обнуляет счетчик} writeln;
   writeln(' --------- КОНТРОЛЬ списка (вывод слева-направо) -----------');
   ele:= Lev.Next;
    if Pusto(ele) then halt(1); {если указатель ele пустой, прога выходит в систему с кодом
     возврата = 1 (т е аварийно)}
   ele^.Prev:= nil; {это будет последний (при движении справа-налево) элемент, поэтому
    его указатель .Prev должен содержать nil}
   Repeat
    e2:= ele; {сохраняю ссылку на элемент ele}
    write (ele^.Number:10:2); {распечатываю содержимое элемента ele }
    inc(count); {увеличиваю счетчик на 1}
    ele:= ele^.Next; {после этого оператора ele будет указывать на следующий (вправо) элемент}
    if ele <> nil then {т е если этот элемент существует, то }
    ele^.Prev:= e2; {указателю на предыдущий (т е расположенный слева) элемент
    присваиваю e2 (который действительно расположен левее от ele)}
   until ele = nil; {цикл продолжается до конца списка (движение слева-направо)}
   Prav.Prev := e2; {после выхода из этого цикла e2 указывает на последний элемент списка,
   поэтому нужно свяхать его с переменной, указывающий на начало (при движении справа-налево)
   списка}
   writeln;
  write(' Для продолжения жми Enter');
  readln; {чтобы программа ожидала нажатия на клавишу Enter}
end;

Procedure ControlPrav(Nac:TElem);
{Показывает содержимое списка, начиная справа }
var ele: PElem; half,ii: Integer;
begin  clrscr; half:= count div 2; writeln;
   writeln(' --------- КОНТРОЛЬ списка (вывод справа-налево) -----------');
   ele:= Nac.Prev; {указателю ele присваиваю адрес крайнего справа элемента списка
   (потому что при вызове фактическим параметром для Nac будет RightHead)}
   if Pusto(ele) then halt(1);
   ii:=0; {(счетчик)}
   Repeat
    inc(ii);
    write (ele^.Number:10:2);
    if ii = half then
      begin writeln;writeln(' ------------ Другая половина ------- ');
      end;
    ele:= ele^.Prev; {перемещаюсь к предыдущему (т е ближайшему слева) элементу списка}
   until ele = nil; {цикл повторяется до конца списка}
   writeln;  writeln;
  write(' Для продолжения жми Enter'); readln;
end;

Procedure VvodSpiska(var Lev,Prav:TElem);
{Ввод списка производится с использованием только правых (.Next) указателей}
var ele: PElem; cnt: integer;
begin textattr:= $1F; {текст атрибуты: цвет фона = 1(синий), цвет символов=$F (белый)}
clrscr;   cnt:=0;
  writeln(' --------- Введи список (четное число элементов) ---------');
  Lev.Next:= nil;
   Repeat
     repeat
     write(' В списке ',cnt,
     ' элементов. Введи вещественное число (0 - выход)-> ');
     readln(d1.Number);
     until not ((d1.Number = 0) and (cnt mod 2 <> 0));
     if (d1.Number = 0) then break;
     inc(cnt);
     New(ele);
     ele^ := d1;
     ele^.Next:= Lev.Next;
     Lev.Next:= ele;
   until false;
  ControlSpiska(Lev,Prav);
end;

Function MinSpis(Lev: TElem; var poradok:integer):double;
{План действий:
1. Нахожу середину списка (сохраняю в указателе Sered),
 т е элемент с порядк номером N/2
(отсчет начинаю с 1). N вычисляет Procedure ControlPrav
2. В задаче требуется найти мин среди чисел:
a[1]*a[N/2+1], a[2]*a[N/2+2],a[3]*a[N/2+3],...a[N/2]*a[N],
где a[i] обозначает содержимое (т е число, хранящееся в )
i-м элементе списка
3. Имея указатель LeftHead, передвигаюсь по элементам
списка 1,2,3,... N/2, а при помощи указателя Sered
передвигаюсь по элементам списка N/2+1,N/2+2,N/2+3,...N,
перемножая соответствующие числа.
4. Мин нахожу, используя стандартный алгоритм т е
  а)Переменной Min присваиваю a[1]*a[N/2+1]
  б)Выполняю цикл по j от 2 до N/2:
    - если a[j]*a[N/2+j] < Min => присваиваю Min:= a[j]*a[N/2+j];
   и poradok:= j;
   (по списку передвигаюсь при помощи elem:= elem^.Next,
   т е передвигаюсь слева-направо)
}
var ele,ele2,Sered: PElem; cnt2,NSered,jj: integer; bufa,Mina: double;
begin
   ele:= Lev.Next; cnt2:= 0;
    if Pusto(ele) then halt(1); {если указатель ele пустой, прога выходит в систему с кодом
     возврата = 1 (т е аварийно)}
   Repeat
    inc(cnt2); {увеличиваю счетчик на 1}
    ele:= ele^.Next;
    {после этого оператора ele будет указывать на следующий (вправо) элемент}
   until cnt2 = count div 2 - 1;
    {цикл продолжается до середины списка (движение слева-направо)}
{***********  writeln(ele^.Number); ********** }
   Sered:= ele;

   ele:= Lev.Next;
   ele2:= Sered^.Next;
   Mina:= ele^.Number*ele2^.Number; {перемножил 1-й и N/2 + 1-й элементы }

{ writeln(' ----------- Сравниваю произведения: -------------');
 write(Mina:10:2);  отладочная распечатка }
   jj:= 0; {счетчик}
   Repeat inc(jj);
     ele:= ele^.Next;
     ele2:= ele2^.Next;
     bufa:= ele^.Number*ele2^.Number;
       {перемножаю следующие элементы (2  на N/2+2 и т д )}
 { write(bufa:10:2); отладочная распечатка }
     if bufa < Mina then
      begin Mina:= bufa; poradok:=jj;
       end;
   until ele2^.Next = nil;
   MinSpis:= Mina;
end;

Procedure Zapoln; {заполняю список случайными числами}
var cnt,ii: integer;
    elem: PElem;
begin randomize; {Чтобы избежать повтора цепочки случайных чисел}
  repeat  write(' Введите число элементов списка (четное) -> ');
 readln(cnt);
 until cnt mod 2 = 0; {чтобы избежать ввода нечетного числа}

  LeftHead.Next:= nil; ii:=0;
   Repeat
     inc(ii); {счет созданных элементов}
     New(elem);
     elem^.Number := random(10)+1 {random*1000 - 500}; {2 варианта случайных чисел}
     elem^.Next:= LeftHead.Next; 
     LeftHead.Next:= elem; {стандартно вставляю новый элемент в начало списка }
   until ii=cnt;
  ControlSpiska(LeftHead,RightHead);
end;

end.
Rambler's Top100
Hosted by uCoz