Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Алгоритмдеу жане багдарламалау негиздери 4 г.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
2.73 Mб
Скачать

12 Дәріс тақырыбы: Бірбағытталған және екібағытталған байланысқан тізімдер. Көрсеткіштер.

Стекте немесе кезекте деректерді деректердің қандай да бір соңына қосуға болады (бұл деректерді алып тастауға да қатысты); осы операцияларды құрылымның кез-келген жерінде орналасқан деректермен жүргізуге жол берілмейді. Байланысқан тізім деректердің бір өлшемді құрылымы болып табылады, ол ерікті таңдалған жерде деректерді қоса алады, сондай-ақ ол жерден шығарылып тасталына алады. Мұндай икемділікті қамтамасыз ету үшін әрбір элементке тізімнің келесі элементін көрсететін байланыстардың звеносы қосылады.

1-суретте бір бағытталған байланысқан тізімнің схемалық кесікіні берілген (екі бағытталған байланысқан тізімдер келесі бөлімде қарастырылатын болады). Head атауы бар айнымалы бұл жерде тізімнің бірінші элементінің көрсеткіштері ретінде қолданылған. Тізімнің барлық элементтері бірдей форматта болады: байланыс звеносы келесі элементті көрсету үшін қолданылады, ал деректер ерікті форматта берілуі мүмкін. Байланыс звеносын және бір элементтің деректер блогын ЭЕМ жадының аралас учаскелерінде орналастыру міндетті болып табылмайды. Тізімде х элементінен кейінгі элементх элементінің орнын басушы; х элементінің алдында орналасқан элемент х элементінің алдындағы элемент деп аталады. Егер х элементінің орнын басушы болмаса, онда ондағы көрсеткіге null мәні беріледі.

Көрсеткі (байланыс звеносы)

head:

null

Бос тізім

Тізім элементінің форматы

Төрт элементтен тұратын тізім

Р элементінен кейін Q элементін қосу

Y элементін алып тастау

р элементі байланысының звеносы q элементін көрсетіп тұрды. Тізімнен х элементінен кейін тұрған у элементін шығарып тастау үшін х элементінде болатын у элементінің орнындағыны бағыттайтын көрсеткі қажет.

Паскаль тіліндегі байланысқан тізімдер мен басқа да динамикалық деректер құрылымын анықтау үшін pointer (көрсеткі) және record (жазба) деректер типіне негізделген тиімді құрал қарастырылған.

Бізге таныс массивтерді (жиымдарды) пайдаланып байланысқан тізімдердің қалай ұйымдастырылатынын қараймыз. Мысал ретінде 100-ден артық емес студенттің фамилиясы мен олардың емтихан бағаларынан тұратын топтың белгілі бір тізімін талқылаймыз. Баға жиымына арналған жады, әрқайсысы 20 литерден тұратын 100 фамилияны орналастыруға арналған 100х20 литерлік типтегі жиым үшін жады. сондай-ақ мәні бүтін сандар болып табылатын көрсеткілер жиымы үшін жады бөлуге болады. Көрсетілген жиымдарды былайша суреттеуге болады:

VAR name : ARRAY [1..100, 1..20] OF

char; . score: ARRAY [1..100] OF real;

link : ARRAY [0..100] OF integer;

Жиымның әрбір 20 литерлік жолы пате және баға жиымының оған сәйкес компоненті score тізімнің бір элементінің деректер блогын құрайды; score жиымы компонентінің нөмірі сияқты реттік нөмірі бар link жиымының компоненті және кейбір элементке жататын name жиымының жолдары осы элемент байланысының звеносы болып табылады.

Кейбір элементтің байланыс звеносының мәні ретінде қарастырылып отырған жиымдар индексінің жарамды мәні немесе null мәні қолданылуы мүмкін. Біздің мысалымызда null=-1; тізім элементтерінің байланыс звеноларының басқа өзге мәндері 1….100 ауқымында жатуы тиіс. link жиымының link[0] қосымша компоненті бар. Бұл компонент тізім басының нұсқағышы болады. Тізім басының нұсқағышы ретінде бүтінсанды типтің бөлек мәлімделген айнымалысы қолданылуы да мүмкін, алайда, бізге нәтижесінде белгілі болатындай, тізімдермен жасалатын кейбір операцияларды тізімнің басына қатынау оның басқа элементтеріне қатынау сияқты жүзеге асырылған жағдайда оңай орындалады.

