Одной из наиболее общих математических абстракций является понятие алгебраической системы < А, О, R >, где
Если операций нет - модель (структура). Если отношений нет - универсальная алгебра.
Математическая структура есть одно или несколько множеств , элементы которых находятся в некоторых отношениях .
Структура данных - модель данных в виде математической структуры.
Примеры:
Значения представлены в виде объектов классов, являющихся производными из одного общего базового класса.
В поле значения звена списка размещается указатель на объект значение.
Для повышения общности схемы реализации будем использовать вместо величины NULL константу pStop для фиксации ситуаций, в которых указатель не содержит адрес какого-либо звена списка.
Информационные методы:
Методы доступа к значениям в списке:
Методы навигации по списку (итератор):
Вставка звеньев:
Удаление звеньев:
Схема стуктуры - структура данных , соответствующая рассмотрению структуры как переменной величины.
Алгоритм соответствует схеме структуры
Экземпляр - структура данных с установленными значениями элементов.
Вычисление соответствует экземпляру
Структуры с бинарными отношениями допускают случай графического изображения
Плекс - структура представления для выражений самого общего вида (линия – операция, точки – операнды)
Пример:
Структуры данных являются операндами операций обработки.
Результаты вычислений также являются структурами, модель которых может как совпадать, так и отличаться от структуры исходных данных.
Анализ примера:
Динамическая структура - математическая структура, которой соответствует частично-упорядоченное (по включению) базовое множество M, элементы которого являются структурами данных. При этом отношения включения индуцируются операциями преобразования структуры данных.
Примеры:
Средства поддержки динамической структуры - программы реализующие отношения включения
Динамические структуры данных – это структуры данных, память под которые выделяется и освобождается по мере необходимости.
Свойства:
Выгодно использовать, если:
Может быть эта схема здесь не нужна
Для имитации звеньев могут быть использованы два массива один из которых используется для хранения значений, другой- для хранения индексов следующих элементов. В этом случае, звено есть элемент массивов с одинаковым индексом, адрес (имя) звена – индекс массивов.
С использованием ООП звено может быть представлено в виде объекта. Образ памяти, выделенной для хранения структур данных, в это случае будет представлять массив звеньев-объектов.
Class TLink
{
public:
Int value; //значение
Int next; //индекс следующего звена
protected:
TLink();
};
TLinkMem[MemLimit];
Множество – набор элементов
int TBitField::GetBit(const int n) const
{
if ((n > -1) && (n < BitLen))
return (pMem[(GetMemIndex(n))] & (GetMemMask(n)));
else return(0);
}
void TBitField::SetBit(const int n)
{ if ((n > -1) && (n < BitLen))
pMem[(GetMemIndex(n))] |= GetMemMask(n);
}
void TBitField::ClrBit(const int n)
{ if ((n > -1) && (n < BitLen))
pMem[(GetMemIndex(n))] &= ~GetMemMask(n);
}
TBitField TBitField::operator|(const TBitField& bf)
{
int i, len;
if (BitLen > bf.BitLen)
len = BitLen;
else len = bf.BitLen;
TBitField temp(len);
for (i = 0; i < MemLen; i++)
temp.pMem[i] = pMem[i];
for (i = 0; i < bf.MemLen; i++)
temp.pMem[i] |= bf.pMem[i];
return temp;
}
TBitField TBitField::operator&(const TBitField &bf)
{
int i, len;
if (BitLen < bf.BitLen)
len = BitLen;
else len = bf.BitLen;
TBitField temp(len);
for (i = 0; i < MemLen; i++)
temp.pMem[i] = pMem[i];
for (i = 0; i < bf.MemLen; i++)
temp.pMem[i] &= bf.pMem[i];
return temp;
}
TBitField TBitField::operator~(void)
{
TBitField temp(BitLen);
for (int i = 0; i < MemLen; i++)
temp.pMem[i] = ~pMem[i];
return temp;
}
Универс U – множество всех элементов.
Конкретизация (допущения и ограничения):
Битовое поле представляет из себя массив int
Бред, который нужно исправить:
Бред, который нужно исправить:
Структура хранения данного типа (звенья, сцепление, барьер, переменная связи) называется линейным или односвязным списком.
Среда выполнения обеспечивает динамически–распределяемую область памяти:
Базисное множество - структуры
Неоднозначность операций в том что можем вставлять как в голову так и в хвост и после текущего и удалять можно тоже по-разному.
Для показа неоднозначности взять простой односвязный линейный список с головой и двусвязный с хвостом и головой.
Множество – набор элементов
int TBitField::GetBit(const int n) const
{
if ((n > -1) && (n < BitLen))
return (pMem[(GetMemIndex(n))] & (GetMemMask(n)));
else return(0);
}
void TBitField::SetBit(const int n)
{ if ((n > -1) && (n < BitLen))
pMem[(GetMemIndex(n))] |= GetMemMask(n);
}
void TBitField::ClrBit(const int n)
{ if ((n > -1) && (n < BitLen))
pMem[(GetMemIndex(n))] &= ~GetMemMask(n);
}
TBitField TBitField::operator|(const TBitField& bf)
{
int i, len;
if (BitLen > bf.BitLen)
len = BitLen;
else len = bf.BitLen;
TBitField temp(len);
for (i = 0; i < MemLen; i++)
temp.pMem[i] = pMem[i];
for (i = 0; i < bf.MemLen; i++)
temp.pMem[i] |= bf.pMem[i];
return temp;
}
TBitField TBitField::operator&(const TBitField &bf)
{
int i, len;
if (BitLen < bf.BitLen)
len = BitLen;
else len = bf.BitLen;
TBitField temp(len);
for (i = 0; i < MemLen; i++)
temp.pMem[i] = pMem[i];
for (i = 0; i < bf.MemLen; i++)
temp.pMem[i] &= bf.pMem[i];
return temp;
}
TBitField TBitField::operator~(void)
{
TBitField temp(BitLen);
for (int i = 0; i < MemLen; i++)
temp.pMem[i] = ~pMem[i];
return temp;
}
Универс U – множество всех элементов.
Конкретизация (допущения и ограничения):
PTDatLink pTemp;
pTemp = new TDatLink();
pTemp-> SetDatValue(Val);
pTemp->SetNextLink(pFirst);
pFirst = pTemp;
PTDatLink pTemp = pFirst;
Val = pFirst->GetDatValue();
pFirst = pFirst->GetNextLink();
delete pTemp;
Перепаковка памяти (перепаковка) - процедура динамического перераспределения памяти путем переписи части хранимых значений в другую область
Перепаковка обеспечивает эффективное использование одного ресурса ЭВМ (памяти) за счет другого ресурса (времени).
Управление памятью - выполнение функций анализа свободной памяти, планирование размещения структур, переписывание структур
Система управления памятью - комплекс программ, реализующих управление памятью
Необходимость перепаковки обуславливается принятым способом реализации отношений следования.
Свойства:
Выполняется при попытке вставки нового значения в стек s, у которого отсутствует свободная память:
Для гарантированного выделения свободной памяти стеку s при наличии только одного свободного элемента памяти (случай 2), выполним:
Для хранения элементов можно выделить непрерывный вектор памяти размера 3*n-2
Адрес
Подход 1:
Подход 2:
Подход 3:
Подход 4:
Бред, который нужно исправить
это же треугольные матрицы, в матрице рамером n * n n ^ 2 ячееки, нулевые мы не храним
поиск будет О(1)т.к. мы просто индекс считаем грубо говоря,если с матрицами типо A + B,где а и б матрицы, то нам нужно каждый элемент с каждым сложитьсоотв. это будет такой же O как и у памятивычитание аналогично а как скалярное произведение матриц-сумма попарных произведений?
Статическое распределение памяти - распределение памяти до начала процесса вычислений.
Динамическое распределение памяти - распределение памяти в ходе выполнения программы.
Перепаковка памяти (перепаковка) - процедура динамического перераспределения памяти путем переписи части хранимых значений в другую область памяти.
Формирование гипотез происходит в результате теоретического анализа модели решаемой задачи или может быть выполнено на основе статистических данных, получаемых в ходе вычислительных экспериментов с проектируемой программной системой.
Гипотеза 1: Стеки используются с одинаковой интенсивностью, память разделяется между стеками поровну.
Гипотеза 2: Интенсивность использования стеков различается.
Сохранение локальных тенденций роста:
правило распределение памяти для стеков в соответствии с их показателями роста
Гипотеза 3: Использование вероятностных предположений о поведении стеков.
Множество – набор элементов
int TBitField::GetBit(const int n) const
{
if ((n > -1) && (n < BitLen))
return (pMem[(GetMemIndex(n))] & (GetMemMask(n)));
else return(0);
}
void TBitField::SetBit(const int n)
{ if ((n > -1) && (n < BitLen))
pMem[(GetMemIndex(n))] |= GetMemMask(n);
}
void TBitField::ClrBit(const int n)
{ if ((n > -1) && (n < BitLen))
pMem[(GetMemIndex(n))] &= ~GetMemMask(n);
}
TBitField TBitField::operator|(const TBitField& bf)
{
int i, len;
if (BitLen > bf.BitLen)
len = BitLen;
else len = bf.BitLen;
TBitField temp(len);
for (i = 0; i < MemLen; i++)
temp.pMem[i] = pMem[i];
for (i = 0; i < bf.MemLen; i++)
temp.pMem[i] |= bf.pMem[i];
return temp;
}
TBitField TBitField::operator&(const TBitField &bf)
{
int i, len;
if (BitLen < bf.BitLen)
len = BitLen;
else len = bf.BitLen;
TBitField temp(len);
for (i = 0; i < MemLen; i++)
temp.pMem[i] = pMem[i];
for (i = 0; i < bf.MemLen; i++)
temp.pMem[i] &= bf.pMem[i];
return temp;
}
TBitField TBitField::operator~(void)
{
TBitField temp(BitLen);
for (int i = 0; i < MemLen; i++)
temp.pMem[i] = ~pMem[i];
return temp;
}
Универс U – множество всех элементов.
Конкретизация (допущения и ограничения):
Сцепление - способ задания отношения следования, в котором фиксация месторасположения следующего элемента производится путем запоминания соответствующего адреса памяти (пары, хранящие и , сцеплены адресными указателями)
Сверху - логический порядок звеньев Снизу - физический порядок звеньев
Основные алгоритмические моменты метода сложения полиномов operator+ состоят в следующем:
TList TList::plus(TList list)
{
pLink tmp, ptr, temp, prev1, prev2, cnt, n;
tmp = prev1 = cnt = Head;
ptr = prev2 = temp = n = list.Head;
size = this->GetSize();
int flag = 1;
while ((tmp->pNext->data != -1) && (ptr->pNext->data != -1))
{
if ((ptr->data == -1) && (tmp->data == -1))
{
ptr = ptr->pNext;
tmp = tmp->pNext;
temp = temp->pNext;
cnt = cnt->pNext;
}
if ((tmp->data > ptr->data) && (flag == 1))
{
ptr = ptr->pNext;
this->insCurrent(temp->data, temp->data2);
list.deleteCurrent(temp->data);
temp = ptr;
flag = 0;
}
if ((tmp->data < ptr->data) && (flag == 1))
{
ptr = ptr->pNext;
tmp = tmp->pNext;
this->insCurrent(temp->data, temp->data2);
list.deleteCurrent(temp->data);
temp = ptr;
flag = 0;
}
if ((tmp->data == ptr->data) && (flag == 1))
{
this->insCurrent(tmp->data, tmp->data2 + ptr->data2);
if ((tmp->data2 + ptr->data2) == 0)
{
while ((prev1->pNext != tmp) && (n->pNext != ptr))
{
prev1 = prev1->pNext;
n = n->pNext;
}
tmp = tmp->pNext;
ptr = ptr->pNext;
this->deleteCurrent(cnt->data);
list.deleteCurrent(temp->data);
cnt = tmp;
temp = ptr;
}
flag = 0;
}
flag = 1;
}
if ((ptr->data == tmp->data) && (ptr->data != -1)
&& (tmp->data != -1))
{
this->insCurrent(ptr->data, tmp->data2 + ptr->data2);
if ((tmp->data2 + ptr->data2) == 0)
{
while ((prev1->pNext != tmp) && (n->pNext != ptr))
{
prev1 = prev1->pNext;
n = n->pNext;
}
tmp = tmp->pNext;
ptr = ptr->pNext;
this->deleteCurrent(cnt->data);
list.deleteCurrent(temp->data);
list.size--;
cnt = tmp;
temp = ptr;
}
}
if (ptr->data != tmp->data)
{
if (tmp->data == -1)
while (ptr->pNext != list.Head)
{
this->insCurrent(ptr->data, ptr->data2);
ptr = ptr->pNext;
list.size--;
}
}
if ((ptr->data != -1) && (tmp->data != -1))
{
this->insCurrent(ptr->data, ptr->data2);
list.deleteCurrent(ptr->data);
}
return *this;
}
В стандарте языка С++ предусматривается наличие в среде программирования стандартной библиотеки шаблонов (Standard Template Library, STL).
Основные понятия библиотеки STL.
Библиотека включает в свой состав большое количество контейнеров, представляющих собой структуры данных, в которых могут храниться объекты.
В числе имеющихся контейнеров:
vector<T>
- вектор переменного размераlist<T>
- двусвязный списокqueue<T>
- очередьstack<T>
- стекdeque<T>
- декpriority_queue<T>
- приоритетная очередьset<T>
- множествоmultiset<T>
- множество с повторением элементовmap<key,val>
- ассоциативный массив (таблица)multimap<key,val>
- ассоциативный массив с повторением ключейДля быстрого и эффективного построения вычислительных процедур, библиотека обеспечивает итераторы для всех видов контейнеров, которые представляют унифицированный механизм последовательного доступа к элементам контейнеров.
Общая схема:
<класс-контейнер>::iterator Iter;
- объявление итератораIter = <объект-контейнер>.begin();
- установка на первый элементIter != <объект-контейнер>.end();
- проверка на завершение++Iter
– переход к следующему элементуВ зависимости от типа контейнера, итератор может обеспечивать прямой доступ, быть одно- или дву- направленным, предназначенным только для чтения или записи и др. Библиотека содержит для контейнеров большое количество реализованных обобщенных алгоритмов.
В числе таких алгоритмов:
for_each()
- вызвать функцию для каждого элемента,find()
- найти первое вхождение элементаfind_if()
- найти первое соответствие условиюcount()
- подсчитать число вхождений элементаcount_if()
- подсчитать число соответствий условиюreplace()
- заменить элемент новым значениемcopy()
- скопировать элементыunique_copy()
- скопировать только различные элементыsort()
- отсортировать элементыmerge()
- объединить отсортированные последовательности и дрПечать текста: схема обхода
while (1)
{
if ( pLink != NULL )
{
cout << pLink->Str; // обработка звена
St.push(pLink); // запись в стек
pLink = pLink->pDown; // переход на подуровень
}
else if ( St.empty() )
break;
else
{
pLink = St.top();
St.pop(); // выборка из стека
pLink = pLink->pNext; // переход по тому же уровню
}
}
Ввод текста из файла: уровень текста в файле можно выделить строками специального вида (например, скобками '{' и '}').
Общая схема алгоритма:
повторить:
ввод строки
ЕСЛИ '}' ТО Завершить
ЕСЛИ '{' ТО Выполнить рекурсивно Ввод_текста
Добавить строку на том же уровне
Для копирования текста необходимо предварительно скопировать разделы текста, на которые указывают указатели pDown
и pNext
Алгоритмы обхода NDT или DNT.
Каждое звено текста копируется за два прохода:
pDown
(подуровень уже скопирован)Str
значения Copy (для распознания звена при попадании на него при втором проходе)pNext
указателя на звено-оригинал (для возможности последующего копирования текста исходной строки)Str
и pNext
При удалении разделов текста для освобождения звеньев следует учитывать следующие моменты:
Память, занимаемая удаляемым текстом, не освобождается, а удаление текста фиксируется установкой указателей в состояние NULL (например, pFirst=NULL
).
Возможный подход доступа к системе управления памятью – разработка специальной системы управления при помощи перегрузки операторов new
и delete
.
TTextLink
создается статическая переменная MemHeader
типа TTextMem
class TTextMem{
PTTextLink pFirst; // первое звено
PTTextLink pLast; // последнее звено
PTTextLink pFree; // первое свободное
InitMemSystem
класса TTextLink
void TTextLink::InitMemSystem(int size) // инициализация памяти
{
char Line[100];
char *tmp = new char[sizeof(TTextLink)*size];
MemHeader.pFirst = (PTTextLink)new char[sizeof(TTextLink)*size];
MemHeader.pFree = MemHeader.pFirst;
MemHeader.pLast = (PTTextLink)tmp + size - 1;
PTTextLink pLink = MemHeader.pFirst;
for (int i = 0; i < size - 1; i++, pLink++) // размер памяти
pLink->pNext = pLink + 1;
pLink->pNext = nullptr;
}
void* TTextLink::operator new(size_t size) // выделение звена
{
PTTextLink pLink = MemHeader.pFree;
if (MemHeader.pFree != nullptr)
MemHeader.pFree = pLink->pNext;
return pLink;
}
delete
звено включается в список свободных звеньевvoid operator delete (void *pM)
{
PTTTextLink pLink = (PTTTextLink)pM;
pLink->pNext = MemHeader.pFree;
MemHeader.pFree = pLink;
}
(при сбалансированном дереве) (при вырожденном дереве)
Из последнего выражения следует:
умножим на
подставим (3) в (1)
Отсюда можно получить (проверяется подстановкой):
(формула Эйлера, )
Пусть есть средняя длина пути для идеально сбалансированного дерева
Текст – линейная последовательность символов
Текст – линейная последовательность слов (слово - линейная последовательность символов)
Текст – линейная последовательность строк, строки состоят из слов, слова – из символов и т.д.
Математическая модель текста – иерархическая структура представления (дерево).
Единый тип звена:
typedef Tlink *PTLink;
class TLink
{
PTLink pNext;
int Atom; // =1 – звено-атом
union {PTLink pDown; char Symb;}
Таблица с вычисляемым входом (хеш-таблица) – это таблица, элементы которой располагаются в соответствии с некоторой функцией расстановки (хеш-функцией)
Функция расстановки f (ключ) вычисляет для каждого элемента таблицы по его ключу номер (позицию) элемента в массиве.
0…N–1
или 1…N
Организация прямого доступа в рассмотренном виде приводит к неэффективному использованию памяти - требуется больше памяти (М >> 1) - количество используемых ключей, как правило, существенно меньше теоретически возможного набора
Размер памяти для представления таблицы значительно меньше возможного количества имен (M << N), и, как результат, получаемые по ключам числовые значения необходимо преобразовывать к диапазону номеров (адресов) строк памяти
Функция (хеширования, перемешивания, рассеивания) расстановки (hash - мешанина, путаница) - функция преобразования значения ключа к номеру (адресу) строки памяти для хранения записи H : K -> L (L = (0, ..., M - 1))
Таблицы с вычислимыми адресами (хеш-таблицы, перемешиваемые таблицы) - таблицы, представление которых организуется при использовании функции расстановки
Метод цепочек
Замечания к открытому перемешиванию как способу размешения коллизий:
Широко используемый подход для разрешения коллизий - метод цепочек, когда все записи, для которых функция хеширования определяет одно и тоже значение,представляются в виде линейного списка.
Открытое перемешивание еще называют закрытым хэшированием, метод цепочек - открытое хэширование.
Печать текста: схема обхода
while (1)
{
if (pLink != NULL)
{
cout << pLink->Str; // обработка звена
St.push(pLink); // запись в стек
pLink = pLink->pDown; // переход на подуровень
}
else if (St.empty())
break;
else
{
pLink = St.top();
St.pop(); // выборка из стека
pLink = pLink->pNext; // переход по тому же уровню
}
}
Ввод текста из файла: уровень текста в файле можно выделить строками специального вида (например, скобками '{' и '}')
Общая схема алгоритма:
повторить:
ввод строки
ЕСЛИ '}' ТО Завершить
ЕСЛИ '{' ТО Выполнить рекурсивно Ввод_текста
Добавить строку на том же уровне
Реализация итератор:
int TText::Reset(void) // Установка на корневое звено текста
{
pCurrent = pFirst;
if (pCurrent != nullptr)
{
St.push(pCurrent);
if (pCurrent->pNext != nullptr)
St.push(pCurrent->pNext);
if (pCurrent->pDown != nullptr)
St.push(pCurrent->pDown);
}
}
bool TText::IsTextEnded(void) const // Стек пуст?
{
return St.empty();
}
bool TText::GoNext(void) // Переход к следующему звену текста
{
if (!IsTextEnded())
{
pCurrent = St.top();
St.pop();
if (pCurrent != pFirst)
{
if (pCurrent->pNext != nullptr)
St.push(pCurrent->pNext);
if (pCurrent->pDown != nullptr)
St.push(pCurrent->pDown);
}
}
return IsTextEnded();
}
Формат записи выражения:
'='
: A+(B-C)*D-F/(G+H)=
Алгоритм:
'*' '/' (3), '+' '-' (2), '(' (1), '=' (0)
Пусть выражение имеет вид: A + (B - C) * D - F / (G + H)=
void TText::DelDownLine(void) // Удаление строки в подуровне
{
if (pCurrent == nullptr)
SetRetCode(TextErr);
else if (pCurrent->pDown == nullptr)
SetRetCode(TextNoDown);
else if (pCurrent->pDown->IsAtom())
pCurrent->pDown = pCurrent->pDown->pNext;
}
void TText::InsDownLine(string str) // Вставка строки в подуровень
{
if (pCurrent == nullptr)
SetRetCode(TextErr);
else
{
TStr buf; // typedef char TStr[TextLineLength];
strcpy(buf, str.c_str());
pCurrent->pDown = new TTextLink(buf, pCurrent->pDown, nullptr);
}
}
void TTreeTable :: DelRecord ( TKey k ) { // удалить запись
if ( FindRecord(k) == NULL )
SetRetCode(TabNoRec); // SKIP_ON
else {
SetRetCode(TabOK);
PTTreeNode pNode = *ppRef;
if ( pNode->pRight == NULL )
*ppRef = pNode->pLeft; // один потомок слева
else if ( pNode->pLeft == NULL )
*ppRef = pNode->pRight; // один потомок справа
else { // два потомка - поиск крайнего справа у левого поддерева
PTTreeNode pN = pNode->pLeft, *ppR = &pNode->pLeft;
while ( pN->pRight != NULL ) {
ppR = &pN->pRight; pN = *ppR;
} // вместо удаления pNode удается pN
pNode->pValue = pN->pValue; // значение в pNode
pNode->Key = pN->Key;
pNode = pN; *ppR = pN->pLeft; // обход удаляемого pN
}
delete pNode;
}// SKIP_OFF
}
Схема определения оптимального значения : - Выполняется оценка величины на последовательных друг за другом отрезках времени
где - параметр схемы адаптации
Идеально сбалансированное дерево - дерево, у которого для каждого его узла количество узлов в левом и правом поддеревьях различаются не более чем на 1.
Сбалансированное дерево - дереао, у которого для каждого узла высота левого и правого поддеревьев различаются не более,чем на 1(АВЛ-деревья).
Идеально сбалансированные деревья являются сбалансированными. Операции обработки сбалансированных деревьев имеют сложность log2N.(поиск, вставка, удаление)
(при сбалансированном дереве) (при вырожденном дереве)
Из последнего выражения следует:
умножим на
подставим (3) в (1)
Отсюда можно получить (проверяется подстановкой):
(формула Эйлера, )
Пусть есть средняя длина пути для идеально сбалансированного дерева
Структура памяти
Структура данных
К
- множество именА
- множество адресовf:К->А
Возможные задания f
:возможный способ-табличное задание функции:
Операции под таблицей:
Таблица - динамическая структура данных.
Базисное множество - семейство линейных структур из записей, базисное отношение включения определяется операциями вставки и удаления записей.
Варианты расширения понятия таблицы:
Принцип реализации таблиц:
Введение различных способов предполагает явное или неявное существование разных типов ситуаций при использовании таблиц.
Просматриваемые таблицы.
Таблица последовательности строк(записей)
По организации способа доступа таблицы делятся на следующие категории:
В просматриваемой таблице порядок расположения элементов никак не связан со значениями ключей (рис. II-34). Поэтому поиск элемента по ключу осуществляется обычным просмотром всех элементов таблицы, начиная с первого и до искомого
Ключ | Информация |
---|---|
08 | ... |
33 | ... |
47 | ... |
25 | ... |
18 | ... |
рис. II-34
Таким образом, при удалении элемента надо:
Поскольку операция поиска возвращает искомый элемент и не сообщает о месте его размещения в списке, при реализации операции удаления элемента из списка приходится либо
Алгоритм удаления элемента из просматриваемой таблицы-списка по варианту a) приведен на рис. II–39.
Ниже приводится текст программы, соответствующий приведенному алгоритму.
struct Item
{
int key;
Type info;
Item *next;
};
Item *ptab; /*указатель на начало таблицы */
int del1(int k)
{
Item *cur, *prev;
cur = ptab;
/*проверяем, есть ли в таблице элементы */
if(!cur)
return -1; /*таблица пуста – отказ */
/*возможно, требуется удалить первый элемент таблицы */
if(cur->key == k)
{
/* удаляем первый элемент */
ptab = cur->next;
delInfo(cur->info);
delete cur;
return 0;
}
/* ищем удаляемый элемент среди других элементов таблицы */
while(cur->next)
{
/* есть другие элементы */
prev = cur;
cur = cur->next;
if(cur->key == k)
{
/* нашли элемент, который надо удалить */
prev->next = cur->next;
delInfo(cur->info);
delete cur;
return 0;
}
}
/* естественный выход из цикла – в таблице нет элемента с ключом k */
return -1;
}
Дерево является идеально сбалансированным если для каждого его узла количество узлов в левом и правом поддеревьях различаются не более чем на 1. Дерево является сбалансированным,если для каждого узла высота левого и правого поддеревьев различаются не более,чем на 1(АВЛ-деревья). Идеально сбалансированные деревья являются сбалансированными.Операции обработки сбалансированных деревьев имеют сложность log2N.(поиск,вставка,удаление) Тmin=1 Tmax=log2N(при сбалансированном дереве) Tmax=N(при вырожденном дереве)
Структура памяти
Структура данных
К
- множество именА
- множество адресовf:К->А
Возможные задания f
(возможный способ - табличное задание функции):
Операции под таблицей:
Таблица - динамическая структура данных.
Базисное множество - семейство линейных структур из записей, базисное отношение включения определяется операциями вставки и удаления записей.
Варианты расширения понятия таблицы:
Принцип реализации таблиц:
Введение различных способов предполагает явное или неявное существование разных типов ситуаций при использовании таблиц.
По организации способа доступа таблицы делятся на следующие категории:
Порядок расположения элементов никак не связан со значениями ключей. Поэтому поиск элемента по ключу осуществляется обычным просмотром всех элементов таблицы, начиная с первого и до искомого
Ключ | Информация |
---|---|
08 | ... |
33 | ... |
47 | ... |
25 | ... |
18 | ... |
Таким образом, при удалении элемента надо:
Поскольку операция поиска возвращает искомый элемент и не сообщает о месте его размещения в списке, при реализации операции удаления элемента из списка приходится либо
Алгоритм удаления элемента из просматриваемой таблицы-списка по варианту a) приведен на рисунке.
Текст программы, соответствующий приведенному алгоритму
struct Item
{
int key;
Type info;
Item *next;
};
Item *ptab; /*указатель на начало таблицы */
int del1(int k)
{
Item *cur, *prev;
cur = ptab;
/*проверяем, есть ли в таблице элементы */
if(!cur)
return -1; /*таблица пуста – отказ */
/*возможно, требуется удалить первый элемент таблицы */
if(cur->key == k)
{
/* удаляем первый элемент */
ptab = cur->next;
delInfo(cur->info);
delete cur;
return 0;
}
/* ищем удаляемый элемент среди других элементов таблицы */
while(cur->next)
{
/* есть другие элементы */
prev = cur;
cur = cur->next;
if(cur->key == k)
{
/* нашли элемент, который надо удалить */
prev->next = cur->next;
delInfo(cur->info);
delete cur;
return 0;
}
}
/* естественный выход из цикла – в таблице нет элемента с ключом k */
return -1;
}
Формирование гипотез происходит в результате теоретического анализа модели решаемой задачи или может быть выполнено на основе статистических данных, получаемых в ходе вычислительных экспериментов с проектируемой программной системой.
Гипотеза 1: Стеки используются с одинаковой интенсивностью, память разделяется между стеками поровну.
Гипотеза 2: Интенсивность использования стеков различается.
Сохранение локальных тенденций роста:
правило распределение памяти для стеков в соответствии с их показателями роста
Гипотеза 3: Использование вероятностных предположений о поведении стеков.
Сортированные (упорядоченные) таблицы - таблицы, в которых записи располагаются в порядке возрастания (или убывания) ключей
Упорядоченность таблиц может быть организована только при возможности сравнения ключей (на множестве ключей задано отношение линейного порядка).
Сортировка - действия, связанные с размещением записей в порядке возрастания (или убывания) ключей
Алгоритм сортировки называют устойчивым, если он никогда не меняет относительный порядок в таблице двух записей с равными ключами
Внутренняя сортировка - Упорядочивание данных, при котором все значения располагаются в ОП
Сортировка включением
Идея похода – вставка нового значения в упорядоченный набор данных.
Алгоритм быстрой сортировки.
Идея подхода (Hoare C.A.R.)– использование процедуры разделения упорядочиваемого набора на две части, в одной из которых располагаются значения, меньшие некоторого порогового (ведущего) элемента массива, в другой – соответственно большие значения. Подобный способ разделения может быть выполнен без привлечения дополнительной памяти.
// Разделение массива с использованием ведущего элемента
key = k[0]; // ведущий элемент
i1 = i2 = N - 1; // индексы левого (i1) и правого (i2) блоков
// цикл, пока разделяемые блоки не пересекутся
while (i1 <= i2) {
// пока k[i1] не превышает ведущего элемента, переход вправо
while ((i1 < N) && (k[i1] <= key))
i1++;
// пока k[i2] меньше ведущего элемента, переход влево
while (k[i2] > key)
i2--;
//перестановка значений, которые приостановили разделение массива
if (i1 < i2) {
kt = k[i1];
k[i1] = k[i2];
k[i2] = kt;
}
}
// установка ведущего элемента между блоками
k[0] = k[i2];
k[i2] = key;
i1 = i2; // индекс ведущего элемента
При наличии процедуры разделения алгоритм сортировки может быть определен рекурсивно – необходимо разбить упорядочиваемый набор на два блока с меньшими и большими значениями соответственно и затем последовательно отсортировать полученные блоки.
Оценка сложности:
Вероятность выбора любого ключа в качестве ведущего элемента является одинаковой:
Докажем по индукции, что
Оценка сложности:
Звено списка представляются в виде объекта класса TLink
class TLink {
public:
int Value;
int Next;
protected:
TLink();
};
Образ памяти, выделенной для хранения стека, определяется в виде массива звеньев-объектов
TLink Mem[MemLimit];
Все свободные звенья объединяются в один список свободных звеньев. Звенья этого списка используются при необходимости свободной памяти, в этот список звенья должны возвращаться после освобождения.
Структура хранения стека - линейный список (начало списка - вершина стека)
Схемы работы со стеком и со списком свободных звеньев совпадают. Список свободных звеньев есть стек.
Дерево - связный граф без циклов
Структура типа дерева (древовидная структура) с базовым типом T
(Непосредственный) Потомок - узел у, находящийся непосредственно под узлом х (т.е. есть ребро (х, у)). Узел х - (непосредственный) предок узла у
Корень - узел, не имеющий предков
Длина пути - число ветвей(ребер), которые необходимо пройти, чтобы продвинуться от корня к заданному узлу
Узлы с одинаковой длиной пути образуют уровень(ярус) дерева * Корень расположен на уровне 1, его потомки на уровне 2 и т.д. * Принято изображать узлы дерева одного и того же уровня на одной горизонтальной прямой
Глубина - максимальный уровень дерева
Степень узла - число непосредственных потомков узла
Степепь дерева - максимальная степень всех узлов
Упорядоченное дерево - дерево, у которого ветви каждого узла упорядочены
Бинарное дерево - упорядоченное дерево степени 2
Дерево поиска - дерево, удовлетворяющее условию: * Если для любой вершины бинарного дерева значения в левом потомке меньше значения узла, а значение в правом потомке больше значени узла
Дерево поиска - дерево, в котором для любой вершины бинарного дерева значения в левом потомке меньше значения узла, а значение в правом потомке больше значения узла
Обработка дерева – выполнение необходимой операции для каждой узла дерева. Реализация подобного типа действий предполагает умение обхода (обхода) дерева
Возможные варианты обхода: * TLR - сверху вниз * LTR - слева направо * LRT - снизу вверх * TRL - сверху вниз * RTL - справа налево * RLT - снизу вверх
void TTreeTable::PrintTreeTab(ostream &os, pTTreeNode pNode)
{
// Печать дерева с вершиной pNode
if (pNode != NULL)
{
PrintTreeTab(os, pNode->pLeft);
pNode->Print(os);
os << endl;
PrintTreeTab(os, pNode->pRight);
}
}
Непрерывная память | Списки |
---|---|
Перепаковка для динамического распределения памяти | Динамическое распределение памяти эффективно реализуется при помощи списка свободных звеньев |
В структуре хранения хранятся только данные | В структуре хранения хранятся данные и указатели |
К элементам структуры данных обеспечивается | К элементам структуры данных обеспечивается |
Прямой доступ | Последовательный доступ |
В качестве базовых объектов рассматриваются основные геометрические фигуры – точку, окружность, прямоугольник и т.д.
Информационное описание объектов – параметры фигуры (координаты, размер, радиус и др.). В общем случае, описание фигуры включает значение координат некоторой опорной точки.
Операции обработки геометрических объектов включают методы для задания и изменения параметров; расширим набор операций процедурами визуализации и скрытия фигур.
Схема иерархии классов для реализации геометрических объектов:
Для обеспечения возможности динамической визуализации геометрических объектов введем тип данных, значения которого вычисляются в соответствии с задаваемым формульным выражением.
Составной объект – набор геометрических объектов (как базовых, так и составных), рассматриваемых при выполнении операций обработки как единый объект.
Геометрический объект может быть сконструирован с использованием уже существующих объектов (например, ломаная может быть определена через набор конечных точек составляющих отрезков).
Геометрический объект может быть образован при помощи сборки существующих объектов – рассмотрим данный способ построения новых объектов на примере рисунков (чертежей), образованных только из объектов двух базовых типов: точек и линий
Операции:
Класс TStack обеспечивает реалзацию динаммической структуры стек.
Управление памятью - хранение значений осуществляется в векторе пямяти от младших элементов к старшим. Индекс последнего занятого элемента в векторе пямяти фиксируется в переменной .
Методы:
#define MemSize 25 // размер памяти для стека
class TStack
{
protected:
int Mem[MemSize]; // память для СД
int Top; // индекс последней занятой ячейки
public:
TStack () { Top = -1; }
int IsEmpty (void) const { Top == -1; }
int IsFull (void) const { Top == MemSize-1;}
void Put ( const int Val ) { Mem[++Top] = val; }
TData Get (void) { return Mem[Top--]; }
};
Очередь (вставка в конец очереди, исключение из начала - FIFO - first in, first out)
Вставка значений происходит в начало очереди, исключение - с конца очереди => для индикации начала и конца очереди требуется 2 индекса.
В ходе вычислений может возникнуть ситуация = = n - 1. Тогда вставка нового значения невозможна, а = 0.
Сдвиг значений очереди после выборки очередного значения (т.е. обеспечение =0) – возрастание накладных расходов, использование левого участка свободной области при достижении =n-1 (т.е. при отсутствии свободной памяти справа).
Циклический или кольцевой буфер - структура хранения, получаемая из вектора расширением отношения следования парой . Реализация кольцевого буфера логически может быть обеспечена переходом индексов и при достижении граничного значения MemSize-1
на индекс первого элемента вектора памяти.
Агрегация – абстракция, превращающая связь между объектами в некоторый агрегированный объект.
Составной объект - набор геометрических объектов (как базовых так и составных), рассматриваемых при выполнении операций обработки как единый объект.
class TChartGroup : public TChartRoot
{
protected:
TDatList Group; // Список объектов
public:
TChartGroup() { }
void InsUnit(TChartRoot *pUnit); // Добавление
virtual void Show(); // Визуализация
virtual void Hide(); // Скрытие
virtual void CalcParams(double t = -1); // Пересчет параметров
};
Геометрический объект может быть сконструирован с использованием уже существующих объектов. Например, ломаная может быть определена через набор конечных точек составляющих отрезков
class TChartPolyline : public TChartGroup
{
public:
TChartPolyline() { }
void InsPoint(TChartRoot *pUnit); // Добавление
virtual void Show(); // Визуализация
virtual void Hide(); // Скрытие
virtual void CalcParams(double t = -1); // Пересчет параметров
};
Агрегация – абстракция, превращающая связь между объектами в некоторый агрегированный объект.
Составной объект - набор геометрических объектов (как базовых так и составных), рассматриваемых при выполнении операций обработки как единый объект.
class TChartGroup : public TChartRoot
{
protected:
TDatList Group; // Список объектов
public:
TChartGroup() { }
void InsUnit(TChartRoot *pUnit); // Добавление
virtual void Show(); // Визуализация
virtual void Hide(); // Скрытие
virtual void CalcParams(double t = -1); // Пересчет параметров
};
Геометрический объект может быть сконструирован с использованием уже существующих объектов. Например, ломаная может быть определена через набор конечных точек составляющих отрезков
class TChartPolyline : public TChartGroup
{
public:
TChartPolyline() { }
void InsPoint(TChartRoot *pUnit); // Добавление
virtual void Show(); // Визуализация
virtual void Hide(); // Скрытие
virtual void CalcParams(double t = -1); // Пересчет параметров
};
FindRecord(TKey k, PTTreeNode pNode)
{
if (pNode != NULL) // лист
{
if (pNode->Key < k) // вправо
pNode = FindRecord(k, pNode->Right);
if (pNode->Key > k) // влево
pNode = FindRecord(k, pNode->Left);
}
return pNode;
}
Введение барьера.
FindRecord(TKey k, PTTreeNode pNode)
{
if (pNode->Key < k) // вправо
pNode = FindRecord(k, pNode->Right);
if (pNode->Key > k) // влево
pNode = FindRecord(k, pNode->Left);
return (pNode == pBarrier) ? NULL : pNode;
}
void TTreeTable ::InsRecord(TKey k, PTDatValue pVal)
{ // вставить запись
if (IsFull())
SetRetCode(TabFull);
else if (FindRecord(k) != NULL)
SetRetCode(TabRecDbl);
else
{
SetRetCode(TabOK);
ppRef = new TTreeNode(k, pVal);
DataCount++;
}
}
while (pN (не принадлежит) TChartPoint)
{
St.push(pN);
pN = pN->GetFirstPoint();
}
//подъем по плексу и рисование
pF = pN;
while (!St.Empty())
{
pN = St.top();
St.Pop();
pL = pN->GetLastPoint(); //рисование линии<pN, pF, pL>
pF = pL;
}
TChartPoint *Show(TChart *pN)
{
if (pN != NULL)
pL = NULL;
else if (pN (принадлежит) TChartPoint)
pL = pN;
else
{
pF = Show(pN->GetFirstPoint());
pL = Show(pN->GetLastPoint()); //рисование линии <pN,pF,pL>
}
return pN;
}
Линейные структуры данных - структуры, которым соответствует ориентированный граф с вершинами, лежащими на одной ломаной
Линейные структуры данных - упорядоченные структуры, в которых адрес элемента однозначно определяется его номером
Свойства:
Примеры линейных структур:
Таблица – динамическая структура данных, базисным множеством которой является семейство линейных структур из записей.
Запись – кортеж, каждый элемент которого обычно именуется полем.
Имя записи (ключ) – одно из полей записи, по которому обычно осуществляется поиск записей в таблице; остальные поля образуют тело записи.
Хеш-функция – функция, ставящая в соответствие ключу номер записи в таблице.
Хеш-таблицами, таблицами с вычисляемыми адресами или перемешиваемыми таблицами - таблицы, получаемые при некотором способе построения.
h(key)
, которая отображает множество имен на множество номеров строк таблицыПри использовании таблиц с вычисляемыми адресами может возникнуть ряд дополнительных проблем
Так, например, при вставке новой записи функция расстановки может выдать номер занятой строки массива (функция расстановки может определять одни и те же значения для нескольких разных ключей)
Метод открытого перемешивания (или закрытое хеширование) - добавление к вычисленному занятому номеру некоторого фиксированного смещения (поторное перемешивание) k' = (k + p) mod N
k'
также является занятым, следует повторить процедуру повторного перемешивания до тех пор, пока не обнаружится свободная строка, либо таблица не будет исчерпанаp
и N
являются взаимнопростыми, открытое перемешивание обеспечивает нахождение свободной строки массиваСреднее количество просматриваемых записей при поиске записи в перемешиваемых таблицах
Tср = (1 - a / 2) / (1 - a)
a
- коэффициент заполненности таблицы (a = N / M
)M
- количество строк в массиве для хранения записейN
- количество записей в таблице.Следует отметить, что количество сравнений при поиске в перемешиваемых таблицах зависит не от количества записей в таблице, а от заполненности памяти, отведённой для размещения записей. Для примера, при заполненности массива на 75% (a = 0.75
) количество сравнений в среднем равно 2.5.
Вставка:
1. Если n==M, ТО { Переполнение; Останов }
2. f = -1 // f – номер первой найденной пустой строки
3. s = h(key) // применение функции расстановки
4. ЕСЛИ s занята и K[s]==key, ТО {Дублир.; Останов }
5. ЕСЛИ s пустая и (f < 0), ТО { f = s }
6. ЕСЛИ s свободна и (f < 0), ТО { K[s]=key; Останов }
7. ЕСЛИ s свободна и (f >-1), ТО { K[f]=key; Останов }
8. (!) Коллизия {s = (s+p) mod M и переход к п. 4 }.
Поиск:
1) f = -1 // f – номер первой найденной пустой строки
2) s = h(key) // применение функции расстановки
3) ЕСЛИ s занята и K[s]==key, ТО { Останов }
4) ЕСЛИ s пустая и (f < 0), ТО { f = s }
5) ЕСЛИ s свободна, ТО { Останов }
6) (!) Коллизия { s = (s+p) mod M и переход к п. 3 }.
Необходимость перепаковки для обеспечения динамического распределения памяти возникает в силу принятого способа реализации отношения следования - следующий элемент структуры располагается в следующем элементе памяти (с адресом, большим на 1). Устранение перепаковки возможно только при кардинальном изменении способа реализации основных отношений – необходимо допустить размещение следующих элементов структуры в произвольных элементах памяти (там, где имеется свободные области памяти). Возможность такого подхода может быть обеспечена запоминанием для каждого текущего элемента структуры адреса памяти, где хранится следующий элемент. Интерпретация содержимого элемента памяти (значение или адрес следующего элемента) в самом простом варианте может быть обеспечена фиксированным форматом используемых участков памяти.
Под квантом памяти понимается последовательность элементов памяти с последовательно-возрастающими адресами.
Именем (адресом) этой группы считается адрес первого слова кванта. Элементы кванта называются полями. В общем случае, набор элементов памяти, связанных с одним именем, называют звеном.
Далее будут использоваться двухэлементные звенья памяти, в которых первое поле будет использоваться для хранения значений, а второе поле – для запоминания адресов.
Способ задания отношения следования, в котором фиксация месторасположения следующего элемента производится путем запоминания соответствующего адреса памяти, называется сцеплением (пары, хранящие ai
и ai+1
, сцеплены адресными указателями).
Для изображения структуры хранения с использованием сцепления звенья памяти рисуются в виде прямоугольников, а сцепление звеньев показывается в виде стрелок.
Индикация последнего звена в списке обычно производится записью в поле адреса некоторого барьера – фиктивного (неадресного) значения (как правило, 0 или -1). Для доступа к звеньям списка должен быть известен адрес первого звена списка. Указатель, в котором этот адрес запоминается, называется переменной связи.
Структура хранения данного типа (звенья, сцепление, барьер, переменная связи) называется линейным или односвязным списком.
Таблица с вычисляемым входом (хеш-таблица) – это таблица, элементы которой располагаются в соответствии с некоторой функцией расстановки (хеш-функцией)
Функция расстановки f (ключ) вычисляет для каждого элемента таблицы по его ключу номер (позицию) элемента в массиве.
0…N–1
или 1…N
Организация прямого доступа в рассмотренном виде приводит к неэффективному использованию памяти - требуется больше памяти (М >> 1) - количество используемых ключей, как правило, существенно меньше теоретически возможного набора
Размер памяти для представления таблицы значительно меньше возможного количества имен (M << N), и, как результат, получаемые по ключам числовые значения необходимо преобразовывать к диапазону номеров (адресов) строк памяти
Функция (хеширования, перемешивания, рассеивания) расстановки (hash - мешанина, путаница) - функция преобразования значения ключа к номеру (адресу) строки памяти для хранения записи H : K -> L (L = (0, ..., M - 1))
Таблицы с вычислимыми адресами (хеш-таблицы, перемешиваемые таблицы) - таблицы, представление которых организуется при использовании функции расстановки
Метод цепочек
Замечания к открытому перемешиванию как способу размешения коллизий:
Широко используемый подход для разрешения коллизий - метод цепочек, когда все записи, для которых функция хеширования определяет одно и тоже значение,представляются в виде линейного списка.
Открытое перемешивание еще называют закрытым хэшированием, метод цепочек - открытое хэширование.
Каждая ячейка массива является указателем на связный список (цепочку) пар ключ-значение, соответствующих одному и тому же хеш-значению ключа. Коллизии просто приводят к тому, что появляются цепочки длиной более одного элемента. Операции поиска или удаления элемента требуют просмотра всех элементов соответствующей ему цепочки, чтобы найти в ней элемент с заданным ключом. Для добавления элемента нужно добавить элемент в конец или начало соответствующего списка, и, в случае, если коэффициент заполнения станет слишком велик, увеличить размер массива и перестроить таблицу.
Плекс может рассматриваться как структура представления для выражений самого общего вида (линия – операция, точки - операнды).
Пример: Арифметическое выражение (a * b + c) * (d - e / f)
:
Здесь необходимо расписать + и - использования просмотровых таблиц, сортированных таблиц, хеш таблиц и ...
Текст – линейная последовательность символов
Текст – линейная последовательность слов (слово - линейная последовательность символов)
Текст – линейная последовательность строк, строки состоят из слов, слова – из символов и т.д.
Математическая модель текста – иерархическая структура представления (дерево).
Единый тип звена:
typedef Tlink *PTLink;
class TLink
{
PTLink pNext;
int Atom; // =1 – звено-атом
union {PTLink pDown; char Symb;}
Множество – набор элементов.
Для множества определены операции:
Проектирование:
Текст – линейная последовательность слов (слово - линейная последовательность символов)
Текст – линейная последовательность строк, строки состоят из слов, слова – из символов и т.д.
Математическая модель текста – иерархическая структура представления (дерево).
При удалении разделов текста для освобождения звеньев следует учитывать следующие моменты:
Память, занимаемая удаляемым текстом, не освобождается, а удаление текста фиксируется установкой указателей в состояние NULL (например, pFirst=NULL
).
Подобный способ выполнения операций удаления текста может привести к ситуации, когда в памяти, используемой для хранения текста, могут присутствовать звенья, на которые нет ссылок в тексте и которые не возвращены в систему управления памятью для повторного использования. Элементы памяти такого вида носят наименование "мусора". Наличие "мусора" в системе может быть допустимым, если имеющейся свободой памяти достаточно для работы программ. В случае нехватки памяти необходимо выполнить "сборку мусора".
Возможный подход доступа к системе управления памятью – разработка специальной системы управления при помощи перегрузки операторов new
и delete
.
Общая схема подхода:
TTextLink
создается статическая переменная MemHeader
типа TTextMem
.class TTextMem{
PTTextLink pFirst; // первое звено
PTTextLink pLast; // последнее звено
PTTextLink pFree; // первое свободное
InitMemSystem
класса TTextLink
.void TTextLink::InitMemSystem(int size) // инициализация памяти
{
char Line[100];
char *tmp = new char[sizeof(TTextLink)*size];
MemHeader.pFirst = (PTTextLink)new char[sizeof(TTextLink)*size];
MemHeader.pFree = MemHeader.pFirst;
MemHeader.pLast = (PTTextLink)tmp + size - 1;
PTTextLink pLink = MemHeader.pFirst;
for (int i = 0; i < size - 1; i++, pLink++) // размер памяти
pLink->pNext = pLink + 1;
pLink->pNext = nullptr;
}
void * TTextLink::operator new(size_t size) // выделение звена
{
PTTextLink pLink = MemHeader.pFree;
if (MemHeader.pFree != nullptr)
MemHeader.pFree = pLink->pNext;
return pLink;
}
delete
звено включается в список свободных звеньев.void operator delete (void *pM)
{
PTTTextLink pLink=(PTTTextLink)pM;
pLink->pNext=MemHeader.pFree;
MemHeader.pFree=pLink;
}
Составной объект - набор геометрических объектов (как базовых так и составных), рассматриваемых при выполнении операций обработки как единый объект
class TChartGroup : public TChartRoot
{
protected:
TDatList Group; // Список объектов
public:
TChartGroup() { }
void InsUnit(TChartRoot *pUnit); // Добавление
virtual void Show(); // Визуализация
virtual void Hide(); // Скрытие
virtual void CalcParams(double t = -1); // Пересчет параметров
};
Ориентрованный граф G представляет собой набор G = (V, R), где - - множество вершин графа - - множество дуг(ребер) графа
Обработка очередной вершины графа продолжается рекурсивной процедурой обработки смежных вершин
Геометрический объект может быть сконструирован с использованием уже существующих объектов. Например, ломаная может быть определена через набор конечных точек составляющих отрезков
class TChartPolyline : public TChartGroup
{
public:
TChartPolyline() { }
void InsPoint(TChartRoot *pUnit); // Добавление
virtual void Show(); // Визуализация
virtual void Hide(); // Скрытие
virtual void CalcParams(double t = -1); // Пересчет параметров
};
Для каждой вершины сначала выполняется обработка непосредственно смежных вершин
Геометрический объект может быть образован при помощи сборки существующих объектов.
Рассмотрим данный способ построения новых объектов на примере рисунков (чертежей), образованных только их объектов двух базовых типов: точек и линий
while (pN (не принадлежит) TChartPoint)
{
St.push(pN);
pN = pN->GetFirstPoint();
}
//подъем по плексу и рисование
pF = pN;
while (!St.Empty())
{
pN = St.top();
St.Pop();
pL = pN->GetLastPoint(); //рисование линии<pN, pF, pL>
pF = pL;
}
TChartPoint *Show(TChart *pN)
{
if (pN != NULL)
pL = NULL;
else if (pN (принадлежит) TChartPoint)
pL = pN;
else
{
pF = Show(pN->GetFirstPoint());
pL = Show(pN->GetLastPoint()); //рисование линии <pN,pF,pL>
}
return pN;
}
Алгоритмы обхода (итератор)
TSearchMode; // способ обхода
PTGraphNode pCurrNode; // текущая вершина
// Достигнутые, но не обработанные вершины
TDataRoot *pStream;
// Множество вершин, достигнутых в ходе обхода
TBitField *pFound;
Инициализация (Reset)
pStream
и ее отметка в множестве pFound
GoNext
Проверка завершения (IsGraphEnded)
return pCurrNode == NULL // текущее звено?
Переход к следующей вершине графа (GoNext)
pStream
pStream
int Reset (void); // установить на первую вершину
int IsGraphEnded (void) const; // обход завершен?
int GoNext (void); // переход к следующей вершине
PTGraphNode GetCurrNode (void) { return pCurrNode; } // доступ
PTGraphPath GetShortestPath (string fn, string ln); // поиск кратчайшего пути
protected:
virtual void Print (ostream &os); // печать графа
};
typedef TGraph * PTGraph;
// end of tgraph.h