
- •4. Просматриваемая динамическая таблица - вектор. Определение, основные операции и особенности их реализации.
- •Способ работы с таблицей
- •Способ доступа к таблице
- •Просматриваемые таблицы
- •Просматриваемая таблица-вектор
- •Статическая просматриваемая таблица-вектор
- •Динамическая просматриваемая таблица-вектор
Статическая просматриваемая таблица-вектор
Для статической просматриваемой таблицы определена только операция поиска элемента. Реализация алгоритма поиска элемента не вызывает затруднений и может быть такой:
int search(int k){
int i;
for(i = 0; i< M && table[i].key != k; i++)
;
return (i<M ? i : -1);
}
Динамическая просматриваемая таблица-вектор
Динамические таблицы разрешают выполнение операций включения новых элементов и удаления существующих. Это накладывает дополнительные требования на отображение таблицы.
Прежде всего, поскольку разрешена операция включения, нужно иметь информацию о наличии в таблице свободных позиций; кроме того, при наличии в таблице нескольких свободных позиций необходимо решить, в какую именно будет включаться новый элемент. Свободные позиции в такой таблице могут появляться, в том числе, и в результате выполнения операций удаления элементов. Наличие в таблице свободных элементов может повлиять на реализацию всех операций с таблицей, в том числе, и на реализацию алгоритма поиска.
Рассмотрим различные способы реализации операций с таблицей.
Способ 1.Для фиксации в таблице свободных и занятых элементов полезно реорганизовать элемент таблицы, включив в него дополнительное (служебное) поле 1/0 – поле занятости (рис.II-35): значение 1 в этом поле означает, что элемент занят, значение 0 – что элемент свободен.
1/0 |
ключ |
информация |
Рис. II‑1.
В исходном состоянии таблица пуста, и все элементы таблицы помечены как свободные. При включении нового элемента в таблицу нужно найти подходящий свободный элемент. Критерием для выбора может служить длина доступа L(количество элементов таблицы, которое необходимо просмотреть, прежде чем будет найдена свободная позиция; в какой-то степени длина доступа аналогична длине поиска). Можно обеспечитьL= 1, если все операции включения выполнять в конец таблицы и использовать специальную переменную (например,int n;), которая определяет первый свободный элемент в конце таблицы. В исходном состоянииn=0; каждая операция включения нового элемента увеличивает значениеn. Если при выполнении операции включения в таблицу нового элемента свободная позиция не будет найдена, операция завершается отказом.
Пусть, например, выполнялись подряд несколько операций включения элементов в таблицу (последовательность элементов 25, 13, 47, 18, 33)
При удалении элементав найденном элементе таблицы достаточно установить в 0 поле занятости; можно не модифицировать значения других полей таблицы. Пусть, например, элементы удалялись в следующем порядке: 33, 18, 13.
Таким образом, после выполнения указанных выше операций включения и удаления, состояние таблицы может иметь вид, приведенный на рис. II-36. Если после этих операций будет выполняться, например, операция поиска элемента с ключом 13, она должна завершиться отказом (элемент был удален). Следовательно, при выполнении поиска элемента в таблице следует учитывать, свободен очередной элемент или занят.
1/0 |
ключ |
информация |
1 |
25 |
... |
0 |
13 |
... |
1 |
47 |
... |
0 |
18 |
... |
0 |
33 |
... |
Рис. II‑2.
Такая реализация операции удаления влияет также и на операцию включения в таблицу нового элемента. Если новый элемент включается всегда в конец таблицы, с течением времени может возникнуть ситуация, когда в конце таблицы свободных позиций нет (т.е. n = M), в то время как в середине таблицы есть много элементов, помеченных как свободные. В таких ситуациях, прежде чем можно будет выполнить очередную операцию включения нового элемента в таблицу, следует ее реорганизовать, собрав все свободные элементы в конце таблицы и изменив текущий размер таблицы (n). Такая операция получила название "сборки мусора".
Поскольку операция сборки мусора приводит к перемещению информации в таблице, она является достаточно медленной. Данную операцию можно выполнять, например, вместе с операцией включения нового элемента в таблицу: если оказалось, что в конце таблицы нет свободного элемента, тогда выполняется операция сборки мусора. Если и после выполнения данной операции в конце таблицы нет свободного элемента, значит, таблица полна, и операция включения нового элемента завершается отказом.
Можно отказаться от выполнения операции сборки мусора, если новый элемент включать не просто в конец таблицы, а в первую свободную позицию в таблице. В этом случае при включении в таблицу нового элемента отыскивается позиция в таблице, помеченная как свободная, и в эту позицию заносится новый элемент. Кроме того, если найденная свободная позиция находится в конце таблицы, изменяется текущий размер таблицы (значение переменной nувеличивается). Если свободная позиция не будет найдена, значит, таблица полна, и операция включения завершается отказом.
Способ 2.Поле занятости не используется и не включается в структуру элемента таблицы. В этом случае алгоритм поиска реализуется без каких-либо изменений. Включение нового элемента выполняется всегда в конец таблицы, что приводит к увеличению значенияn. При удалении элемента из таблицы в освободившуюся позицию переписывается последний элемент таблицы, после чего значение переменнойnуменьшается.
Выбор конкретного способа удаления зависит от многих причин, в том числе, от размера таблицы, частоты выполнения операций включения и удаления элементов и других. Нельзя утверждать, что какой-то способ из рассмотренных выше лучше, а какой-то хуже. Но в любом случае не следует при удалении элемента из середины таблицы перемещать информацию из нижней половины таблицы на одну позицию вверх, сохраняя исходный порядок включения элементов в таблицу. В просматриваемой таблице порядок размещения элементов никакого значения не имеет, тогда как подобная реализация операции удаления может привести к существенному увеличению времени выполнения операции.
Тексты функций для выполнения операций включения, удаления, поиска элементов в таблице и "сборки мусора" приводятся ниже и в файле Programs/tab1vec.cpp.
const int M = 20; // Максимальный размер таблицы
struct Item{
int busy; //поле занятости
int key; //ключ
Type info; // информация
};
Item table[M]; /* Объявление таблицы как внешней (вне функций) приводит к тому, что все элементы инициализируются нулем; поэтому можно не устанавливать явно значения 0 в полеbusy всех элементов при создании таблицы */
int n = 0; // текущий размер таблицы
/* поиск элемента в таблице */
int search(int k)
{
inti;
for(i = 0; i< n; i++)
if(table[i].busy && table[i].key == k)
return i; /* элемент найден – он занят и имеет искомый ключ */
return -1; /* элемент не найден */
}
/* удаление элемента*/
int del(int k)
{
int l;
if((l = search(k)) < 0)
return-1; /* указанного элемента в таблице нет */
table[l].busy = 0; /* "удаление" элемента */
return 0;
}
/* "сборка мусора" */
int garbage()
{
int i, cur = n;
n = 0;
for(i = 0; i< cur; i++)
if(table[i].busy){ /* элемент занят */
if(i != n) /* элемент должен быть перемещен */
table[n] = table[i]; /* перемещение элемента */
n++;
}
return n== M ? -1 : 0; /* в таблице нет свободного места */
}
/* включение нового элемента в таблицу */
int insert(int k, Type in)
{
if(search(k) >= 0)
return -1; /* в таблице есть элемент с заданным ключом */
if(n== M) /* в конце таблицы нет свободной позиции */
if(garbage() < 0) /* "сборка мусора" */
return-2; /* в таблице нет свободной позиции */
/* включение нового элемента в таблицу */
table[n].busy = 1;
table[n].key = k;
table[n++].info = in;
return 0;
}