Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
2014_2015 / LECT6_2_2015_new.pptx
Скачиваний:
11
Добавлен:
27.12.2015
Размер:
163.86 Кб
Скачать

линейные списки Ранее - основная компонента структуры данных - массив (обычный или массив указателей).

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

Линейная (список как линейная последовательность элементов, каждый из которых содержит указатели (ссылается) на своих соседей) или ветвящейся (деревья, графы).

Основная особенность: физическое размещение в памяти эл-тов списка не имеет никакого значения, все определяется наличием ссылок на него в других элементах и извне. У массива всегда есть «начало», а у списка по определению отсутствует фиксированная привязка к памяти.

Основной эл-т списка - составная (структурированная) переменная, содержащая собственно хранимые данные и указатели на соседей.

struct elem // определение структурированного типа

{

// значение элемента (хранимые данные)

int value;

elem *next;

 

 

// единственный указатель или

 

elem *next,*prev;

// два указателя или

 

elem *links[10];

// ограниченное кол-во указателей

elem **plinks;

 

// (не больше 10) или

 

 

// произвольное кол-во указателей

 

};

 

// (динамический массив)

 

 

 

 

 

 

 

 

Переменная такого типа может содержать 1, 2, не более

10 и произвольное (динамический массив) кол-во

указателей на аналогичные переменные, хотя это еще не

список, а описание его составляющих (эл-тов) как типа

данных. Из него следует только, что каждый из них

ссылается на аналогичные эл-ты, но никак нельзя

определить ни кол-ва таких переменных в структуре

данных,

ни

характера

связей

между

ними

(последовательный,

циклический,

произвольный)

конкретный тип структуры данных (линейный список,

дерево, граф) зависит от ф-ий, кот. с ней работают.

Списковые структуры данных - динамические, т.к.:

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

def динамич. в процессе работы программы. В зависимости от связей списки бывают:

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

Основные свойства списка:

Эл-т списка доступен в программе через указатель, кот. отражает функцио-нальное назначение эл-та списка в программе: 1, последний, текущий, предыдущий, новый и т.п. Между указателем и эл-том списка имеется такая же связь, как между индексом в массиве и эл-том массива;в программе список задается посредством заголовка – указателя на первый эл-т списка;

порядок следования эл-тов def последовательностью

связей между эл-тами. Изменение порядка следова-ния эл-тов (вставка, удаление) осуществляются изме-нением (переустановкой) указателей на соседние эл-ты.

логический (порядковый) номер эл-та списка также задается его естественной нумерацией в цепочке эл-тов;список – структура данных с последовательным доступом. Для получения n-го по счету эл-та необхо-димо последовательно пройти по цепочке от эл-та, на который имеется указатель (например, от заголовка);список удобен для использования именно как дина-

мическая структура данных: эл-ты списка обычно соз- даются как динамические переменные, а связи меж-ду ними устанавливаются программно (динамически);список обладает свойством локальности изменений: при вставке/удалении эл-та изменения касаются толь-ко текущего и его соседей (в массиве при вставке/уда-лении его эл-тов происходит физическое переме-щение (сдвиг) всех элементов от текущего до конца.

преимущества списков проявляются в таких структурах данных, где операции изменения порядка превалируют

над операциями доступа и поиска.

«обычные» (разомкнутые) списки имеют в качестве

ограничителя последовательности NULL-указательвозможен случай пустого списка, в котором заголовок - указатель на первый элемент также содержит значение NULL.

замкнутый круг: чтобы работать со структурой дан- ных, необходимо ее создать, а при создании нуж-но знать технологические приемы работы с ней.

Работа со списками осуществляется исключи-тельно через указатели. Каждый из них может перемещаться по списку (переустанавливаться с эл-та на эл-т), приобретая одну из смысловых интерпретаций – указатель на 1, последний, текущий, предыдущий, новый и т.п. эл-ты списка. Аналогия с массивом и индексом в нем, но при условии, что индекс меняется линейно, а не произвольно, а текущее количество заполненных эл-тов в массиве задано отдельной переменной. В результате получим следующие выражения, определяющие базовые действия со списком:

 

Список

Определение

struct list {int val;

 

list *next, *prev; };

Пустой список

list *ph=NULL;

Первый

list *p; p=ph;

Следующий

p->next

Предыдущий

p->prev

К следующему

p=p->next

К предыдущему

p=p->prev

Просмотр

for (p=ph; p!=NULL; p=p->next)

 

…p->val…

Проверка на последн

p->next ==NULL

К последнему

for (p=ph; p->next!=NULL;

 

p=p->next);

Новый

list *q = new list;

 

q->val = v;

Включить последним for (p=ph; p->next!=NULL;

 

p=p->next);

 

q->next=NULL; p->next=q;

Включить первым

q->next=ph; ph=q;

Массив

int A[100]; int n;

n=0;

Int i=0;

i+1

i-1

i++

i--

for (i=0; i<n; i++) …A[i]…

i==n-1 i=n-1

int v;

A[n++]=v;

for (i=n; i>0; i--)

Основная операция при работе с элементами массива

– « -> » выполняется в контексте: указатель на элемент - поле элемента списка.

сам список представляет собой множество связанных указателями переменных. В простейшем случае (для создания тестовых данных) можно - статический список: его эл-ты - обычные структурированные переменные, связи между ними инициализируются транслятором, и вся структура данных в программный код.

struct list { int val; list *next; }

a={0,NULL}, b={1,&a}, c={2,&b}, *ph = &c;

по условиям def переменных список создается «хвостом вперед». В двусвязном списке проблема «ссылок вперед» на еще неопределенные эл-ты решается: сначала переменные объявляются, как внешние, затем def и инициализируются.

struct list2 { int val; list *next,*prev;};

extern list2 a,b,c; // предварит def эл-тов списка list2 a={0,&b,NULL}, b={1,&c,&a}, c={2,NULL&b}, *ph = &c; // выделены «ссылки вперед»

Список может содержать ограниченное количество

эл-тов, взятых из массива. Связи устанавливаются

динамически, т. е. программой (используется, когда

заданное количество эл-тов образуют несколько

различных

динамических

структур

(например,

очередей), переходя из одной в другую).

 

list

A[100],*ph;

// Создать список эл-тов,

for (i=0; i<99; i++)

// размещ в статич массиве

{

A[i].next = A+i+1; // Адрес следующ вычисляется

}

A[i].val = i;

 

 

 

A[99].next = NULL;

 

 

 

ph = &A[0];

вариант

полезен

только в

том случае,

Но!!! Этот

когда 1 (по счету) эл-т списка остается таковым в процессе работы со списком. Т.к. заголовок передается по значению (как копия), то его изменение никак не сказывается на оригинале – истинном заголовке списка в main.

Необходимое изменение заголовка можно получить

другими способами:

· возврат измененного значения заголовка в виде результата функции; · передача указателя на заголовок списка

(указателя на указатель); · передача ссылки на заголовок. Напомним, что

ссылка - неявный указатель, использующий при работе синтаксис объекта, который «отображается» на соответствующий ему фактический параметр.

//---- включение в начало списка с изменением //заголовка: 1. Измененный указатель возвращается

list *Ins1(list *ph, int v) { list *q=new list;

q->val=v; q->next=ph; ph=q; return ph; }

// 2. Используется указатель на заголовок void Ins2(list **pp, int v)

{ list *q=new list;

q->val=v; q->next=*pp; *pp=q; }

Соседние файлы в папке 2014_2015