Я должен зацикливать частоту из двоичных файлов.
Что я имею в виду, я буду читать символы, присутствующие в файле, а затем вычислять частоту по количеству повторений символа. Я использую этот код. И он отлично работает:
struct Node
{
unsigned char symbol;
int appear;
struct Node *link;
struct Node * left,*right;
};Node * head;
Где-то в основном мне нравится читать файл:
ch = fgetc(fp);
while (fread(&ch,sizeof(ch),1,fp))
{
symbol(ch);
}
fclose(fp);
где функция add_symbol выглядит так:
Но я не могу понять логику этого кода. Может ли кто-нибудь объяснить вопросы, которые я задал в коде?
symbol(unsigned char sym)
{
Node*pt,*pt,*t;
int is_there=0;
pt = pt = head;
while (pt != NULL)
{
if (pt -> symbol == sym)
{
pt -> appear++;
is_there = 1;
break;
}
pt = pt;
pt = pt -> link;
}
if (!is_there)
{
// printf("\n is_there2 : %d\n",!is_there);
printf("sym2 : %d\n", sym);
t = (Node *) malloc(sizeof( Node));
t -> symbol = sym;
t -> appear = 1;
t -> left = NULL;
t -> right = NULL;
t->link = NULL;
if (head == NULL)
{
head = temp;
}
else
{
pt->link = temp;
}
}
}
Чтобы найти ту же частоту, нам нужно сначала сохранить все данные.
(1) Где это делается?
(2) Нам нужно сравнить символ, если это появляется снова или нет?
(3) Пожалуйста, объясните немного больше кода, что логика одинакова в c и c++. Так что любой язык, никаких проблем.
В объяснении у меня есть сомнения, что: предположим, что 1 2 1 3 3 1 2 - символы в двоичном файле. При первом выполнении addymbol мы делаем addymbol (1); , Теперь мы сохраняем "1", чтобы узнать, появится ли какое-либо другое "1" в будущем или нет? поэтому мы делаем символ pt->, если снова равен "1", тогда мы увеличиваем частоту на единицу. Но при втором выполнении addymbol мы делаем addymbol (2); который не равен "1", поэтому снова повторяйте.
В третий раз я получил addymbol (1); , на этот раз я получил "1", который равен ранее сохраненному "1", поэтому увеличивает частоту на "1". Как насчет предыдущего "2"? Поскольку мы читаем файл только один раз, делая
while (fread(&ch,sizeof(ch),1,fp))
{
add_symbol(ch);
}
и если "2" уже пройден, мы не сможем его подсчитать. Как этот код сохраняет этот "2", а также находит его частоту. Пожалуйста, не стесняйтесь спрашивать меня, не по-прежнему ли я оставил мой вопрос?
Код не хранит все данные, он хранит только символы и подсчеты в связанном списке.
Код читает один символ за раз, вызывая add_symbol() для каждого. Функция add_symbol
начинается с поиска символа в связанном списке. Если символ есть, функция просто увеличит счетчик; в противном случае он добавит символ в хвост списка и со счетом 1.
Изменить: по запросу, вот как это выглядело бы, если бы оно было более разложено:
void Huffman::add_symbol(unsigned char sym)
{
Node * foundNode = find_node_in_linked_list(sym);
if(foundNode != NULL)
foundNode->freq++;
else
add_freq1_node_at_end_of_list(sym);
}
Node* Huffman::find_node_in_linked_list(unsigned char sym)
{
Node* pCur = Start;
while(pCur != NULL)
{
if(pCur->symbol == ch)
return pCur;
pCur = pCur->next;
}
return NULL;
}
void Huffman::add_freq1_node_at_end_of_list(unsigned char sym)
{
//Get tail of list
Node* pTail = NULL;
Node* pCur = Start;
while(pCur != NULL)
{
pTail = pCur;
pCur = pCur->next;
}
//Now, pTail is either the last element, or NULL if the list is empty.
//Create the new object
//(should use the new keyword instead, but since the deletion code was not posted...
Node* pNew = static_cast< Node* >(malloc(sizeof *pNew));
if(pNew == NULL)
return;
pNew->symbol = sym;
pNew->freq = 1;
pNew->left = NULL;
pNew->right = NULL;
pNew->next = NULL;
pNew->is_processed = 0;
//Add the new node at the tail
if(pTail != NULL)
pTail->next = pNew;
else
Start = pNew;
}
Обратите внимание, что он менее эффективен, чем большая функция, потому что он проходит через список дважды, когда символ не найден (один раз, чтобы попытаться найти символ, один раз, чтобы найти хвост).
На самом деле, нет причин специально добавлять на хвост, а не вставлять в голову.
Совершенно откровенно связанный список - это не самый эффективный способ хранения счетчиков до 256 символов. Я бы рекомендовал вместо этого использовать таблицу поиска (немой вектор из 256 структур или даже выделенный объект гистограммы, который был бы просто вектором из 256 целых чисел).
Несколько советов по вашему общему дизайну:
Шаг №1: Чтобы подсчитать символы, вы можете использовать простую гистограмму:
include <limits.h>
int histogram[1<<CHAR_BIT] = {0};
unsigned char ch;
while (fread(&ch,sizeof(ch),1,fp))
histogram[ch]++;
Шаг №2: Теперь вам нужно использовать гистограмму, чтобы построить дерево Хаффмана:
Node
, по одному для каждой записи в histogram
со значением больше 0.Node
из кучи.Node
чьи дочерние элементы являются этими двумя элементами Node
.Node
обратно в кучу.Шаг № 3: Теперь, когда у вас есть дерево Хаффмана, обратите внимание на следующее:
Node
созданных в начале предыдущего шага).Вы можете увидеть полный пример:
http://planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=9737&lngWId=3.