Қаралып отырған мысалда q тізімге р индексі бар элементтен кейін қойылуы тиіс элементтің индексі болып табылады деп аламыз, деректер блогы толтырылған, сонда элементті қосуды операторлардың келесідей тізбегінің көмегімен орындауға болады:

{р элементінен кейін q элементін енгізу}

link[q]:=link[р];

link[p]:=q;

Элементті тізімнен шығарып тастау оңайырақ; келесі оператор у элементінің х индексі бар элементінің орнындағыны шығарып тастауға арналған:

(х элементінің орнындағыны шығарып тастау}

IF link[x]<>null THEN link [х] : = [link [x] ]

ELSE {Қате, х элементінің орнын басушы жоқ};

Төменде студенттердің фамилиялары мен емтихан бағаларын енгізуге және оларды топтың тізіміне алфавитке сәйкес фамилиялардың реттілігін сақтайтындай түрде қосуға арналған программа келтірілген. Программаның басында тізімнің басына null мәнін беру қарастырылған; пате және score жиымдарының программаны орындау басында деректері болмайды. Содан кейін мәндердің келесі жұбын енгізу жүзеге асырылады, яғни фамилиялар мен сәйкес бағалары, және оларды name жиымының келесі бос жолына және сәйкесінше score жиымының келесі ұяшығына орналастыру. Осыдан кейін тізімнің басынан бастап ол алфавит бойынша орналастырылмаған фамилия табылғанға дейін, немесе тізімнің соңына жеткенге дейін қаралады. Бұдан әрі жаңа фамилия тізімге фамилиялардың реттілігі тізімде алфавит бойынша сақталатындай түрде енгізіледі. Барлық бастапқы деректер енгізілгеннен кейін тізімнен емтихан бағалары топ бойынша орташа бағадан төмен болған студенттердің фамилиялары шығарылып тасталады. Тізімде қалған студенттердің фамилиялары мен олардың бағалары басуға шығарылады.

PROGRAM ClassList;

{Бос жолдармен бөлінген фамилиялар мен емтихан бағаларының тізбегін енгізу жүзеге асырылады; тізбектің соңының белгісі нүкте болады. Әрбір фамилия- баға жұбы байланысқан тізімге орналастырылады, онда фамилиялар алфавит ретімен орналастырыалды. Бастапқы деректерді енгізу аяқталғаннан кейін орташа емтихан бағалары топ бойынша орташа бағадан төмен болған студенттердің бағалары тізімнен алынып тасталады, ал қалған студенттердің фамилиялары мен бағалары басуға шығарылады}

CONST listLen = 100; nameLen = 20; {List and name lengths}

null = -1; {End-of-list link value} endChar = '.'; space = ' '; {Terminator and separator}

VAR

name : ARRAY [1..listLen, 1..nameLen] OF char;

score: ARRAY [1..listLen] OF real;

link : ARRAY [0..listLen] OF integer; {link[0] = head} sum, avg : real;

nNames, nChar, j, prev, next : integer; inChar : char; greater : boolean;

BEGIN

sum:=0; nNames:=0; link[0]:=null; {Initialization}

read(inChar); .{Get first char}

WHILE inChar <> endChar DO

BEGIN {Read all names and scores} nNames:=nNames+l; nChar:=l;

WHILE (inCharOspace) AND (inCharOendChar) DO

BEGIN {Read one name}

IF nChar<=nameLen THEN name[nNames,nChar]:=inChar; read(inChar); nChar:=nChar+l; END;

FOR j:=n char TO nameLen DO {Pad end with spaces}

name[nNames,j]:=space;

readln(score[nNames]); {Get score and start new line}

sum:=sum+score[nNames]; {Add to sum for average}

