Консультация № 186234
29.05.2012, 11:34
699.29 руб.
0 4 1
Уважаемые эксперты! Пожалуйста, ответьте на вопрос:
Написать программу для работы с перемешанной таблицей, использующей перемешивание сцеплением, по запросам оператора.
В основной области перемешанной таблицы находится указатель на элементы из области переполнения; каждый элемент области переполнения имеет следующую структуру:
struct Ofl {
int key; /*ключ элемента*/
char *info; /*указатель на информацию */
Ofl *next; /*указатель на следующий элемент*/
};
Максимальный размер основной области ограничен (для задания максимального размера использовать константу -например, const int SIZE = ...;).

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

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

ПРИМЕЧАНИЕ:
1. Программа должна содержать несколько функций; функция main должна выполнять:
вывод меню, ввод и анализ ответа, вызов на исполнение требуемой функции;
2. в программе нужно предусмотреть проверку правильности ввода данных;
3. Для варианта b) следует модифицировать структуру, определяющую элемент области переполнения, включив в нее длину информации и ее смещение в файле;
4. В варианте b) для работы с файлом использовать функции проекта stdio.h; чтение и запись выполнять с помощью fread() и fwrite(), в которых должна быть указана реальная длина информации.

Обсуждение

Неизвестный
30.05.2012, 12:33
общий
Очень нужна программа до первого июня.
давно
Посетитель
7438
7205
30.05.2012, 16:08
общий
Нужна - сделаем...
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
30.05.2012, 16:14
общий
Огромное спасибо
давно
Посетитель
7438
7205
01.06.2012, 03:39
общий
это ответ
Здравствуйте, Орт Кирилл Валерьевич!
Вот Вам программы на перемешивание сцеплением
а)
[code h=200]#include <locale>
#include <iostream>

using namespace std;

void AddElement(void);
void DelElement(void);
void OutTable(void);
void Exit(void);
int GetNum(void);

const int SIZE = 10;

typedef struct Ofl
{
int key; //ключ элемента
char *info; //указатель на информацию
Ofl *next; //указатель на след. элемент
}Ofl;

char *mesMain[] = //сообщения меню
{
"Включить новый элемент",
"Удалить элемент",
"Вывести таблицу",
"Выход"
};
//количество пунктов меню
int MesMainCount = sizeof( mesMain ) / sizeof( mesMain[0] );
//функции отработки пунктов меню
void ( *funcMain[] )()={AddElement,
DelElement,
OutTable,
Exit};

Ofl *table[SIZE]; //таблица-вектор

//Поиск элемента и места, куда вставить
//Вызывается при добавлении нового элемента
//параметры: ключ и адрес указателя в цепочке next, куда додавим новый элемент
//или NULL, если цепочка пуста
//возвращает true, если элемент найден и false, если не найден
bool Find(int num, Ofl **ppOfl)
{
Ofl *pOfl;
int i = num%SIZE; //функция расстановки - остаток от деления на SIZE=10
//результат - производный ключ

//найдем, есть ли уже заданный ключ
//*ppOfl в итоге будет указывать на предыдущий последний элемент,
//после которого мы вставим новый
for (*ppOfl=NULL,pOfl=table[i]; pOfl!=NULL; pOfl=pOfl->next)
{
*ppOfl = pOfl; //возвращаем указатель предыдущего последнего
//ищем искомый ключ
if (pOfl->key == num) //ключ равен!
return true; //выходим
}
return false; //не нашли, в *ppOfl будет указатель последнего (или NULL)
}

