Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Konspekt_S__Chast_2.doc
Скачиваний:
34
Добавлен:
09.02.2015
Размер:
1 Mб
Скачать

Одномерные двунаправленные списки

Каждый элемент списка содержит два адресных поля PredиNext. ПолеPred содержит адрес предыдущего элемента списка (в первом элементе это поле равно0). ПолеNextсодержит адрес следующего элемента списка (в последнем элементе это поле равно0). Такая организация списка позволяет перемещаться по его элементам в двух направлениях.

Тип данных для элементов такого списка можно определить так:

struct t_Item

{

double Inf;

t_Item * Pred,

* Next;

};

Здесь предполагается, что информационное поле имеет тип double.

Для создания такого списка можно использовать следующую функцию:

t_Item *CreateList ( unsigned Length )

{

t_Item *Curr = 0, // Адрес очередного элемента списка

*Next = 0; // Адрес следующего за очередным элемента списка

// Начинаем создавать список с последнего элемента

for ( unsigned i = 1; i <= Length; ++ i )

{

// Создаем очередной элемент списка

Curr = new t_Item;

// В адресную часть записываем адрес следующего

// за очередным элемента списка

Curr->Next = Next;

if ( Next ) // Следующий элемент существует (Nextне равен 0)

// Очередной элемент с адресом Currявляется предыдущим

// элементом для элемента с адресом Next

Next->Pred = Curr;

// Запоминаем адрес очередного элемента в качестве

// следующего элемента для следующего шага цикла

Next = Curr;

}

// Для первого элемента списка адрес предыдущего элемента

// должен быть равен 0

Curr->Pred = 0;

// Возвращаем адрес последнего созданного элемента,

// как адрес первого элемента списка

return Curr;

}

Функции удаления списка DeleteList, доступа к элементам спискаListItem, определения длины списка LengthListи перемещения элементаMoveItemостаются такими же, как и для однонаправленного списка (необходимо только заменить идентификатор поляAdrнаNext). Остальные функции требуют небольшой коррекции, связанной с дополнительной обработкой адресного поляPred:

t_Item *InsItem( t_Item * &Beg, unsigned Index )

{

t_Item * Item = new t_Item;

if ( !Index || !Beg)

{

Beg->Pred = Item;

Item->Pred = 0;

Item->Next = Beg;

Beg = Item;

return Item;

}

t_Item * PredItem = Beg;

-- Index;

while ( PredItem->Next && ( Index -- ) )

PredItem = PredItem->Next;

Item->Pred = PredItem;

Item->Next->Pred = Item;

Item->Next = PredItem->Next;

PredItem->Next = Item;

return Item;

}

void DelItem( t_Item * &Beg, unsigned Index )

{

if ( Index >= LengthList ( Beg ) )

return;

t_Item * Item;

if ( !Index )

{

Item = Beg->Next;

delete Beg;

Beg = Item;

Beg->Pred = 0;

return;

}

Item = ListItem ( Beg, Index - 1, 0 );

t_Item * DItem = Item->Next;

Item->Next = DItem->Next;

Item->Next->Pred = Item;

delete DItem;

}

Многомерные списки

Стек

13. Знакомство с классами

13.1. Понятие класса

13.2. Пример создания класса

///////////////////////////////////////////////////////////////////////////////////////////

// Пример реализации класса для работы с одномерными //

// однонаправленными списками. //

// В этой реализации элементы списка индексируются, //

// начиная с 0. //

///////////////////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"

#include <iostream>

using namespace std;

///////////////////////////////////////////////////////

// Начало определения класса List //

///////////////////////////////////////////////////////

// Тип данных t_Infопределяет тип данных информационных частей

// элементов динамического списка. В этом примере в качестве

// информации, хранящейся в элементах списка, используется тип данных double.

// Если необходимо хранить в элементах списка данные другого типа,

// необходимо заменить тип double,

// на нужный тип данных. При этом необходимо скорректировать

// значение определенной ниже константы DefVal.

// Также, возможно, потребуется незначительная коррекция функций-членов

// класса, связанная с операциями с информационными частями элементов списка

typedef double t_Inf;

// Значение информационной части элементов списка, используемое по умолчанию