prev:=0; next:=link[0]; {Point to class list head}

greater:=false;

WHILE (nextonull) AND (NOT greater) DO

BEGIN {Chase down list until end or greater name found}

FOR j:=nameLen DOWNTO 1 DO

greater: = (name[next,j]>name[nNames, j]) OR ((name[next,j]=name[nNames,j]) AND greater);

IF NOT greater THEN {Get next item}

BEGIN prev:=next; next:=link[next] END;

END; {Then insert new item after prev}

link[nNames]:=next; link[prev]:=nNames;

IF nNames<listLen THEN read(inChar)

ELSE inChar:=endChar; {Terminate if toomany names}

END;

avg:=sum/nNames; {Compute average}

writeln('Average score:',avg,'Lower scores will be purged');

prev:=0; {Purge all scores lower thanclass average}

WHILE link [prev] Onull DO

BEGIN

IF score[link[prev]]<avg THEN

link[prev]:=link[link[prev]] ELSE

prev:=link[prev];

END;

next:=link[0]; writeln; {Now print there maining sorted list}

WHILE nextonull DO

BEGIN

FOR j:=l TO nameLen DO

write(name[next,j ] ) ;

writeln (score[next]);

next:=link[next];

END;

END.

Тізімнің басы ретінде link жиымының нөлдік элементін қолдану элементтерді тізімнің басына енгізу және оларды тізімнен арнайы тексерулер орындамастан шығарып тастау операцияларын жүргізуге мүмкіндік беретінін атап өтеміз. head жеке айнымалысын пайдалану мұндай операцияларды орындауды күрделендіріп жіберген болар еді.

Біздің мысалымызда тізімде деректер мен байланыстарды сақтау үшін жиымдар қолданылды, бұл ретте индекстер көрсеткіштердің рөлін атқарды. Индексті жиымда көрсеткіш ретінде қолдану объектілік программада тізімнің элементіне әрбір сілтеме жасаған сайын жиымның сәйкес компоненті үшін жады адресін шығарып тастауға арналған командалардың пайда болуына әкеліп соқтырады. Ассемблер тіліндегі программаларда көрсеткіш ретінде жадының абсолютті адрестерін қолданса программа көлемінің қосымша артуына жол бермеуге болады.

Біз суреттеген элементті бір бағытталған тізімге қосу және оны ол жерден шығарып тастау операциялары тізімнің кейбір элементінің орнындағысына әсерін тигізеді. Қосу операциясы з элементінен кейін q элементін орналастырудан, ал шығарып тастау операциясы х элементінің орнындағыны тізімнен шығарып тастаудан тұрады. Көрсеткі бір тізімнің х элементіне орнатылған және мысалы, мынадай операцияны орындау қажет деп аламыз: «У элементін л элементінің алдына қою», «Л элементін алып тастау». Екі операцияда да алдындағыда х элементінен тұратын көрсеткіштің мәні өзгеруі тиіс. Егер біздің жағдайымызда х элементіне тек қана көрсеткіш бар болса, онда х элементінің алдындағысын іздестірудің бір ғана тәсілі тізімнің басына қайтадан бару және оны х элементін тапқанға дейін қараудан тұрады. У элементін х элементінің алдына қосу программаның келесідей фрагментінің көмегімен орындалуы мүмкін:

(У элементін Х элементінің алдына қосу)

{ link [0] тізімнің басы болып табылады деп ұйғарамыз}

prev:=0;

WHILE (link[prev]<>null) AND

(linkfprev]<>x) DO prev:=link[prev];

IF link[prev]=x THEN BEGIN link[prev]:=y; link[y]:=x END

ELSE {Қате, Х элементі табылған жоқ};

Х элементін тізімнен шығарып тастау үшін мысалы, мынадай операторларды орындау талап етілген болар еді:

{Х элементін алып тастау}

prev:=0;

WHILE (link[prev]0null) AND (link[prev]<>x) DO prev:=link[prev];

IF link[prev]=x THEN link[prev]:=link[link[prev]];

ELSE {Қате, Х элементі табылған жоқ};