//добавление элемента в таблицу
void AddElement()
{
int num; //индекс нового элемента
char str[80];
Ofl *pOfl; //указатель на текущий элемент
Ofl *pOflPrev; //указатель на элемент, после которого вставим

cout << "Введите ключ элемента: ";
num = GetNum(); //вводим ключ

if(Find(num, &pOflPrev))
{
cout << "Элемент с таким ключем уже есть" << endl;
return;
}
pOfl = new Ofl; //создаем новый элемент
//заполняем поля
pOfl->key = num; //ключ
pOfl->next = NULL; //признак последнего элемента в цепочке
cout << "Введите строку: ";
cin.ignore();
cin.getline(str, 80);
pOfl->info = new char[strlen(str)+1];
strcpy(pOfl->info, str); //добавляем строку

//определимся со ссылкой на наш элемент
if (pOflPrev != NULL) //если вставляется не в начало цепочки
pOflPrev->next = pOfl; //то предыдущий будет на него ссылаться
else
table[num%SIZE] = pOfl; //если первый элемент, то запоминаем ссылку в массиве table
cout << "Элемент добавлен" << endl;
}

//удаление элемента с заданным ключем
void DelElement()
{
int i, num;
Ofl *pOflPrev, *pOfl, *pOflNext;

cout << "Введите ключ элемента: ";
num = GetNum(); //вводим ключ
i = num%SIZE; //функция расстановки - остаток от деления на SIZE=10
//результат - производный ключ

//по всем элементам цепочки для производного ключа
for (pOflPrev=NULL,pOfl=table[i]; pOfl; pOfl=pOflNext)
{
pOflNext = pOfl->next; //указатель на следующего
//сравниваем ключ
if (pOfl->key == num)
{ //выкинем элемент из цепочки указателей
if (pOflPrev == NULL) //первый элемент в цепочке?
table[i] = pOflNext; //пишем в массив table адрес следующего
else //иначе, предыдущий ссылается
pOflPrev->next = pOflNext; //на следующего
delete [] pOfl->info; //удаляем строку
delete pOfl; //и сам элемент
cout << "Элемент удален" << endl;
return;
}
pOflPrev=pOfl; //сдвигаем указатель на предыдущий элемент
}
//прошли всю цепочку, значит не нашли
cout << "Элемент не найден" << endl;
}

//вывод всей таблицы
void OutTable()
{
int i, count = 0; //посчитаем число элементов
Ofl *pOfl;

for(i=0; i<SIZE; i++) //по всем элементам таблицы
{
//по всем элементам цепочек
for (pOfl = table[i]; pOfl; pOfl=pOfl->next)
{
cout << "key = " << pOfl->key
<< ", info = " << pOfl->info
<< endl;
count++;
}
}
if (0 == count) //сообщение для пустой таблицы
cout << "Таблица пуста" << endl;
}

//выход, удалим все элементы
void Exit()
{
Ofl *pOfl, *pOflNext;
for (int i=0; i<SIZE; i++)
{
for (pOfl=table[i]; pOfl; pOfl=pOflNext)
{
pOflNext = pOfl->next; //запомним уазатель на следующего
delete [] pOfl->info; //удаляем текущего
delete pOfl;
}
}
}

//ввод числа
int GetNum()
{
int a;
cin >> a;
while ( !( cin.good() || cin.eof() ) || ( a < 0 ) )
{
cout << "Введите число! " << endl;
cin.clear();
cin.ignore();
cin >> a;
}
return a;
}

//показ меню с вводом номера строки
int ViewMenu(char** mes, int max)
{
int ret;
do
{
//меню
for ( int i = 0; i < max; i++ )
cout << i+1 << ". " << mes[i] << endl;
cout << "Ваш выбор: ";
//вводим число
ret = GetNum();
}
//проверим на допустимость
while ( ret < 1 || ret > max );
//вернем номер строки
return ret;
}

int main()
{
int ret;

system("chcp 1251 >> nul"); //чтобы писалось по-русски
// или так:
// locale::global(locale("Russian_Russia.866"));
do
{
ret = ViewMenu(mesMain, MesMainCount); //выводим меню, вводим номер строки
funcMain[ret-1](); //отрабатываем пункт меню
cout << "--------------------------------" << endl;
if (ret == MesMainCount) //последняя - выход
break;
}
while ( ret );
return 0;
}[/code]
б)
[code h=200]#include <locale>
#include <iostream>