const t_Inf DefVal = 0;

// Структура t_Itemопределяет тип данных элемента списка

struct t_Item

{

t_Inf Inf; // Информационная часть - хранит полезную информацию

t_Item *Adr; // Адресное поле - хранит адрес следующего элемента списка

};

class List

{

// Закрытые члены-данные класса

t_Item *Items, // Адрес первого элемента

*End; // Адрес последнего элемента

// Закрытые члены-функции класса

bool ItemExists(unsigned Index); // Проверка наличия элемента по его индексу

t_Item *Item(unsigned Index); // Получение адреса элемента по его индексу

t_Item *ExtractItem(unsigned Index); // Выделение элемента из списка по его

// индексу

public:

// Открытые члены-данные класса

unsigned Count; // Количество элементов в списке

// Открытые члены-функции класса

List(unsigned N = 0); // Коструктор класса.N - количество элементов списка

~List(void); // Деструктор класса

void Create(unsigned N = 0); // Создание нового списка изNэлементов

void Clear(); // Удаление элементов списка

t_Inf GetItem(unsigned Index); // Получение информационной части элемента

// по его индексу

void PutItem(unsigned Index, t_Inf Val); // Присвоение значения Val элементу

// с индексом Index

void AddItem(t_Inf Val = DefVal); // Добавление элемента в конец списка

// (Val- значение информационной части)

void DelItem(unsigned Index); // Удаление из списка элемента с индексомIndex

void InsItem(unsigned Index, t_Inf Val = DefVal); // Вставка нового элемента

// в позицию Index

void MoveItem(unsigned OldIndex, unsigned NewIndex); // Перестановка элемента

// с индексом OldIndex

// на позицию NewIndex

};

// ----------------------------------------------

List::List ( unsigned N )

// Конструктор класса DinArr. N - количество элементов в списке.

// Автоматически вызывается при создании объекта

{

// Вначале список пустой:

Count = 0;

Items = 0;

End = 0;

// Создает в динамической области список из N элементов:

Create ( N );

}

// ----------------------------------------------

List::~List ( )

// Деструктор класса DinArr. Автоматически вызывается при уничтожении объекта

{

// При уничтожении объекта освобождает динамическую память от списка

Clear ( );

}

// ----------------------------------------------

void List::Create ( unsigned N )

// Удаляет существующий список и создает новый список из N элементов

{

if ( Count ) // Если в списке есть элементы, то удаляем их

Clear ( );

for (unsigned i = 1; i <= N; ++ i) // Добавляем к пустому списку N элементов

AddItem ( ); // Добавляем в конец списка новый элемент

}

// ----------------------------------------------

void List::Clear ( )

// Очищает динамическую память от списка из Count элементов

{

unsigned N = Count;

for (unsigned i = 1; i <= N; ++ i) //Nраз удаляем из списка первый

// элемент (элемент с индексом 0)

DelItem ( 0 );

}

// ----------------------------------------------

bool List::ItemExists ( unsigned Index )

// Проверка наличия элемента с индексом Index (значения индекса от 0 до Count - 1)

{

if (Index >= Count) // Если значение индекса некорректное

{

// Выводим сообщение об ошибке

cout << "Элемент с индексом " << Index << " отсутствует!\n";

return 0; // Возвращаем значение false

}

return 1; // Элемент с заданным индексом существует. Возвращаем значение true

}

// ----------------------------------------------

t_Item *List::Item ( unsigned Index )

// Функция возвращает адрес элемента с индексом Index (значения индекса

// от 0 до Count- 1). Если такого элемента нет, выводится сообщение об

// ошибке и функция возвращает нулевой адрес

{

if ( !ItemExists ( Index ) ) // Если элемент с заданным индексом

// отсутствует, выводим сообщение об ошибке,

return 0; // возвращаем нулевой адрес

if ( Index == Count – 1 ) // Если нужен последний элемент списка,

return End; // возвращаем адрес последнего элемента

// Начиная с начала списка перемещаемся по списку до элемента

// с заданным индексом

t_Item *Curr = Items; // Делаем адрес очередного элемента равным

// адресу первого элемента

while ( Index -- ) // Цикл продолжаетсяIndexраз

Curr = Curr->Adr; // Делаем адрес очередного элемента

// равным адресу следующего элемента

return Curr; // Возвращаем адрес элемента с заданным индексом

}