Бір бағытталған тізімнен соңғы элементті шығарып тастау операциясы барлық уақытта барлық тізімді қараумен байланысты. Кей кезде тізімді қарауға көп уақыт жұмсамас үшін екі бағытталған байланысқан тізімді пайдаланған тиімді.

Екі бағытталған байланысқан тізімде әрбір элементтің екі көрсеткіші болады: бірі sucdink – осы элементтің орнындағыны, екіншісі predlink - алдындағыны көрсетеді. Енді кейбір элементтің орнындағы немесе алдындағыға бір қадамда қол жеткізіледі, алайда элементті тізімге қосқан және одан шығарып тастаған кезде көрсеткіштердің біраз байланыстарын немесе мәндерін өзгерту қажет болады. Екі бағытталған тізімді пайдаланған кезде біз қарастырып отырған операцияларды операторлардың келесідей тізбегінің көмегімен орындауға болады:

{ У элементін Х элементінің алдына енгізу}

succlink[y]:=x;

predlink[y]:=predlink[х];

succlink[predlink[х]]:=у;

predlink[х]:=у;

{Включение элемента Y после элементаX}

succlink[у]:=succlink[х];

predlink[у]:=х;

predlink[succlink[х]]:=у;

succlink[х]:=у;

{Исключение элемента X}

predlink[succlink[х]]:=predlink[x];

succlink[predlink[х]]:=succlink[х];

Бір бағытталған тізім болған жағдайда егер тізімнің басы (head) мен соңына (tail) тізімнің басқа элементтеріне сияқты қатынау мүмкіндігі болса қосу және шығарып тастау операцияларын орындау оңай болады. Бұған егер head = succlink[0] и tail = predlink[0] деп алсақ қол жеткізуге болады. Тікелей бастапқы орнатудан кейін тізімнің басы мен соңы бірін бірі көрсетеді.

MS DOS операциялық жүйесі барлық адрестелетін кеңістікті сегменттерге бөледі. Сегмент – бұл өлшемі 64 К байт болатын жадының учаскесі. Адрес тапсырмалары үшін сегменттің басының адресін және сегменттің басына қатысты ығыстыруды анықтау қажет.

Паскалда Pointer – көрсеткіш адрестік түрі анықталған. Pointer түріндегі айнымалылар

var p: Pointer;

программаның қандай да бір элементінің адресінен тұрады және 4 байтты иеленеді, бұл ретте адрес екі сөз ретінде сақталады, олардың бірін сегмент, екіншісін – ығыстыру анықтайды.

Көрсеткіш түріндегі айнымалыны басқа тәсілмен сипаттауға болады:

type NameType = ^Т;

var p: NameType;

Бұл жерде р- Name Type типіндегі атаудың көмегімен Т типімен байланысты көрсеткіш типті айнымалы. Көрсеткіш типті айнымалыны тікелей айнымалылылардың сипаттамасы бөлімінде сипаттауға болады:

var p: ^T;

Көрсеткіш типті айнымалыны және осы көрсеткіш сүйенетін айнымалыны ажырату қажет. Мысалы, егер р, Т типті айнымалыға сілтеме болса, онда р^ – осы айнымалының мәні болып табылады.

Көрсеткіш типтегі айнымалылар үшін NIL стандарттық мәні енгізілген, ол көрсеткіштің ешқандай объектіге сүйенбейтінін білдіреді. NIL константы кез-келген көрсеткіш үшін қолданылады.

Көрсеткіштермен теңдікке және теңсіздікке тексеруден басқа ешқандай операциялар анықталмаған.

Көрсеткіш типті айнымалылар меншіктеу операторының сол жақ бөлігіне жазылуы мүмкін, бұл ретте оң жағында адресті анықтау функциясы Add r(^), немесе @Х, өрнегі болуы мүмкін, мұнда @ —адрес алудың бірорынды операциясы, Х – кез келген типтегі, соның ішінде процедуралық айнымалының аты.

Көрсеткіш типті айнымалылар енгізу-шығару тізімінің элементі бола алмайды.