using namespace std;

void ReadTableFromFile(void);
void WriteTableToFile(void);
void AddElement(void);
void DelElement(void);
void OutTable(void);
void Exit(void);
int GetNum(void);

const int SIZE = 10;

typedef struct Ofl
{
int key; //ключ элемента
int seek; //смещение поля info относительно начала строк в файле
int len; //длина info
Ofl *next; //указатель на след. элемент
}Ofl;

char *mesMain[] = //сообщения меню
{
"Включить новый элемент",
"Удалить элемент",
"Вывести таблицу",
"Выход"
};
//количество пунктов меню
int MesMainCount = sizeof( mesMain ) / sizeof( mesMain[0] );
//функции отработки пунктов меню
void ( *funcMain[] )()={AddElement,
DelElement,
OutTable,
Exit};

int StringsOff; //начало строк в файле
Ofl *table[SIZE]; //таблица-вектор
FILE *file = NULL; //указатель на открытый файл
char fName[256];

//чтение таблицы из файла
//формат файла:
//int StringsOff - начало строк в файле
//Ofl *table[SIZE] - таблица (вся), после каждого элемента цепочка элементов
//... - строки info
void ReadTableFromFile()
{
int i;
Ofl *pOfl, *pOflPrev;

cout << "Введите имя файла: ";
cin.getline(fName, 256); //вводим имя файла
file = fopen(fName, "r+b"); //открываем на чтение/запись, тип двоичный
if (NULL == file) //если нет такого
{
file = fopen(fName, "w+b"); //то создаем новый файл
if (file) //создался?
{ //запишем файл с пустой таблицей
//смещение строк равно сумме длин всех указателей
//и самого поля смещения
StringsOff = sizeof(Ofl*) * SIZE + sizeof(int);
//пишем смещение блока строк в файле
fwrite(&StringsOff, sizeof(int), 1, file);
//нулевой массив указателей
fwrite(table, sizeof(Ofl*), SIZE, file);
}
else
cout << "Ошибка создания файла" << endl;
}
else //файл есть
{ //читаем смещение блока строк в файле
fread(&StringsOff, sizeof(int), 1, file);
for (i=0; i<SIZE; i++) //читаем элементы таблицы
{ //читаем указатель в таблице
fread(&pOfl, sizeof(Ofl*), 1, file);
if (pOfl) //ненулевой - дальше будут элементы!
{
while(pOfl) //читаем цепочку элементов, пока указатель ненулевой
{
pOfl = new(Ofl); //создаем элемент
if (table[i] == NULL) //первый?
table[i] = pOfl; //записываем указатель в таблицу
else //непервый - делаем ссылку у предыдущего на текущего
pOflPrev->next = pOfl;
//читаем с файла элемент
fread(pOfl, sizeof(Ofl), 1, file);
pOflPrev = pOfl; //запоминаем текущего, как нового предыдущего
pOfl=pOfl->next; //у последнего в цепочке здесь будет нуль
}
}
else //нулевой - элементов нет!
table[i] = NULL;
}
}
fclose(file); //файл закрываем
}

