RFpro.ru: Программирование на C / C++
Хостинг портала RFpro.ru: РАССЫЛКИ ПОРТАЛА RFPRO.RU
Лучшие эксперты по данной тематике
/ КОМПЬЮТЕРЫ И СОФТ / Программирование / C/C++
Консультация # 186114: Здравствуйте! У меня возникли сложности с таким вопросом: Написать программу для работы с перемешанной таблицей, использующей перемешивание сцеплением, по запросу оператора. Перемешанная таблица представлена массивом указателей на элементы таблицы, имеющие следующую структуру: struct Item{ int key; /* ключ элемента char *info; /*указ... Здравствуйте! У меня возникли сложности с таким вопросом:
Дата отправки: 20.05.2012, 17:05 Консультирует Лысков Игорь Витальевич (Старший модератор): Здравствуйте, ШмонинЕА! Код : #include <locale> #include <iostream> using namespace std; void AddElement(void); void DelElement(void); void SearchRange(void); void OutTable(void); void Exit(void); int GetNum(void); const int SIZE = 10; typedef struct Item { int key; //ключ элемента char *info; //указатель на информацию Item *next; //указатель на след. элемент }ITEM; char *mesMain[] = //сообщения меню { "Включить новый элемент", "Удалить элемент", "Найти элемент из диапозона ключей", "Вывести таблицу", "Выход" }; //количество пунктов меню int MesMainCount = sizeof( mesMain ) / sizeof( mesMain[0] ); //функции отработки пунктов меню void ( *funcMain[] )()={AddElement, DelElement, SearchRange, OutTable, Exit}; ITEM *table[SIZE]; //таблица-вектор //Поиск элемента и места, куда вставить //Вызывается при добавлении нового элемента //параметры: ключ и адрес указателя в цепочке next, куда додавим новый элемент //или NULL, если цепочка пуста //возвращает true, если элемент найден и false, если не найден bool Find(int num, ITEM **ppItem) { ITEM *pItem; int i = num%SIZE; //функция расстановки - остаток от деления на SIZE=10 //результат - производный ключ //найдем, есть ли уже заданный ключ //*ppItem в итоге будет указывать на предыдущий последний элемент, //после которого мы вставим новый for (*ppItem=NULL,pItem=table[i]; pItem!=NULL; pItem=pItem->next) { *ppItem = pItem; //возвращаем указатель предыдущего последнего //ищем искомый ключ if (pItem->key == num) //ключ равен! return true; //выходим } return false; //не нашли, в *ppItem будет указатель последнего (или NULL) } //Поиск по всей таблице элементов с ключом в заданном интервале [min, max] //Для первого вызова необходимо задать *idx = -1 //После каждого вызова по этим адресам будут возвращаться индекс в таблице и адрес //удовлетворяющего условию элемента. //Повторный вызов будет продолжен с того же места. //Т.о., можно найти все элементы в цикле bool FindRange(int min, int max, int *idx, ITEM **ppItem) { ITEM *pItem; int i; if (min > max) //на всякий случай, проверим min < max { i = min; min = max; max = i; } if (*idx == -1) //первый вызов? { i = 0; //начинаем с 0-го индекса pItem=table[0]; } else //продолжение поиска { i = *idx; //индекс pItem = (*ppItem)->next; //следующий за обработанным! } while (i<SIZE) //по всей таблице { for(; pItem; pItem=pItem->next) //по элементам одной цепочки { //проверяем условие попадания ключа в интервал if ((pItem->key >= min) && (pItem->key <= max)) { //попал *idx = i; //сохраняем индекс *ppItem = pItem; //и указатель на элемент return true; //нашли! } } pItem=table[++i]; //на первый элемент следующей цепочки //для последней будет несуществующий адрес //но мы выйдем по while(i<SIZE) ! } return false; //больше нет } //добавление элемента в таблицу void AddElement() { int num; //индекс нового элемента char str[80]; ITEM *pItem; //указатель на текущий элемент ITEM *pItemPrev; //указатель на элемент, после которого вставим cout << "Введите ключ элемента: "; num = GetNum(); //вводим ключ if(Find(num, &pItemPrev)) { cout << "Элемент с таким ключем уже есть" << endl; return; } pItem = new ITEM; //создаем новый элемент //заполняем поля pItem->key = num; //ключ pItem->next = NULL; //признак последнего элемента в цепочке cout << "Введите строку: "; cin.ignore(); cin.getline(str, 80); pItem->info = new char[strlen(str)+1]; strcpy(pItem->info, str); //добавляем строку //определимся со ссылкой на наш элемент if (pItemPrev != NULL) //если вставляется не в начало цепочки pItemPrev->next = pItem; //то предыдущий будет на него ссылаться else table[num%SIZE] = pItem; //если первый элемент, то запоминаем ссылку в массиве table cout << "Элемент добавлен" << endl; } //поиск элементов из интервала ключей void SearchRange() { int i = -1; //для поиска с начала таблицы ITEM *pItem; int count, min, max; cout << "Введите минимальный ключ диапозона: "; min = GetNum(); //вводим ключ cout << "Введите максимальный ключ диапозона: "; max = GetNum(); //вводим ключ count = 0; //посчитаем, чтобы определить нашли или нет while (FindRange(min, max, &i, &pItem)) { //выводим cout << "key = " << pItem->key //ключ << ", info = " << pItem->info //строка << endl; count++; //считаем } if (0==count) //выведем сообщение, если не нашли cout << "Элементы не найдены" << endl; } //удаление элемента с заданным ключем void DelElement() { int i, num; ITEM *pItemPrev, *pItem, *pItemNext; cout << "Введите ключ элемента: "; num = GetNum(); //вводим ключ i = num%SIZE; //функция расстановки - остаток от деления на SIZE=10 //результат - производный ключ //по всем элементам цепочки для производного ключа for (pItemPrev=NULL,pItem=table[i]; pItem; pItem=pItemNext) { pItemNext = pItem->next; //указатель на следующего //сравниваем ключ if (pItem->key == num) { //выкинем элемент из цепочки указателей if (pItemPrev == NULL) //первый элемент в цепочке? table[i] = pItemNext; //пишем в массив table адрес следующего else //иначе, предыдущий ссылается pItemPrev->next = pItemNext; //на следующего delete [] pItem->info; //удаляем строку delete pItem; //и сам элемент cout << "Элемент удален" << endl; return; } pItemPrev=pItem; //сдвигаем указатель на предыдущий элемент } //прошли всю цепочку, значит не нашли cout << "Элемент не найден" << endl; } //вывод всей таблицы void OutTable() { int i, count = 0; //посчитаем число элементов ITEM *pItem; for(i=0; i<SIZE; i++) //по всем элементам таблицы { //по всем элементам цепочек for (pItem = table[i]; pItem; pItem=pItem->next) { cout << "key = " << pItem->key << ", info = " << pItem->info << endl; count++; } } if (0 == count) //сообщение для пустой таблицы cout << "Таблица пуста" << endl; } //выход, удалим все элементы void Exit() { ITEM *pItem, *pItemNext; for (int i=0; i<SIZE; i++) { for (pItem=table[i]; pItem; pItem=pItemNext) { pItemNext = pItem->next; //запомним уазатель на следующего delete [] pItem->info; //удаляем текущего delete pItem; } } } //ввод числа 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; } б) Код : #include <locale> #include <iostream> using namespace std; void ReadTableFromFile(void); void WriteTableToFile(void); void AddElement(void); void DelElement(void); void SearchRange(void); void OutTable(void); void Exit(void); int GetNum(void); const int SIZE = 10; typedef struct Item { int key; //ключ элемента int seek; //смещение поля info относительно начала строк в файле int len; //длина info Item *next; //указатель на след. элемент }ITEM; char *mesMain[] = //сообщения меню { "Включить новый элемент", "Удалить элемент", "Найти элементы из диапозона ключей", "Вывести таблицу", "Выход" }; //количество пунктов меню int MesMainCount = sizeof( mesMain ) / sizeof( mesMain[0] ); //функции отработки пунктов меню void ( *funcMain[] )()={AddElement, DelElement, SearchRange, OutTable, Exit}; int StringsOff; //начало строк в файле ITEM *table[SIZE]; //таблица-вектор FILE *file = NULL; //указатель на открытый файл char fName[256]; //чтение таблицы из файла //формат файла: //int StringsOff - начало строк в файле //ITEM *table[SIZE] - таблица (вся), после каждого элемента цепочка элементов //... - строки info void ReadTableFromFile() { int i; ITEM *pItem, *pItemPrev; cout << "Введите имя файла: "; cin.getline(fName, 256); //вводим имя файла file = fopen(fName, "r+b"); //открываем на чтение/запись, тип двоичный if (NULL == file) //если нет такого { file = fopen(fName, "w+b"); //то создаем новый файл if (file) //создался? { //запишем файл с пустой таблицей //смещение строк равно сумме длин всех указателей //и самого поля смещения StringsOff = sizeof(ITEM*) * SIZE + sizeof(int); //пишем смещение блока строк в файле fwrite(&StringsOff, sizeof(int), 1, file); //нулевой массив указателей fwrite(table, sizeof(ITEM*), SIZE, file); } else cout << "Ошибка создания файла" << endl; } else //файл есть { //читаем смещение блока строк в файле fread(&StringsOff, sizeof(int), 1, file); for (i=0; i<SIZE; i++) //читаем элементы таблицы { //читаем указатель в таблице fread(&pItem, sizeof(ITEM*), 1, file); if (pItem) //ненулевой - дальше будут элементы! { while(pItem) //читаем цепочку элементов, пока указатель ненулевой { pItem = new(ITEM); //создаем элемент if (table[i] == NULL) //первый? table[i] = pItem; //записываем указатель в таблицу else //непервый - делаем ссылку у предыдущего на текущего pItemPrev->next = pItem; //читаем с файла элемент fread(pItem, sizeof(ITEM), 1, file); pItemPrev = pItem; //запоминаем текущего, как нового предыдущего pItem=pItem->next; //у последнего в цепочке здесь будет нуль } } else //нулевой - элементов нет! table[i] = NULL; } } fclose(file); //файл закрываем } //запись таблицы в файл (в конце работы) void WriteTableToFile() { ITEM *pItem; 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(ITEM*), 1, file); //выводим структуры цепочек for (pItem=table[i]; pItem; pItem=pItem->next) fwrite(pItem, sizeof(ITEM), 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, ITEM **ppItem) { ITEM *pItem; int i = num%SIZE; //функция расстановки - остаток от деления на SIZE=10 //результат - производный ключ //найдем, есть ли уже заданный ключ //*ppItem в итоге будет указывать на предыдущий последний элемент, //после которого мы вставим новый for (*ppItem=NULL,pItem=table[i]; pItem!=NULL; pItem=pItem->next) { *ppItem = pItem; //возвращаем указатель предыдущего последнего //ищем искомый ключ if (pItem->key == num) //ключ равен! return true; //выходим } return false; //не нашли, в *ppItem будет указатель последнего (или NULL) } //Поиск по всей таблице элементов с ключом в заданном интервале [min, max] //Для первого вызова необходимо задать *idx = -1 //После каждого вызова по этим адресам будут возвращаться индекс в таблице и адрес //удовлетворяющего условию элемента. //Повторный вызов будет продолжен с того же места. //Т.о., можно найти все элементы в цикле bool FindRange(int min, int max, int *idx, ITEM **ppItem) { ITEM *pItem; int i; if (min > max) //на всякий случай, проверим min < max { i = min; min = max; max = i; } if (*idx == -1) //первый вызов? { i = 0; //начинаем с 0-го индекса pItem=table[0]; } else //продолжение поиска { i = *idx; //индекс pItem = (*ppItem)->next; //следующий за обработанным! } while (i<SIZE) //по всей таблице { for(; pItem; pItem=pItem->next) //по элементам одной цепочки { //проверяем условие попадания ключа в интервал if ((pItem->key >= min) && (pItem->key <= max)) { //попал *idx = i; //сохраняем индекс *ppItem = pItem; //и указатель на элемент return true; //нашли! } } pItem=table[++i]; //на первый элемент следующей цепочки //для последней будет несуществующий адрес //но мы выйдем по while(i<SIZE) ! } return false; //больше нет } //добавление элемента в таблицу void AddElement() { int num; //индекс нового элемента char str[80]; ITEM *pItem; //указатель на текущий элемент ITEM *pItemPrev; //указатель на элемент, после которого вставим cout << "Введите ключ элемента: "; num = GetNum(); //вводим ключ if(Find(num, &pItemPrev)) { cout << "Элемент с таким ключем уже есть" << endl; return; } pItem = new ITEM; //создаем новый элемент //заполняем поля pItem->key = num; //ключ pItem->next = NULL; //признак последнего элемента в цепочке cout << "Введите строку: "; cin.ignore(); cin.getline(str, 80); if (fName[0]) //проверим на наличие имени файла { file = fopen(fName, "r+b"); //открываем if (file) //открылся? { //определим смещение строки в массиве строк fseek(file, 0, SEEK_END); //становимся в конец файла pItem->seek = ftell(file)-StringsOff; //запоминаем позицию, как // смещение в массиве строк поля info pItem->len = strlen(str)+1; //запоминаем длину строки fwrite(str, pItem->len, 1, file); //и пишем строку в конец файла fclose(file); //закрываем файл //определимся со ссылкой на наш элемент if (pItemPrev != NULL) //если вставляется не в начало цепочки pItemPrev->next = pItem; //то предыдущий будет на него ссылаться else table[num%SIZE] = pItem; //если первый элемент, то запоминаем ссылку в массиве table cout << "Элемент добавлен" << endl; } else cout << "Ошибка открытия файла" << endl; } else cout << "Имя файла не задано" << endl; } //поиск элемента всех версий //поиск элементов из интервала ключей void SearchRange() { int i = -1; //для поиска с начала таблицы ITEM *pItem; int count, min, max; char str[80]; cout << "Введите минимальный ключ диапозона: "; min = GetNum(); //вводим ключ cout << "Введите максимальный ключ диапозона: "; max = GetNum(); //вводим ключ count = 0; //посчитаем, чтобы определить нашли или нет if (fName[0]) //имя файла задано? { file = fopen(fName, "r+b"); //открываем файл if (file) //открылся? { while (FindRange(min, max, &i, &pItem)) { fseek(file, pItem->seek+StringsOff, SEEK_SET); //становимся в позицию, где начинается строка fread(str, pItem->len, 1, file); //читаем нужное число байт //выводим cout << "key = " << pItem->key //ключ << ", info = " << str //строка << endl; count++; //считаем } fclose(file); //файл закрываем } else cout << "Ошибка открытия файла" << endl; } else cout << "Имя файла не задано" << endl; if (0==count) //выведем сообщение, если не нашли cout << "Элементы не найдены" << endl; } //удаление элемента с заданным ключем //файл не используется. //удаление происходит только в памяти! void DelElement() { int i, num; ITEM *pItemPrev, *pItem, *pItemNext; cout << "Введите ключ элемента: "; num = GetNum(); //вводим ключ i = num%SIZE; //функция расстановки - остаток от деления на SIZE=10 //результат - производный ключ //по всем элементам цепочки для производного ключа for (pItemPrev=NULL,pItem=table[i]; pItem; pItem=pItemNext) { pItemNext = pItem->next; //указатель на следующего //сравниваем ключ if (pItem->key == num) { //выкинем элемент из цепочки указателей if (pItemPrev == NULL) //первый элемент в цепочке? table[i] = pItemNext; //пишем в массив table адрес следующего else //иначе, предыдущий ссылается pItemPrev->next = pItemNext; //на следующего delete pItem; //удаляем элемент cout << "Элемент удален" << endl; return; } pItemPrev=pItem; //сдвигаем указатель на предыдущий элемент } //прошли всю цепочку, значит не нашли cout << "Элемент не найден" << endl; } //вывод всей таблицы void OutTable() { int i, count = 0; //посчитаем число элементов ITEM *pItem; char str[80]; if (fName[0]) //имя файла задано? { file = fopen(fName, "r+b"); //открываем файл if (file) //открылся? { for(i=0; i<SIZE; i++) //по всем элементам таблицы { //по всем элементам цепочек for (pItem = table[i]; pItem; pItem=pItem->next) { fseek(file, pItem->seek+StringsOff, SEEK_SET); //становимся в позицию, где начинается строка fread(str, pItem->len, 1, file); //читаем нужное число байт cout << "key = " << pItem->key << ", info = " << str << endl; count++; } } fclose(file); //файл закрываем } else cout << "Ошибка открытия файла" << endl; } else cout << "Имя файла не задано" << endl; if (0 == count) //сообщение для пустой таблицы cout << "Таблица пуста" << endl; } //выход, удалим все элементы void Exit() { ITEM *pItem, *pItemNext; WriteTableToFile(); //сохраним таблицу в файле //удалим элементы таблицы со всеми цепочками for (int i=0; i<SIZE; i++) { for (pItem=table[i]; pItem; pItem=pItemNext) { pItemNext = pItem->next; //запомним уазатель на следующего delete pItem; } } } //ввод числа 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; }
Оценить выпуск | Задать вопрос экспертам
главная страница
|
стать участником
|
получить консультацию
© 2001-2012, Портал RFPRO.RU, Россия
Авторское право: ООО "Мастер-Эксперт Про" Калашников О.А. | Гладенюк А.Г. Хостинг: Версия системы: 2011.6.36 от 26.01.2012 |
В избранное | ||