Консультация № 190338
25.12.2016, 13:48
0.00 руб.
0 13 1
Здравствуйте! Прошу помощи в следующем вопросе:

Подготовить текстовый файл, содержащий не менее 10 слов. Прочитать данные из этого файла и сформировать двусвязный список, элементы которого имеют тип STRING. Написать программу, подсчитывающую количество элементов списка, которые начинаются и оканчиваются одним и тем же символом.
После завершения работы со списками освободить занимаемую ими динамическую память.

Буду благодарна, если код будет написан на Си. Я смогла написать только основные функции работы с двусвязным и списком и не уверена, что и они верны. Заранее спасибо за помощь!

Приложение:
#include "stdafx.h"
#include <iostream>

using namespace std;
struct ListNode1
{
double info; // значение
ListNode1 *next; //указатель на следующий элемент
ListNode1 *prev; //указатель на предыдущий элемент
};

void AddToList(ListNode1 *&p, double info)
{
if (p) {
if (p->next)
{
AddToList(p->next, info);
}
else
{
ListNode1 *q = new ListNode1;
q->info = info;
q->next = NULL;
q->prev = p;
p->next = q;
}
}
else {
p = new ListNode1;
p->info = info;
p->next = NULL;
p->prev = NULL;
}
}

ListNode1 *FormList1(ListNode1 *&p) //заполняем последовательность c начала
{
int i, n;
double num;
cout « "Введите количество элементов: \n";
cin » n;
cout « "Введите элементы последовательности: \n";
for (i = 0; i < n; i++)
{
cin » num;
AddToList(p, num);

}
return(p);
}

Обсуждение

давно
Посетитель
7438
7205
26.12.2016, 17:05
общий
это ответ
Здравствуйте, Usagisan!
1) Вы говорите о С, а сами используете элементы C++, такие как new, cin , cout
2) Полем данных должна быть строка, а не double
3) Должен быть двунаправленный список, т.е. должны быть и голова, и хвост
3) Надо читать с файла, а не с консоли
Посмотрите, как я сделал (на чистом С):
[code h=200]#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>

typedef struct ListNode1
{
char* info; //указатель на строку
ListNode1* next; //указатель на следующий элемент
ListNode1* prev; //указатель на предыдущий элемент
}ListNode1;

//указатели на голову и хвост определим в глобальной памяти
ListNode1* pHead = NULL;
ListNode1* pTail = NULL;

//параметром укажем только значение поля info
void AddToList(char * info)
{
ListNode1* q = (ListNode1*) malloc(sizeof(ListNode1)); //выделим память под узел
q->info = (char*)malloc(strlen(info)+1); //и под строку
strcpy(q->info, info); //копируем строку
q->next = NULL; //узел всегда будет последним
if (pTail) //указатель хвоста непуст?
{
q->prev = pTail; //для нового предыдущим станет старый хвост
pTail->next = q; //для бывшего хвоста следующим - новый
}
else
{ //новый - единственный, будет и головой, и хвостом
q->prev = NULL; //для головы предыдущего нет
pHead = q; //голова списка - новый узел
}
pTail = q; //новый становится новым хвостом
}

//параметром укажем имя файла
int FormList1(char *fName)
{
char string[1024]; //буфер для чтения

FILE *fp = fopen(fName, "r") ; //открываем файл на чтение

if (fp) //открылся?
{
while (-1 != fscanf(fp, "%s", string)) //читаем, пока читается
{
AddToList(string); //и включаем очередную строку в список
}
fclose(fp); //закрываем файл
return true; //файл считан
}
return false; //ошибка, скорее всего, файл не найден
}

//подсчитываем слова, у которых одинаковые первая и последняя буквы
int GetCount(void)
{
int count = 0;
ListNode1 * node;

for(node=pHead; node; node=node->next) //по всем узлам
//сравниваем буквы, если равны, получим 1, иначе 0
count += (node->info[0] == node->info[strlen(node->info)-1]);

return count; //возвращаем счетчик
}