//запись таблицы в файл (в конце работы)
void WriteTableToFile()
{
Ofl *pOfl;
int i, len;
fpos_t pos; //позиция в файле
void *pStrings; //адрес буфера для чтения массива строк

if (fName[0]) //проверим на наличие имени файла
{
file = fopen(fName, "r+b"); //открываем на чтение/запись
if (file) //открылся?
{
//прочитаем массив строк из файла
//определим длину файла
fseek(file, 0, SEEK_END); //в конец файла
fgetpos(file, &pos); //определяем позицию
fseek(file, StringsOff, SEEK_SET); //в начало массива строк!
len = (int)pos - StringsOff; //длина массива строк

pStrings = malloc(len); //выделим память под массив строк
fread(pStrings, len, 1, file); //прочитаем
fseek(file, 0, SEEK_SET); //позицию в начало файла!

//формируем файл!
fwrite(&StringsOff, sizeof(int), 1, file); //начало массива строк
//выводим таблицу
for (i=0; i<SIZE; i++)
{
//указатель начала цепочки (или 0)
fwrite(&table[i], sizeof(Ofl*), 1, file);
//выводим структуры цепочек
for (pOfl=table[i]; pOfl; pOfl=pOfl->next)
fwrite(pOfl, sizeof(Ofl), 1, file);
}
//запишем массив строк и подправим новое смещение массива строк!
StringsOff = ftell(file); //равно позиции после записи таблицы

fwrite(pStrings, len, 1, file); //пишем сохраненный массив строк

fseek(file, 0, SEEK_SET); //в начало файла!
fwrite(&StringsOff, sizeof(int), 1, file); //и пишем новое смещение массива строк

fclose(file); //файл закрываем
free(pStrings); //освобождаем память под строки
}
else
cout << "Ошибка открытия файла" << endl;
}
else
cout << "Имя файла не задано" << endl;
}

//Поиск элемента и места, куда вставить
//Вызывается при добавлении нового элемента
//параметры: ключ и адрес указателя в цепочке next, куда додавим новый элемент
//или NULL, если цепочка пуста
//возвращает true, если элемент найден и false, если не найден
bool Find(int num, Ofl **ppOfl)
{
Ofl *pOfl;
int i = num%SIZE; //функция расстановки - остаток от деления на SIZE=10
//результат - производный ключ

//найдем, есть ли уже заданный ключ
//*ppOfl в итоге будет указывать на предыдущий последний элемент,
//после которого мы вставим новый
for (*ppOfl=NULL,pOfl=table[i]; pOfl!=NULL; pOfl=pOfl->next)
{
*ppOfl = pOfl; //возвращаем указатель предыдущего последнего
//ищем искомый ключ
if (pOfl->key == num) //ключ равен!
return true; //выходим
}
return false; //не нашли, в *ppOfl будет указатель последнего (или NULL)
}

//добавление элемента в таблицу
void AddElement()
{
int num; //индекс нового элемента
char str[80];
Ofl *pOfl; //указатель на текущий элемент
Ofl *pOflPrev; //указатель на элемент, после которого вставим

cout << "Введите ключ элемента: ";
num = GetNum(); //вводим ключ

if(Find(num, &pOflPrev))
{
cout << "Элемент с таким ключем уже есть" << endl;
return;
}
pOfl = new Ofl; //создаем новый элемент
//заполняем поля
pOfl->key = num; //ключ
pOfl->next = NULL; //признак последнего элемента в цепочке
cout << "Введите строку: ";
cin.ignore();
cin.getline(str, 80);

if (fName[0]) //проверим на наличие имени файла
{
file = fopen(fName, "r+b"); //открываем
if (file) //открылся?
{
//определим смещение строки в массиве строк
fseek(file, 0, SEEK_END); //становимся в конец файла
pOfl->seek = ftell(file)-StringsOff; //запоминаем позицию, как
// смещение в массиве строк поля info
pOfl->len = strlen(str)+1; //запоминаем длину строки
fwrite(str, pOfl->len, 1, file); //и пишем строку в конец файла
fclose(file); //закрываем файл

//определимся со ссылкой на наш элемент
if (pOflPrev != NULL) //если вставляется не в начало цепочки
pOflPrev->next = pOfl; //то предыдущий будет на него ссылаться
else
table[num%SIZE] = pOfl; //если первый элемент, то запоминаем ссылку в массиве table
cout << "Элемент добавлен" << endl;
}
else
cout << "Ошибка открытия файла" << endl;
}
else
cout << "Имя файла не задано" << endl;
}

