
Лекция 16. Таблицы
Таблицы
Таблица – это набор элементов, содержащих ключ – отличительный признак для поиска элементов, и тело – сопутствующую информацию.
Примеры таблиц.
Таблица функции f(x): ключ – аргумент x, тело – значение f(x).
Словарь: ключ – слово, тело – его перевод.
Таблица имен компилятора: ключ – имя объекта программы (например, переменной), тело – его характеристики (тип, адрес, значение и т.п.).
Таблицы используются везде, где есть поиск информации.
Основные операции над таблицами
Инициализация (подготовка к работе).
Поиск элемента по ключу – основная операция (входит в другие операции).
Включение в таблицу данного элемента.
Исключение из таблицы элемента с данным ключом.
Изменение в таблице тела элемента с данным ключом.
Распечатка элементов таблицы в порядке, определяемом ключами.
Сортировка таблицы по возрастанию или убыванию ключей.
Типы таблиц
- статическая (постоянная) и динамическая (меняющаяся при выполнении программы);
- внутренняя (в ОП) и внешняя (во внешней памяти, в файле);
- последовательная, с прямым доступом, древовидная.
Последовательные таблицы
Последовательной (линейной) называют таблицу, в которой производится линейный поиск, т.е. последовательный перебор элементов с начала таблицы.
Последовательные таблицы бывают сортированными и несортированными. Внутренние таблицы могут храниться в виде вектора или в виде списка. Рассмотрим операции над таблицами на примерах.
Пример 17.1.
Задача. Дана последовательность слов, разделенных пробелами или символов перевода строки. Конец последовательности отмечается нажатием клавиш Ctrl – Z (конец файла). Подсчитать количество повторений каждого слова в последовательности. Результат вывести в алфавитном порядке.
Например, исходная последовательность:
май апрель май июнь июль
август май апрель
Результат:
Слово Количество
-------------------------------------------------
август 1
апрель 2
июль 1
июнь 1
май 3
Для решения задачи нужна таблица, в которой ключом будет слово, а телом – число его повторений.
Метод решения. Очередное введенное слово ищется в таблице. Если его там нет, оно включается в таблицу, если есть, увеличивается число его повторений.
Будут использоваться все основные операции над таблицами, кроме исключения элемента.
Алгоритм 1. Использование последовательной несортированной таблицы в виде вектора.
Чтение слов и заполнение таблицы.
Сортировка таблицы по алфавиту.
Печать таблицы.
май |
1 |
|
|
|
|
|
|
|
|
май |
1 |
апрель |
1 |
|
|
|
|
|
|
май |
2 |
апрель |
1 |
|
|
|
|
|
|
заполнения
таблицы:
. . .
Программа 17.1:
#include <stdio.h>
#include <string.h>
#include <conio.h>
#define DSLMAX 21 /* макс. длина слова + 1 (‘\0’) */
#define DTMAX 30 /* макс. длина таблицы (макс. число разных слов) */
/* тип элемента таблицы */
struct EL_TAB
{ char sl [DSLMAX]; /* слово */
int kol; /* количество повторений */
};
/* прототипы функций */
void CorrectTab (struct EL_TAB tab[], int *dt, char tsl[]);
void SortTab (struct EL_TAB tab[], int dt);
/*----------------------------*/
/* главная функция */
/*----------------------------*/
int main()
{ struct EL_TAB tab[DTMAX]; /* таблица слов */
int dt=0; /* длина таблицы (число элементов) */
int i; /* индекс тек. элемента таблицы */
char tsl [DSLMAX]; /* текущее слово */
/*------------------------------------------------------------*/
/* 1. Чтение слов и заполнение таблицы */
puts ("\n\n Введите последовательность слов");
while (scanf("%s", tsl)!=EOF)
CorrectTab(tab, &dt, tsl); /* корректировка таблицы для прочитанного
слова */
/*------------------------------------------------------------*/
/* 2. Сортировка таблицы по алфавиту */
SortTab (tab, dt);
/*-------------------------------------------------------------*/
/* 3. Печать таблицы */ puts ("\n\n Слово Кол-во");
puts (" -------------------------");
for (i=0; i<dt; i++)
printf(" %-*s %d\n", DSLMAX, tab[i].sl, tab[i].kol);
getch();
}
/*-------------------------------------------------------------------------------*/
/* Функция корректировки таблицы для прочитанного слова */
/*-------------------------------------------------------------------------------*/
void CorrectTab (struct EL_TAB tab[], int *dt, char tsl[])
/* Вх. данные: tab – таблица слов, */
/* *dt – длина таблицы, */
/* tsl – текущее слово */
/* Вых. данные: tab, *dt */
{ int i; /* индекс очередного элемента таблицы */
/* линейный поиск текущего слова в таблице */ for (i=0; i<*dt && strcmp(tsl,tab[i].sl); i++);
if (i<*dt) /* слово найдено */
tab[i].kol++; /* увеличение количества повторений слова */
else /* слова нет в таблице */
if (*dt < DTMAX) /* есть место в таблице */
{ strcpy(tab[i].sl,tsl); /* запись слова в конец таблицы */
tab[i].kol=1;
(*dt)++;
}
else { printf("\n Таблица переполнена.");
printf (" Слово %s не учитывается.", tsl);
}
}
/*-------------------------------------------------------------------*/
/* Функция сортировки таблицы слов по алфавиту */
/*-------------------------------------------------------------------*/
void SortTab (struct EL_TAB tab[], int dt)
{ int k,i; /* параметры циклов */
struct EL_TAB s; /* вспомогательная переменная для перестановки элементов таблицы */
for (k=dt -1; k>0; k--)
for (i=0; i<k; i++)
if (strcmp(tab[i].sl, tab[i+1].sl)>0)
{ /* перестановка эл-тов tab[i] и tab[i+1] */
s = tab[i];
tab[i] = tab[i+1];
tab[i+1] = s;
}
}
Алгоритм 2. Использование последовательной сортированной таблицы в виде списка.
Первый элемент таблицы можно сделать фиктивным с пустым словом, чтобы включение нового слова в начало таблицы происходило так же, как и в середину таблицы (упростить операцию включения).
После чтения очередного слова оно ищется в списке. Если слово есть в списке, значение поля количества kol увеличивается на 1. Если его там нет, то создается новый элемент списка, в него записывается слово и количество 1, а затем этот элемент включается в соответствующее место списка так, чтобы не нарушить алфавитный порядок слов. Поэтому сортировка таблицы не нужна (в отличие от предыдущего алгоритма).
Алгоритм:
Инициализация таблицы – создание таблицы из одного фиктивного элемента.
Чтение слов и формирование таблицы в виде списка.
Печать таблицы.
Удаление таблицы (освобождение памяти).
Программа 17.2:
#include <stdio.h>
#include <string.h>
#include <conio.h>
#include <stdlib.h>
#define DSLMAX 21 /* макс. длина слова + 1 (‘\0’) */
/* тип элемента таблицы */
struct EL_TAB
{ char sl [DSLMAX]; /* слово */
int kol; /* количество повторений */
struct EL_TAB *sled; /* указатель на следующий элемент */
};
/* прототипы функций */
void CorrectTab (struct EL_TAB *pt, char tsl[]);
void UdalTab(struct EL_TAB *pt);
/*----------------------------*/
/* главная функция */
/*----------------------------*/
int main()
{ struct EL_TAB *pt; /* указатель таблицы (ссылается на фиктивный эл-т) */
struct EL_TAB *i; /* указатель текущего эл-та таблицы (при печати) */
char tsl [DSLMAX]; /* текущее слово */
/*--------------------------------------------------------------*/
/* 1. Инициализация таблицы */
pt = (struct EL_TAB *) malloc (sizeof (struct EL_TAB));
pt->sled = NULL;
strcpy (pt->sl,"");
/*--------------------------------------------------------------*/
/* 2. Чтение слов и формирование таблицы в виде списка */
puts ("\n\n Введите последовательность слов ");
while (scanf("%s",tsl)!=EOF)
CorrectTab (pt, tsl); /* корректировка таблицы для прочитанного слова */
/*--------------------------------------------------------------*/
/* 3. Печать таблицы */
puts ("\n\n Слово Кол-во");
puts (" -------------------------");
for (i=pt->sled; i; i=i->sled)
printf (" %-*s %d\n", DSLMAX, i->sl, i->kol);
getch();
/*--------------------------------------------------------------*/
/* 4. Удаление таблицы */
UdalTab (pt);
}
/*-------------------------------------------------------------------------------*/
/* Функция корректировки таблицы для прочитанного слова */
/*-------------------------------------------------------------------------------*/
void CorrectTab(struct EL_TAB *pt, char tsl[])
/* Вх. данные: pt - указатель начала таблицы, */
/* tsl - текущее слово */
{ struct EL_TAB *i, *j, *k; /* указатели элементов таблицы */
/* линейный поиск текущего слова в таблице */ j = pt;
while ( j && strcmp (tsl,j->sl)>0)
{ k=j; j=j->sled; }
if ( j && strcmp (tsl,j->sl) == 0 ) /* слово найдено */
j->kol++;
else /* слова в таблице нет */
{ /* создание нового элемента */
i = malloc (sizeof (struct EL_TAB));
strcpy (i->sl,tsl);
i->kol = 1;
/* включение нового элемента в список */
k->sled = i;
i->sled = j;
}
}
/*-----------------------------------------*/
/* Функция удаления таблицы */
/*-----------------------------------------*/
void UdalTab (struct EL_TAB *pt)
{ struct EL_TAB *i;
while (pt)
{ i=pt;
pt = i->sled;
free (i);
}
}