// ----------------------------------------------

t_Inf List::GetItem ( unsigned Index )

// Функция возвращает информационную часть элемента с индексом Index,

// если такой элемент имеется. Если такого элемента нет, выводится

// сообщение об ошибке, и функция возвращает значение

// информационной части равное DefVal

{

t_Item *Curr = Item ( Index ); // Получаем адрес элемента с заданным индексом

if ( !Curr ) // Если адрес нулевой

return DefVal; // Возвращаем значение по умолчанию

return Curr->Inf; // Возвращаем значение информационной части

}

// ----------------------------------------------

void List::PutItem ( unsigned Index, t_Inf Val )

// Функция устанавливает значение информационной части элемента

// с индексом Index, если такой элемент имеется, в значениеVal.

// Если такого элемента нет, выводится сообщение об ошибке,

// а информационная часть элемента остается без изменения

{

t_Item *Curr = Item ( Index ); // Получаем адрес элемента с заданным индексом

if ( !Curr ) // Если адрес нулевой

return; // Выходим из функции

Curr->Inf = Val; // Информационной части найденного элемента

// присваиваем значение Val

}

// ----------------------------------------------

void List::AddItem ( t_Inf Val )

// Функция добавляет новый элемент в конец списка и

// делает значение информационной части этого элемента равной Val

{

t_Item *NewItem = new t_Item; //NewItem- адрес нового созданного

// элемента списка

NewItem->Inf = Val; // Присваиваем информационной части этого

// элемента значение Val

NewItem->Adr = 0; // Поскольку элемент добавляется в конец списка,

// в его адресную часть заносим 0

if (Count) // Если в списке уже были эементы (Count> 0),

End->Adr = NewItem; // адресной части последнего элемента

// присаиваем адрес нового элемента

else // Иначе (Count= 0 - список был пуст)

Items = NewItem; // делаем адрес первого элемента списка

// равным адресу нового элемента

End = NewItem; // Теперь адрес последнего элемента списка

// делаем равным адресу добавленного элемента

++ Count; // Увеличиваем количество элементов списка на 1

}

// ----------------------------------------------

t_Item *List::ExtractItem ( unsigned Index )

// Функция выделяет элемент списка с индексом Index, исключая его из списка,

// но не удаляет его из динамической памяти. Возвращает адрес

// выделенного элемента, если такой элемент есть. Если такого элемента нет –

// выводит сообщение об ошибке и возвращает нулевой адрес

{

if ( !ItemExists ( Index ) ) // Если элемент с заданным индексом отсутствует,

// выводим сообщение об ошибке,

return 0; // возвращаем нулевой адрес

t_Item *DItem, // Переменная для адреса выделяемого элемента

*Pred = 0; // Переменная для адреса элемента

// предшествующего выделяемому

if ( Index == 0 ) // Если выделяется первый элемент списка,

{

DItem = Items; // адрес выделяемого элемента делаем равным адресу

// первого элемента списка,

Items = Items->Adr; // изменяем адрес первого элемента равным адресу

// следующего элемента

}

else // Иначе (выделяется не первый элемент списка)

{

Pred = Item ( Index – 1 ); // находим адрес элемента, который расположен

// перед удаляемым,

DItem = Pred->Adr; // делаем адрес выделяемого элемента равным

// адресной части предыдущего,

Pred->Adr = DItem->Adr; // и в адресную часть предыдущего элемента

// записывем адрес элемента, следующего

// за выделяемым (тем самым исключаем

// выделяемый элемент из списка).

}

if ( DItem == End ) // Если выделяемый элемент является

// последним элементом списка,

End = Pred; // корректируем адрес последнего элемента, делая его

// равным адресу предыдущего

-- Count; // Уменьшаем количество элементов в списке на 1

return DItem; // Возвращаем адрес выделенного элемента

}

// ----------------------------------------------

void List::DelItem ( unsigned Index )

// Функция удаляет элемент с индексом Index из списка и освобождает

// от него динамическую память. Если такого элемента нет, то выводится