void DelList() //освобождаем память списка
{ //воспользуемся указателями pHead и pTail, все равно они уже не нужны
while(pHead) //пока что-то есть
{
pTail = pHead->next; //сохраним адрес следующего
free(pHead->info); //сначала освободим память строки
free(pHead); //потом память самого узла
pHead = pTail; //адрес следующего
}
}

int main()
{
if (FormList1("test.txt")) //формируем список из файла
{
printf("Count = %d\n", GetCount()); //выводим количество слов с одинаковыми первой и последней буквой
DelList(); //освобождаем память
}
else
printf ("File 'test.txt' not found!\n"); //файл не найден
return 0;
}
[/code]
test.txt
Код:
asdasda 3123123 treter 456456 sdfsdf 45454544 
asdasdas gdfgdfgdfg tttttt 5555555 434343 5555556765
5
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
400314
8
26.12.2016, 18:52
общий
Большое спасибо!
Да, я прекрасно знаю об этих косяках. Так уж вышло, что я просто скопировала функции из тетради, особо не разоравшись:С Больше не буду так
давно
Посетитель
400314
8
26.12.2016, 19:05
общий
Тут такая проблема: компилятор выдаёт ошибку в 9 и 10 строке, а так же в 51 и 53
давно
Посетитель
7438
7205
26.12.2016, 19:27
общий
Адресаты:
51 и 53 - не знает, что такое true и false
#define true 1
#define false 0
9 и 10 - попробуйте, как было у Вас
struct ListNode1
{
char * info; // значение
ListNode1 *next; //указатель на следующий элемент
ListNode1 *prev; //указатель на предыдущий элемент
};
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
400314
8
27.12.2016, 18:35
общий
Всё, заработало. Можете объяснить один момент? q - узел, а для чего он нам нужен?
давно
Посетитель
7438
7205
27.12.2016, 18:42
общий
Адресаты:
Это переменная, в которой хранится адрес вновь созданного узла.
Потом адрес этого узла вставляется в список узлов. После чего сама переменная q уже становится не нужна.
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
400314
8
27.12.2016, 18:48
общий
А зачем нам указатель на голову и хвост списка? Просто мы не использовали эти указатели, лишь на предыдущий и следующий элемент.
давно
Посетитель
400314
8
27.12.2016, 18:52
общий
И почему мы их создаём не в структуре?
давно
Посетитель
7438
7205
27.12.2016, 19:02
общий
Адресаты:
Если все будет в элементах списка, то как мы найдем эти элементы?
Надо же иметь адрес начала (как минимум), адрес хвоста можно не использовать. Но с ним удобнее.
Если адрес хвоста не использовать, то при вставке надо постоянно искать хвост.
Кроме того, бывает, что надо проходить список в обратном порядке (раз есть ссылка на предыдущий элемент).
Тогда иметь адрес хвоста просто необходимо.
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
400314
8
28.12.2016, 16:45
общий
Можете, пожалуйста, пояснить цикл, который начинается с 62 строки?
давно
Посетитель
7438
7205
28.12.2016, 17:02
общий
Адресаты:
//проходим по всем узлам, начиная с головы.
//т.к. pHead портить нельзя, используем дополнительную переменную node
//циклим, пока адрес узла не 0, т.е. пока не пройдем по всей цепочке
for(node=pHead; node; node=node->next)
//для каждого узла сравниваем буквы, если равны, получим 1, иначе 0
//node->info[0] даст нам первую букву слова node->info
//strlen(node->info)-1 дает адрес последней буквы слова
//node->info[strlen(node->info)-1] даст последнюю букву
//node->info[0] == node->info[strlen(node->info)-1] проверяем на равенство,
// в итоге получим 1, если равно, или 0, если неравно
//ну и складываем результат сравнения
count += (node->info[0] == node->info[strlen(node->info)-1]);
//можно было записать:
// if (node->info[0] == node->info[strlen(node->info)-1])
// count++;
//результат тот же
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
400314
8
28.12.2016, 17:12
общий
Большое спасибо за такие подробные ответы!
давно
Посетитель
7438
7205
28.12.2016, 17:23
общий
Адресаты:
Главное, чтобы на пользу
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Форма ответа