//удаление элемента с заданным ключем
//файл не используется.
//удаление происходит только в памяти!
void DelElement()
{
int i, num;
Ofl *pOflPrev, *pOfl, *pOflNext;

cout << "Введите ключ элемента: ";
num = GetNum(); //вводим ключ
i = num%SIZE; //функция расстановки - остаток от деления на SIZE=10
//результат - производный ключ

//по всем элементам цепочки для производного ключа
for (pOflPrev=NULL,pOfl=table[i]; pOfl; pOfl=pOflNext)
{
pOflNext = pOfl->next; //указатель на следующего
//сравниваем ключ
if (pOfl->key == num)
{ //выкинем элемент из цепочки указателей
if (pOflPrev == NULL) //первый элемент в цепочке?
table[i] = pOflNext; //пишем в массив table адрес следующего
else //иначе, предыдущий ссылается
pOflPrev->next = pOflNext; //на следующего
delete pOfl; //удаляем элемент
cout << "Элемент удален" << endl;
return;
}
pOflPrev=pOfl; //сдвигаем указатель на предыдущий элемент
}
//прошли всю цепочку, значит не нашли
cout << "Элемент не найден" << endl;
}

//вывод всей таблицы
void OutTable()
{
int i, count = 0; //посчитаем число элементов
Ofl *pOfl;
char str[80];

if (fName[0]) //имя файла задано?
{
file = fopen(fName, "r+b"); //открываем файл
if (file) //открылся?
{
for(i=0; i<SIZE; i++) //по всем элементам таблицы
{
//по всем элементам цепочек
for (pOfl = table[i]; pOfl; pOfl=pOfl->next)
{
fseek(file, pOfl->seek+StringsOff, SEEK_SET); //становимся в позицию, где начинается строка
fread(str, pOfl->len, 1, file); //читаем нужное число байт
cout << "key = " << pOfl->key
<< ", info = " << str
<< endl;
count++;
}
}
fclose(file); //файл закрываем
}
else
cout << "Ошибка открытия файла" << endl;
}
else
cout << "Имя файла не задано" << endl;

if (0 == count) //сообщение для пустой таблицы
cout << "Таблица пуста" << endl;
}

//выход, удалим все элементы
void Exit()
{
Ofl *pOfl, *pOflNext;

WriteTableToFile(); //сохраним таблицу в файле
//удалим элементы таблицы со всеми цепочками
for (int i=0; i<SIZE; i++)
{
for (pOfl=table[i]; pOfl; pOfl=pOflNext)
{
pOflNext = pOfl->next; //запомним уазатель на следующего
delete pOfl;
}
}
}

//ввод числа
int GetNum()
{
int a;
cin >> a;
while ( !( cin.good() || cin.eof() ) || ( a < 0 ) )
{
cout << "Введите число! " << endl;
cin.clear();
cin.ignore();
cin >> a;
}
return a;
}

//показ меню с вводом номера строки
int ViewMenu(char** mes, int max)
{
int ret;
do
{
//меню
for ( int i = 0; i < max; i++ )
cout << i+1 << ". " << mes[i] << endl;
cout << "Ваш выбор: ";
//вводим число
ret = GetNum();
}
//проверим на допустимость
while ( ret < 1 || ret > max );
//вернем номер строки
return ret;
}

int main()
{
int ret;

system("chcp 1251 >> nul"); //чтобы писалось по-русски

// или так:
// locale::global(locale("Russian_Russia.866"));

ReadTableFromFile(); //читаем таблицу из файла (или создаем новый)
do
{
ret = ViewMenu(mesMain, MesMainCount); //выводим меню, вводим номер строки
funcMain[ret-1](); //отрабатываем пункт меню
cout << "--------------------------------" << endl;
if (ret == MesMainCount) //последняя - выход
break;
}
while ( ret );
return 0;
}[/code]
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Форма ответа