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

9 Дәріс тақырыбы: Ақпараттық құрылым. Сызықты тізім.

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

Төменде көрсетілген сияқты анықталған Node и Ptr екі типі бар делік. Node типінің әрбір айнымалысы үш компоненттен тұрады, атап айтқанда теңестіру кілтінен (key), келесі элементке сілтемеден (next) және біз осы жерде түсіретін қандай да бір басқа ақпараттан тұруы мүмкін:

TYPE Ptr = ^Node;

Node = RECORD key: INTEGER;

next: Ptr;

data: ...

END;

VAR p, q: Ptr;

Сурет. Тізімнің мысалы.

Суретте төбелер тізімі, р айнымалысы берілген бірінші элементке сілтеме берілген. Осындай тізіммен жасауға болатын ең қарапайым операция – оның басына бірқатар элемент қосу. Алдымен Node типті элемент жадыға орналастырылады және оған сілтеме q кейбір көмекші айнымалысын иеленеді. Осыдан кейін сілтемелерге жаңа мән беріледі де операция осымен аяқталады. Бұл былайша программаланады:

Allocate(q, SIZE(Node)); q^.next := p; p := q;

Бұл жерде осы операторлардың реті маңызды екеніне назар аударыңыз.

Элементті тізімнің басына қосу операциясы кез келген тізімді қалай қалыптастыруға болатынын бірден түсіндіреді: бос тізімнен бастау және басына жүйелеп элементтерді қосып отыру. Тұтастай тізім қалытастыру процесін келесідей фрагментпен береміз (байланыстырылатын элементтер саны – п):

p := NIL; (* басында тізім бос *)

WHILE n > О DO BEGIN

Allocate(q, SIZE(Node)); q^.next := p; p := q;

q^.key := n; n := n-1

END;

Бұл тізім құрудың ең қарапайым тәсілі, алайда онда тізімдегі элементтер реті олардың ену ретіне кері болады. Кейбір жағдайларда бұл орынсыз, сондықтан жаңа элементтерді тізімнің басына емес, соңына қосу қажет. Тізімнің соңын барлық тізімді қарай отырып оңай табуға болады, бірақ бұл белгілі бір шығындарды талап ететін өте аңғырт шешім. Соңғы элементті көрсететін q екінші сілтемесін енгізсе жеткілікті. Мұндай әдістің кемшілігі мынада, бірінші болып қосылатын элементтерді қалғандарына қарағанда басқаша өңдеу қажет.

Сілтемені анық пайдалану кейбір операцияларды барынша ықшамдайды, олар басқаша болғанда шиеленісіп кеткен болар еді. Қарапайым операциялардың арасында тізімдерде элементтерді қосу және шығарып тастау (тізімді ішінара өзгерту) және тізімді қарау орындалады. Тізімге қосу операциясын талдаудан бастаймыз.

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

q^.next := p^.next;

p^.next := q;

Егер көрсетілген p^ элементінен кейін емес, оның алдына қосу талап етілсе, онда байланыстардың бірбағытталған тізбегі жұмысты қиындатуы тиіс сияқты болады, өйткені осының алдындағы элементке “жол” жоқ. Алайда бұл проблема қарапайым түрде шешіледі.

Сурет. p^ элементінен кейін тізімге қосу

Сурет. p^ элементінің алдына тізімге қосу

Сәйкес схема суретте келтірілген (бұл жерде — key жаңа элементінің кілті = 8 деп ұйғарылады):

Allocate(q, SIZE(Node)); q^ := р^;

p^.key := k; p^.next := q;

" Шеберлік тәсіл" мынада, жаңа компонент шын мәнінде р^-ден кейін қосылады, бірақ кейін жаңа компонент пен р^ мәндерін «ауыстырады».

Сурет. Кейін басқа тізімге енгізе отырып, тізімнен

шығарып тастау

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

r : = p^.next; p^.next := r^.next; r^.next := q; q := r;

Көрсетілген элементтің өзін (одан кейінгіні емес) шығарып тастау қиынырақ, өйткені біз енгізген кездегідей проблемаға тап келеміз. Көрсетілгеннің алдындағы элементке өту мүмкін емес. Алайда енді қарапайым шешім белгілі: келесі элемент шығарылып тасталады, ал оның алдында оның мәні алға «ығысады». р-да келесі бар болса, яғни бұл соңғы элемент болмаса осылай жасауға болды.

Енді негізгі операция - тізім бойынша өтуді талқылаймыз. Тізімнің әрбір элементімен Р(х) операциясын орындау қажет деп шамалаймыз; тізімнің бірінші элементі – Р. Бұл есепті былайша орындауға болады:

WHILE р арқылы белгіленген тізім, DO бос емес

Р операциясын орындау;

келесіге өту

END;

Нақтылағаннан кейін бұл операция енді былайша беріледі:

WHILE р <> NIL DO

Р(р^) := p^.next

END;

Цикл операторының анықтамасынан және тізім құрылымынан Р басқалары үшін емес, тізімнің барлық элементтері үшін орындалатыны келіп шығады.

Барынша жиі қолданылатын операциялардың бірі - тізімнен х берілген кілті бар элементті іздеу. Массивтерден айырмашылығы бұл жағдайда іздестіру қатаң жүйелілікпен жүруі тиіс. Ол элементті тапқан кезде немесе тізімнің соңына дейін жеткен кезде аяқталады. Мұндай шарт мынаған келтіреді, конъюнкция екі қатынастан тұрады. Бұрынғыша тізімнің басы р сілтемесімен беріледі деп есептейміз:

WHILE (р <> NIL) and (p^.key <> х) DO p := p^.next;

р=NIL қатынасы р^ жоқ деп болжамдайды, демек, p^key<>x өрнегі анықталған жоқ. Сондықтан қатынастар тәртібі өте маңызды.