// сообщение об ошибке, а список остается без изменений

{

t_Item *DItem = ExtractItem ( Index ); // Выделяем заданный элемент из списка

if ( DItem ) // Если адрес выделенного элемента не равен 0,

delete DItem; // освобождаем от него динамическую память

}

// ----------------------------------------------

void List::InsItem ( unsigned Index, t_Inf Val )

// Функция создает и вставляет новый элемент в список в позицию с индексом Index.

// Val - значение информационной части этого элемента. ЕслиIndexуказывает

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

// в конец списка

{

if ( Index > Count ) // Если указан слишком большой индекс,

// корректируем его так,

Index = Count; // чтобы новый элемент был вставлен в конец

// списка

t_Item *NewItem = new t_Item; // Создаем новый элемент (его адрес -NewItem)

NewItem->Inf = Val; // Формируем информационную часть

// вставляемого элемента

if ( Index == 0 ) // Если элемент вставляется в начало списка,

{

NewItem->Adr = Items; // присоединяем новый элемент к началу

// списка и

Items = NewItem; // изменяем адрес первого элемента списка

}

else // Иначе (элемент должен быть не первым)

{

t_Item *Pred = Item ( Index – 1 ); // находим адрес элемента, после

// которого должен быть вставлен

// новый элемент,

NewItem->Adr = Pred->Adr; // в адресную часть нового элемента

// заносим адрес следующего элемента,

Pred->Adr = NewItem; // в адресную часть предыдущего

// элемента заносим адрес нового

// элемента

}

if ( Index == Count ) // Если новый элемент был вставлен в конец списка,

End = NewItem; // корректируем адрес последнего элемента, делая

// его равным адресу нового элемента

++ Count; // Увеличиваем количество элементов списка на 1

}

// ----------------------------------------------

void List::MoveItem ( unsigned OldIndex, unsigned NewIndex )

// Функция перемещает элемент с индексом OldIndex на позицию с индексом

// NewIndex. Если элемента с индексомOldIndexне существует, выводится ошибка

// и список не меняется. Если неверно указан новый индекс (NewIndex>Count),

// то элемент переставляется в конец списка

{

t_Item *MItem = ExtractItem ( OldIndex ); // Выделяем перемещаемый элемент из

// списка

if (MItem) // Если перемещаемый элемент найден,

{

InsItem(NewIndex, MItem->Inf); // вставляем новый элемент в позицию

// NewIndex, а информационную часть

// для него берем из перемещаемого

// элемента, и

delete MItem; // удаляем выделенный элемент из

// динамической памяти

}

}

// ----------------------------------------------

/////////////////////////////////////////////////////

// Конец определения класса List //

/////////////////////////////////////////////////////

// Остальной код не имеет отношения к определению класса,

// а служит для иллюстрации использования созданного класса

void WriteArr ( List &A )

// Функция выводит на экран значения информационных полей элементов списка А

{

for ( unsigned i = 0; i < A.Count; ++ i )

cout << A.GetItem ( i ) << ' '; // Выводим на экран значение

// информационной части элемента

// с индексом iсписка А

cout << endl;

}

int _tmain ( int argc, _TCHAR* argv [ ] )

{

setlocale ( 0, "" );

List Arr ( 10 ); // Создаем список на 10 элементов

// В цикле заполняем информационные части всех элементов списка

// значениями, равными индексам этих элементов

for ( unsigned i = 0; i < Arr.Count; ++ i )

Arr.PutItem ( i, i );

WriteArr ( Arr ); // На экране видим: 0 1 2 3 4 5 6 7 8 9

// В цикле добавляем в конец списока еще 5 элементов, информационные части

// которых заполняются значениями, от 10 до 14 - Arr.AddItem(i+ 10 )

for ( unsigned i = 0; i < 5; ++ i )

Arr.AddItem ( i + 10 );

WriteArr ( Arr ); // На экране видим: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14

Arr.MoveItem ( 10, 2 ); // Перемещаем элемент с индексом 10 в позицию

// с индексом 2

WriteArr ( Arr ); // На экране видим: 0 1 10 2 3 4 5 6 7 8 9 11 12 13 14

system ( "pause" );

return 0;

}

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]