I'm having issues to correct my code so that it works as I want it.
I have three arrays given in this example:
char arr[MAX_ELEMENTS][MAX_LENGTH] = {"ABS","ABS","ABS","ACT","ACT","PPB","PPB","QQQ","QQQ"};
char race[MAX_ELEMENTS][MAX_LENGTH] = {"PARI", "PARI", "LOND", "PARI", "PARI", "CYKA", "LOND", "CYKA", "PARI"};
int freq[MAX_ELEMENTS];
I wish to create a function that can count the amount of occurrences of string elements in arr[] and store them in freq[]. Apart from that I also wish to know in what race[] there have been the most occurrences of given arr[].
To demonstrate this here is an example of what output I wish to receive when the function works:
In Race [PARI] the highest occurence was [ABS] with 3 occurences!
In Race [LOND] the highest occurence was [ACT] with 1 occurences!
.....
Currently, I am able to count the occurrences of arr[] in freq[] but I can't associate them with their respective race[] and give that output..
for(i=0; i<size; i++)
{
count = 1;
for(j=i+1; j<size; j++)
{
/* If duplicate element is found */
if(strcmp(arr[i], arr[j])==0)
{
count++;
/* Make sure not to count frequency of same element again */
freq[j] = 0;
}
}
/* If frequency of current element is not counted */
if(freq[i] != 0)
{
freq[i] = count;
}
}
Giving me currently :
ABS occurs 3 times.
ACT occurs 2 times.
etc. etc...
But I don't know how I can associate them with the race[] and only count them if a given race.
You probably have to use struct here to format your data.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#define true 1
#define len 100
#define elms 10
struct NODE;
#define Node struct NODE
struct NODE {
unsigned long int val;
int count;
char name[len];
Node *left;
Node *right;
};
Node * makeNode(char * str, unsigned long int val){
Node * tmp = (Node *)malloc(sizeof(Node));
strcpy(tmp->name, str);
tmp->val = val;
tmp->left = NULL;
tmp->right = NULL;
tmp->count = 1;
return tmp;
}
unsigned long int getHash(char * name){
int prime = 19;
int i = 0;
unsigned long int val = 0;
while(name[i]!='\0'){
val += (name[i] * pow(prime, i) );
++i;
}
return val;
}
void insert(Node * root, char * name){
Node * newnode;
int val = getHash(name);
Node * tmp = root;
while(tmp != NULL) {
if ( tmp->val == val){
tmp->count += 1;
break;
}
if (val > tmp->val){
if( tmp->right != NULL)
tmp = tmp->right;
else{
tmp->right = makeNode(name, val);
break;
}
}else {
if( tmp->left != NULL)
tmp = tmp->left;
else{
tmp -> left = makeNode(name, val);
break;
}
}
}
}
Node * find(Node * root, char * name){
int val = getHash(name);
Node * tmp = root;
while(tmp != NULL){
if(tmp -> val == val){
return tmp;
}else if (val > tmp->val){
tmp = tmp->right;
}else{
tmp = tmp->left;
}
}
return NULL;
}
struct Race {
char name[len];
char elements[elms][len];
};
char arr[elms][len] = {"ABS","ABS","ABS","ACT","ACT","PPB","PPB","QQQ","QQQ"};
char race[elms][len] = {"PARI", "PARI", "LOND", "PARI", "PARI", "CYKA", "LOND", "CYKA", "PARI"};
int freq[elms];
void copyArray(char dest[elms][len], char src[elms][len] ){
int i = 0;
while(strlen(src[i]) > 0){
strcpy(dest[i],src[i]);
++i;
}
}
int main(){
Node * root = makeNode("root", 0);
int i = 0;
while(strlen(arr[i]) > 0){
insert(root,arr[i]);
++i;
}
i = 0;
while(strlen(arr[i]) > 0){
Node * r = find(root,arr[i]);
printf("found %s, count = %ld\n", r->name, r->count);
++i;
}
// make representation of race
struct Race r1, r2;
strcpy(r1.name, "PARI");
{
char tmp[elms][len] = { "ABS", "PPB", "QQQ" };
copyArray(r1.elements, tmp);
}
strcpy(r2.name, "LOND");
{
char tmp[elms][len] = { "ACT" };
copyArray(r2.elements, tmp);
}
struct Race races[2] = {r1, r2};
i = 0;
while(i < 2){
struct Race * current = &races[i];
printf("for %s", current->name);
Node * max = NULL;
int m = -1;
int j = 0;
while(strlen(current->elements[j]) > 0){
Node * tmp = find(root, current->elements[j]);
if( tmp != NULL && tmp->count > m) {
max = tmp;
m = tmp->count;
}
++j;
}
if (max != NULL){
printf(" max is %s : %d\n", max->name, max->count);
}else{
printf(" max is None\n");
}
++i;
}
return 0;
}
Basically you have to format you data, and specify link between them. Here I used Binary tree and Rabin karp hashing technique to store data efficiently.
Binary tree is best way to solve counting problem, since the search operation fairly cheap. and Rabin karp hashing technique will avoid string comparison every time.
And I create a struct called Race to store all related elements of that race. so the algorithm is going to be.
let arr be array of elements
let races be array of races
for each race in races
define related element
#find occurrence now
#Binary tree will increment count if element already exist.
let binary_tree be a Binary Tree
for each element in arr
add element to binary_tree
# now we have all the elements with it's count
# let's iterate through races now
for each race in races
m = null
for element in race.elements
node = find_element_in_binary_tree(element)
if node is not null
m = max(m, node)
if m is not null then
print m
else
print not found
First, initializations, note the []s
char arr[][MAX_LENGTH] = {"ABS","ABS","ABS","ACT","ACT","PPB","PPB","QQQ","QQQ"};
char race[][MAX_LENGTH] = {"PARI","PARI","LOND","PARI","PARI","CYKA","LOND","CYKA","PARI"};
int freq[MAX_ELEMENTS];
int n = sizeof(arr)/sizeof(*arr); // get actual number of used items
int i,j;
int max = 0; // init max to 0
The main loop goes through arr and race, and whenever a dupe is found at [j] (after [i]), "invalidate" the dupe ("already processed") by setting its first char to 0 (empty string).
Note that j starts from i and not i+1 to ensure freq is at least 1, even for the first non-dupes items.
for(i=0 ; i<n ; i++) {
freq[i] = 0; // ensure freq is 0 for any item
if ( ! *arr[i]) continue; // skip already processed items
for(j=i ; j<n ; j++) { // j=i, not i+1!
if (!strcmp(arr[i],arr[j]) && !strcmp(race[i],race[j])) {
freq[i]++; // update max if necessary
if (freq[i] > max) max = freq[i];
if (j > i) *arr[j] = 0; // invalidate that arr element
}
}
}
Finally display the max appearances, including ties
printf("Items at max=%d:\n", max);
for(i=0 ; i<n ; i++) {
if (freq[i] == max) { // skipped items are never displayed (max cannot be 0)
printf("%s / %s\n", arr[i],race[i]);
}
}
(no need to check for "invalidation" as max will be >0, and all invalidated items have freq[i] == 0)
Related
I have a project, that generates a Linked List, delete them and show this at the User. Now, I want to sort the list.
My struct:
typedef struct YugiohCard {
char Name[100];
char CardType[20];
int Level;
int Rank;
int PendulumStage;
int Link;
int ATK;
int DEF;
char Property[20];
char MonsterType[40];
char CardType2[30];
char Description[500];
struct YugiohCard* pNext;
struct YugiohCard* pPrev;
} struYugiohCard;
When the User says: "CardType2 Ascending" then the program sort the list by CardType2 and Ascending.
In this case alphematicaly. It is also possible to sort by the other struct contents(Monstertyp, ATK, DEF, etc.). Ascending or Descending.
How can I do it without things from C++?
Sorry for my bad English. I'm not very well at this.
Edit:
Here is my complete Code:
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "time.h"
typedef struct YugiohCard {
char Name[100];
char CardType[20];
int Level;
int Rank;
int PendulumStage;
int Link;
int ATK;
int DEF;
char Property[20];
char MonsterType[40];
char CardType2[30];
char Description[500];
struct YugiohCard* pNext;
struct YugiohCard* pPrev;
} struYugiohCard;
bool OutputList(struYugiohCard* pStart)
{
int count = 0;
struYugiohCard* current = pStart; // Initialize current
while (current != NULL)
{
count++;
current = current->pNext;
}
char answer[265];
int CountetCardsThatWillBeOutputet;
printf("How many Yugioh cards would you like to spend? 0 means all,
otherwise the number counts. Number of elements in list: %i Input:",
count);
fgets(answer, 265, stdin);
CountetCardsThatWillBeOutputet = atoi(answer);
int countOutputetCards = 0;
if (CountetCardsThatWillBeOutputet > count)
{
printf("Please enter a correct number!");
system("pause");
return false;
}
else if (CountetCardsThatWillBeOutputet == 0)
{
CountetCardsThatWillBeOutputet = count;
}
system("cls");
printf("%10s %20s %10s %10s %20s %10s %10s %10s %20s %20s %20s %20s\n",
"Name", "CardType", "Level", "Rank", "PendulumStage", "Link", "ATK",
"DEF", "Property", "MonsterType", "CardType2", "Description");
for (struYugiohCard* pOut = pStart; pOut != NULL; pOut = pOut->pNext)
{
printf("%10s %20s %10i %10i %20i %10i %10i %10i %20s %20s %20s
%20s\n", pOut->Name, pOut->CardType, pOut->Level, pOut-
>Rank, pOut->PendelumStage, pOut->Link, pOut->ATK, pOut->DEF,
pOut->Property, pOut->MonsterType, pOut->CardType2, pOut-
>Description);
countOutputetCards++;
if (countOutputetCards == CountetCardsThatWillBeOutputet )
{
break;
}
}
system("pause");
}
void DeleteList(struYugiohCard** head_ref)
{
struct YugiohCard* prev = *head_ref;
while (*head_ref)
{
*head_ref = (*head_ref)->pNext;
free(prev);
prev = *head_ref;
}
}
struYugiohCard* CreateList()
{
system("cls");
char answer[265];
int countedCards;
printf("\nHow many Yugioh cards would you like to create? Please enter
only enter numbers, otherwise you'll crash.");
fgets(answer, 265, stdin);
countedCards = atoi(answer);
struYugiohCard* pFirst = NULL;
for (int i = 0; i < countedCards; i++)
{
struYugiohCard* pNew =
(struYugiohCard*)malloc(sizeof(struYugiohCard));
if (pNew == NULL) break;
pNew->Name[0] = 'A' + rand() % 26;
pNew->Name[1] = '\0';
pNew->CardType[0] = 'A' + rand() % 26;
pNew->CardType[1] = '\0';
pNew->Level = 1 + rand() % 12;
pNew->Rank = 1 + rand() % 13;
pNew->PendulumStage = 1 + rand() % 12;
pNew->Link = 1 + rand() % 8;
pNew->ATK = rand() % 10001;
pNew->DEF = rand() % 10001;
pNew->Property[0] = 'A' + rand() % 26;
pNew->Property[1] = '\0';
pNew->MonsterType[0] = 'A' + rand() % 26;
pNew->MonsterType[1] = '\0';
pNew->CardType2[0] = 'A' + rand() % 26;
pNew->CardType2[1] = '\0';
pNew->Description[0] = 'A' + rand() % 26;
pNew->Description[1] = '\0';
if (pFirst != NULL)
{
pNew->pNext = pFirst;
}
else
{
pNew->pNext = NULL;
}
pFirst = pNew;
}
return pFirst;
}
int main()
{
struYugiohCard* pStart = NULL;
printf("\nIMPORTANT: Please maximize the window, otherwise it will not
represents everything correctly.");
do
{
system("cls");
printf("\nDo you want to create a Yugioh card list (YKE) that
Delete Yugioh card list(YKL), a single Yugioh card
delete(EYKL), sort the list(YKS), the Yugioh-
Output card list(YKA) or the program
close(Prsc):");
char answer[265];
fgets(answer, 265, stdin);
if (strcmp(answer, "YKE\n") == 0)
{
pStart = CreateList();
}
else if (strcmp(answer, "YKS\n") == 0)
{
//SortList(pStart);
}
else if (strcmp(answer, "EYKL\n") == 0)
{
//DeleteOneCard(pStart);
}
else if (strcmp(answer, "YKL\n") == 0)
{
DeleteList(&pStart);
}
else if (strcmp(answer, "YKA\n") == 0)
{
OutputList(pStart);
}
else if (strcmp(answer, "Prsc\n") == 0)
{
return 0;
}
else
{
printf("Please enter a shortcut!");
}
} while (true);
}
Make an array
Create an array of pointers. Have the array members point to the list members. The code uses a little trick so that the last element of the list will get its pNext member set to NULL properly.
struYugiohCard *arr[size_of_list + 1], **arrp = arr, *iter;
for (iter = list; iter != NULL; iter = iter->pNext) {
*arrp++ = iter;
}
*arrp = NULL;
Write a comparison function, then call qsort
There are lots of examples of how to use qsort, but the trick is writing an appropriate comparison function. It is important to realize that qsort will pass in the addresses of the array elements it is comparing. Since our array contains pointers, the comparison function will be passed pointers to pointers.
In your case, I would guess CardType2 Ascending might be implemented using strcmp, which has return values that match up to what qsort expects (negative if a is less than b, positive if greater than, zero if equal):
int cmp_CardType2_Ascending(const void *a, const void *b) {
const struYugiohCard * const *aa = a;
const struYugiohCard * const *bb = b;
return strcmp((*aa)->CardType2, (*bb)->CardType2);
}
//...
qsort(arr, size_of_list, sizeof(*arr), cmp_CardType2_Ascending);
Fix your list
Now, rewire your list to the sorted order. Notice the pNext of the last iteration is making use of the extra array member which was set to NULL.
arr[0]->pNext = arr[1];
arr[0]->pPrev = NULL;
for (int i = 1; i < size_of_list; ++i) {
arr[i]->pNext = arr[i+1];
arr[i]->pPrev = arr[i-1];
}
list = arr[0];
Putting it into a function
Below is a function that puts most of this logic into a single function. The sorting function is passed in, and this function is then passed to qsort.
void sort_YugiohCard(struYugiohCard **pList, int size_of_list,
int (*By)(const void *, const void *)) {
if (size_of_list == 0) return;
struYugiohCard *list = *pList;
struYugiohCard *arr[size_of_list+1], **arrp = arr, *iter;
for (iter = list; iter != NULL; iter = iter->pNext)
*arrp++ = iter;
*arrp = NULL;
qsort(arr, size_of_list, sizeof(*arr), By);
arr[0]->pNext = arr[1];
arr[0]->pPrev = NULL;
for (int i = 1; i < size_of_list; ++i) {
arr[i]->pNext = arr[i+1];
arr[i]->pPrev = arr[i-1];
}
list = arr[0];
*pList = list;
}
Then, you can call this function like this:
sort_YugiohCard(&list, 5, cmp_CardType2_Ascending);
And the list will be returned in sorted order as determined by the comparison function.
A demo
Try it online!
The goal of the following code segment is to take a sorted array of strings, and count how many of each word there is.
That information is then put into a struct called reduceNode that holds a string and a count for the given string.
The reduceNode structs are put into another array.
Once all of the words and their counts are found and put into the intermediate array, they are inserted into a global array of reduceNode structs.
This method is called by threads, which is why I am storing the results into a global array.
Anytime I run this part of the program, I am getting a segfault.
I assume I am accessing an array out of bounds, but I am having trouble narrowing down where I am doing so.
void* reduce(void* num) //Reduce function
{
int index = *(int*)num;
int curSize = 0; //Size of the current linked list
struct HashNode *head = HashTable[index]; //Get the head of the linked list from the hashtable
struct HashNode *linkedList = head; //Pointer to the head to traverse the linked list
while(linkedList != NULL) //Gets the size of the current linked list
{
curSize++;
linkedList = linkedList->next;
}
linkedList = head;
int linkedListTraverse = 0; //Array index for each linked list node
int numSort[curSize];
char* wordSort[curSize];
while(linkedList != NULL)
{
if(app == 1)
numSort[linkedListTraverse] = linkedList->num; //Copy the data from the linked list into an array
else
{
wordSort[linkedListTraverse] = (char*) malloc(sizeof(linkedList->string));
strcpy(wordSort[linkedListTraverse],linkedList->string); //Copy the data from the linked list into an array
}
linkedList = linkedList->next;
linkedListTraverse++;
}
if(app == 1)
{
qsort(numSort, curSize, sizeof(int), numCmpFunc); //Sort the current node
int i, j = 0;
reduceNode* numSortArray[curSize];
reduceNode* curNum;
for(i = 0; i < curSize; i++)
{
curNum = (reduceNode*) malloc(sizeof(reduceNode));
curNum->num = numSort[i];
numSortArray[i] = curNum;
}
i = 0;
while(sortedArray[i] != NULL)
{
i++;
}
for(j = 0; j < curSize; j++, i++)
{
sortedArray[i] = numSortArray[j];
}
return (void*) 0;
}
else
{
int i = 0;
while(i < curSize) //Convert all of the words to lowercase
{
char* str = wordSort[i];
char *p;
for (p = str; *p != '\0'; p++)
*p = (char)tolower(*p);
i++;
}
qsort(wordSort, curSize, sizeof(char*), stringCmpFunc); //Sort the current node
}
int curWordIndex = 0; //Exclusively for wordcount
int checkWordIndex = 1;
int curArrayIndex = 0;
reduceNode *curWord;
reduceNode* wordCountArray[curSize];
while(curWordIndex < curSize)
{
curWord = malloc(sizeof(reduceNode));
curWord->word = wordSort[curWordIndex]; //Set the word
curWord->count = 1; //Start the count out at 1
while(strcmp(wordSort[curWordIndex], wordSort[checkWordIndex]) == 0) //While the two words are equal
{
checkWordIndex++; //Advance the leading index check
curWord->count++;
if(checkWordIndex >= curSize) //If the leading index goes beyond the array bounds
{
break;
}
}
if(checkWordIndex <= curSize)
{
curWordIndex = checkWordIndex;
checkWordIndex = curWordIndex + 1;
}
else if(checkWordIndex >= curSize) //If the leading index goes beyond the array bounds
{
if(strcmp(curWord->word, wordSort[curWordIndex]) != 0)
{
curWord->word = wordSort[curWordIndex]; //Set the word
curWord->count = 1; //Start the count out at 1
curArrayIndex++;
wordCountArray[curArrayIndex] = curWord;
}
else
{
wordCountArray[curArrayIndex] = curWord;
curArrayIndex++;
}
break;
}
wordCountArray[curArrayIndex] = curWord;
curWord = NULL;
curArrayIndex++;
}
int i,j = 0;
while(sortedArray[i] != NULL)
{
i++;
}
for(j = 0; j < curSize; j++, i++)
{
sortedArray[i] = wordCountArray[j];
}
return (void*) 0;
}
reduceNode is defined as
typedef struct reduceNode
{
int count;
char *word;
int num;
} reduceNode;
sortedArray is declared globally as
reduceNode **sortedArray;
and later initialized as
sortedArray = (reduceNode **)calloc(1,sizeof(reduceNode*)*inputCount);
Input count is the number of words that are read into the program
An example input would be an array: [alpha, alpha, bravo, charlie, charlie, charlie, delta]. The expected result would be [alpha 2, bravo 1, charlie 3, delta 1].
1.
You checkWordIndex reaches exactly curSize and strcmp(wordSort[curWordIndex], wordSort[checkWordIndex] will go out of bounds. I recomment printing the indicies for debugging.
if(checkWordIndex < curSize)
{
curWordIndex = checkWordIndex;
checkWordIndex = curWordIndex + 1;
}
this code will still lead to checkWordIndex == curSize
2.
You allocate new memory, remember to free it.
3.
For thread safety lookup mutex in C.
I recommend using only one indicie and iterating like
while(index < cursize-1)
{
...
++index;
}
your fist indicie is index and your second is index+1.
I've been working on a Trie program for practice and i'm running into some logic/coding issues when it comes to trying to create a method that removes or destroys words that are currently in the trie:
#include "trie.h"
/**************************************************************************/
/* Helper Functions
* trie_node_t * trie_new( void );
* Allocates memory for a new trie node
* Returns NULL if memory allocation was not possible or
* a memory address to a trie_node in the heap
/**************************************************************************/
trie_node_t * trie_new( void ){
trie_node_t * tmp = NULL;
int i;
if ( ( tmp = ( trie_node_t * ) malloc ( sizeof( trie_node_t ) ) ) == NULL )
return NULL;
for( i = 0; i < ALPHA_SIZE; i++ ) {
tmp->child[ i ] = NULL;
tmp->end = 1;
}
return tmp;
}
/**************************************************************************/
/* Functions functions
* int trie_size ( trie_node_t * root );
* Returns the number of words in the trie
* int trie_contains ( trie_node_t * root, char word[ ] );
* Returns 1 if a the word is in the trie
* 0 otherwise
* int trie_insert ( trie_node_t ** rootRef, char word[ ] );
* Returns 1 if the word is inserted in the trie
* 0 otherwise
* int trie_remove ( trie_node_t ** rootRef, char word[ ] );
* Returns 1 if the word is removed from the trie
* 0 otherwise
* int trie_destroy ( trie_node_t ** Tref );
* Returns 1 if the trie and all its node are destroyed
**************************************************************************/
int trie_size ( trie_node_t * root ) {
int i = 0;
int count = 0;
trie_node_t *temp = root; //Creates a temp variable (Because its being modified)
//if the reference does not exist(no more children)
if (temp == NULL){
return EXIT_FAILURE;
}
//loops through the child array
for (i = 0; i < ALPHA_SIZE; i++){
//if the reference to next child is not null
if(temp->child[i] != NULL){
//and the end character is '/0' (or not)
if(temp->child[i]->end == '/0'){
count += 1;
}
//add the return of trie_size to count, then run through the method again at the lower level.
count += trie_size(temp->child[i]);
}
}
return count;
}
/**************************************************************************/
int trie_contains ( trie_node_t * root, char word[ ] ){
trie_node_t *temp = root; //Create a temp variable, can't use the default root. (just a location).
int i = 0;
int length = strlen(word); //finds the length of array
int index = 0;
if (temp == NULL){
return EXIT_FAILURE;
}
if(!valid_word(word)){
return 0;
}
for (i = 0; i < length; i++){
index = charToInt(tlower(word[i]));
if (!temp->child[index]){
return 0;
}
temp = temp->child[index];
}
if (temp->end != '/0'){ //Checks if the end character at the last index is '/0' if it is not, it is not a word. Return 0 (not found)
return 0;
}
return 1;
}
/**************************************************************************/
int trie_insert ( trie_node_t ** rootRef, char word[ ] ){
trie_node_t *temp = *rootRef; //Create a temp variable, can't use the default rootRef. (just a location).
int i = 0;
int length = strlen(word); //finds the length of array
int index = 0;
if (temp == NULL){ //checks that the reference is not null
return EXIT_FAILURE;
}
if (!valid_word(word)){//checks if word is valid.
return 0;
}
for (i = 0; i < length; i++){
if (word[i] == '/0'){
index = 26;
} else if (word[i] >= 'A' || word[i] <= 'Z'){
index = charToInt(tolower(word[i])); //turns the word[i] into a usable integer.
}
else {
return EXIT_FAILURE;
}
if (!temp->child[index]){ //if there is not a child reference.
temp->child[index] = trie_new(); //create one.
}
temp = temp->child[index]; //move down to next level (next child)
}
temp->end = '\0';
return 1;
}
/**************************************************************************
* I'm pretty sure the majority of this method is incorrect, this was just an attempt I had. From what I understand I have to do is this:
* (1) Find the last character in the word (Found with the '/0' end char) and as long as there are no nodes connected at a lower level free the memory.
* (2) Move up (recursion is probably the easiest way to do this, but I haven't been able to figure out how) and check again.
* (3) Continue until the first letter of the word is reached, then exit.
* My question is how do I check to see if another node is connected? Also what would be the format of the recursive call?
**************************************************************************/
void trie_remove ( trie_node_t ** rootRef, char word[ ] ){
trie_node_t *temp = *rootRef;
int i = 0;
int index = 0;
int length = strlen(word);
if (temp == NULL){
return;
}
if (!valid_word(word)){
return;
}
//Code is incomplete, just an attempt.
for (i = 0; i < length; i++){
index = charToInt(tolower(word[i])); //not sure if this is necessary.
if (temp->child[i]->end == '/0'){
free(temp->child[i]);
}
}
return;
}
/**************************************************************************/
int trie_destroy ( trie_node_t ** rootRef ){
//issues with logic here, not exactly sure how to do this.
return 1;
}
/**************************************************************************/
int trie_init(trie_node_t **rootRef){
if ( *rootRef == NULL) {
*rootRef = trie_new();
}
return 1;
}
/**************************************************************************/
int valid_word (char word[]){
int length = 0;
int i = 0;
for (i = 0; i < length; i++){
if(charToInt(word[i]) > 26 || charToInt(word[i]) < 0){
return 0;
}
}
return 1;
}
/**************************************************************************/
int charToInt(char c){
return (int)c-(int)'a';
}
Trie.h: (Important stuff anyways) ALPHA_SIZE is 27.
typedef struct trie_node {
char end;
struct trie_node *child[ ALPHA_SIZE ]; //reference to trie node.
}trie_node_t;
I hope I formatted this question correctly, and I have looked on the site for possible solutions already but have yet to find any. If anyone can help me check my logic/ assist me in the coding of these methods that would be amazing. I don't just want the code I want to learn why it works!
Thanks in advance.
for Remove, you need to remove free'd pointers from the trie:
for (i = 0; i < length; i++){
index = charToInt(tolower(word[i])); //not sure if this is necessary.
if (temp->child[i]->end == '/0'){
free(temp->child[i]);
temp->child[i]=0; // lets not point to free'd elements
}
}
For destroy - try recursion, roughly:
for (int i=ALPHA_MIN; i < ALPHA_MAX; ++i)
{
if (rootRef->child[i])
{
trie_destroy(rootRef->child[i]);
}
}
free (rootRef);
I'm having major trouble figuring out how to do this correctly. The output was until shortly riddles with errors. I managed to fix most of them but I'm still left with two, and likely a bunch of logic errors.
I also have trouble with my hash algorithm, so I have replaced it with simple temp code. The instructions for the correct one are:
The hash function to be used is h(k) = m(k · A mod 1) where
A = (√5 − 1)/2 and k · A mod 1 returns the fractional part of k · A.
I assume I've not implemented it properly.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define TABLE_SIZE 8
typedef struct stItem item;
struct stItem {
int key;
item *next;
};
void init(item * H[]) {
int i = 0;
for (i; i < TABLE_SIZE; i++)
H[i] = NULL;
}
int h(int k) {
// this does not work at all, currently using testcode
/*
int m = TABLE_SIZE;
int A = ( sqrt(5.0) - 1) / 2;
return m * (k * A % 1);
*/
return k % TABLE_SIZE;
}
void insert(int key, item * H[]) {
int keyHashed = h(key);
if (H[keyHashed] == NULL) {
item * temp = malloc(sizeof(item));
temp->key = key;
temp->next = NULL;
H[keyHashed] = temp;
free(temp);
}
else {
item * temp = malloc(sizeof(item));
temp->next = H[keyHashed]->next;
while (temp != NULL) {
temp = temp->next;
}
temp->key = key;
temp->next = NULL;
}
}
int search(int key, item * H[]) {
int keyHashed = h(key);
if (H[keyHashed] == NULL)
return -1;
else if (H[keyHashed]->key != key) {
item * temp = malloc(sizeof(item));
temp->next = H[keyHashed]->next;
while (temp->key != key && temp != NULL)
temp = temp->next;
if (temp->key == key) {
free(temp);
return keyHashed;
}
else {
free(temp);
return -1;
}
}
else
return keyHashed;
}
void printHash(item * H[]) {
printf("Table size: %d", TABLE_SIZE);
int i = 0;
for (i; i < TABLE_SIZE; i++) {
if (H[i] != NULL) {
printf("i: %d key: %d",i,H[i]->key);
if (H[i]->next != NULL) {
item * temp = malloc(sizeof(item));
temp->next = H[i]->next;
while (temp != NULL) {
printf(" -> %d", temp->key);
}
printf("\n");
}
else
printf("\n");
}
}
}
void test() {
// a)
int array[7] = {111,10112,1113,5568,63,1342,21231};
item *h[TABLE_SIZE];
init(h);
int i = 0;
for (i; i < 7; i++)
insert(array[i], h);
// b)
printHash(h);
// c)
printf("Search result for 1: %d", search(1, h));
printf("Search result for 10112: %d", search(10112, h));
printf("Search result for 1113: %d", search(1113, h));
printf("Search result for 5568: %d", search(5568, h));
printf("Search result for 337: %d", search(337, h));
}
int main() {
test();
}
EDIT: Thanks to user3386109's fix the code now compiles with no errors but what happens is that the command prompt just pops up with nothing displayed in it and nothing happening at all. It doesn't close either. Not even after several minutes of waiting.
EDIT2: After some more testing it looks to be hanging up on the insert-function. Nothing after the for-loop in test() is executed.
If I add this printf("init done %d", h[1]); to just after the init() in the test function, I get "init done 0" instead of "init done NULL", might that be one of the issues?
The structure definition is malformed. I would suggest the following
typedef struct stItem item;
struct stItem {
int key;
item *next;
};
I am trying to write a module which assigns huffman encoded words to the input symbols, but the given codes differ from what they should look like.
For example, if I run it with following symbol probabilities:
(1st column: probabilities; 2nd column: my huffman codes; 3rd column: correct huffman codes)
0,25 --> 01 --> 10
0,15 --> 101 --> 111
0,15 --> 110 --> 110
0,1 --> 1111 --> 010
0,1 --> 000 --> 001
0,05 --> 0010 --> 0110
0,05 --> 0011 --> 0001
0,05 --> 1000 --> 0000
0,05 --> 1001 --> 01111
0,05 --> 1110 --> 01110
I think the problem might be caused in my function for generating huffman codes, since strcat() function's behaviour was initially not good for my idea, so I combined it with strcat(). Not sure if it is good that way tho.
I am providing you with two functions responsible for codes assign, build_huffman_tree() and generate_huffman_tree(), hopefully you can help me out with this, and point out where the problem could be.
Generate guffman tree:
void generate_huffman_tree(node *n, char *code){
if(n->left== NULL && n->right== NULL){
SYMBOLS[code_counter] = n->symbol; // this 3 lines just store current code, not important
CODES[code_counter] = strdup(code);
code_counter += 1;
}
if(n->left!= NULL){
char temp[100];
strcpy(temp, code);
strcat(temp, "0");
generate_huffman_tree(n->left, temp);
}
if(n->right!= NULL){
char temp[100];
strcpy(temp, code);
strcat(temp, "1");
generate_huffman_tree(n->right, temp);
}
Build Huffman tree:
node *build_huffman_tree(double *probabilities){
int num_of_nodes = NUM_SYMBOLS;
int num = NUM_SYMBOLS;
// 1) Initialization: Create new node for every probability
node *leafs = (node*) malloc(num_of_nodes*sizeof(node));
int i;
for(i=0; i<num_of_nodes; i+=1){
node c;
c.probability= *(probability+ i);
c.symbol= *(SYMBOLS + i);
c.left= NULL;
c.right= NULL;
*(leafs+i) = c;
}
node *root= (node*) malloc(sizeof(node)); // Root node which will be returned
while(num_of_nodes> 1){
// 2) Find 2 nodes with lowest probabilities
node *min_n1= (node*)malloc(sizeof(node));
node *min_n2 = (node*)malloc(sizeof(node));
*min_n1 = *find_min_node(leafs, num, min_n1);
leafs = remove_node(leafs, min_n1, num);
num -= 1;
*min_n2= *find_min_node(leafs, num, min_n2);
leafs = remove_node(leafs, min_n2, num);
num -= 1;
// 3) Create parent node, and assign 2 min nodes as its children
// add parent node to leafs, while its children have been removed from leafs
node *new_node = (node*) malloc(sizeof(node));
new_node->probabilty= min_n1->probability + min_n2->probability;
new_node->left= min_n1;
new_node->right= min_n2;
leafs = add_node(leafs, new_node, num);
num += 1;
num_of_nodes -= 1;
root = new_node;
}
return root;
I have tested functions for finding 2 min nodes, removing and adding nodes to leafs structure, and it is proven to work fine, so I guess the problem should be something about this here.
I didn't look at your source code, but there's nothing wrong with the Huffman code you generated. There is also nothing wrong with what you are calling "correct huffman codes". There is more than one valid Huffman code possible with that set of probabilities. If you take the sum of the probabilities times the bit lengths for both Huffman codes, you will find that those sums are exactly the same. Both Huffman codes are optimal, even though they're different.
The way this happens is that when you look for the two lowest frequencies, there is more than one choice. Depending on which choice you make, you will get a different tree.
This code below is an implementation of Mark Allen Weiss's Algorithm. Give it a try!
It offers routines similar to yours, in addition to a function that displays the result according to the previously constituted codes for each letter.
The compiler used is MinGW 2.95 (C-Free 4.0).
Prerequisites:
An input file with a text (any, but remember, it deals with alphabet characters only, no punctuation, no space, no numbers).
The constant IN_PATH is the one you should modify to point at the right location of your text file to run the program successfully.
The image shows a sample text, the letters proportions and the result of huffman code interpretation (letters separated by one space).
Good luck!
//*******************************************************************
// File: HuffmanEncoding - Tree.c
// Author(s): Mohamed Ennahdi El Idrissi
// Date: 14-Aug-2012
//
// Input Files: in.txt
// Output Files: out.txt
// Description: CSC 2302 - <Data Structures>
// <Struct, Array, File I/O, Recursion, Pointers, Binary Tree>
// This program covers the Huffman Encoding concept.
// We first read a file, from we which we count the number of characters, and then reckon the frequency
// of each letter individually. Each letter's frequency is stored in a node with its respective character.
// This node is stored in an array of 26 elements (element 0 -> 'A', element 1 -> 'B'...element 25 -> 'Z').
// Each element is a pointer, and each pointer is supposed to be a root of a tree (sub tree).
// After processing all characters of the text (read from a file), we end up with an array with
// 25 NULL elements. The only element that is not NULL is the root of the tree that gathers the different
// nodes of each letter.
// Deducing the encoding of each letter if performed with intermediary of the prefix traversal.
// To summarize, the pseudo-code is:
// - Initialize the letters array
// - Read file
// - Increment each letter frequency + compute the number of characters in the file
// - Store in the array's node the frequency of each letter
// - Compute the number (N) of involved characters (Sometimes, texts don't include all letters. In our case 'Q' and 'Z' are absent).
// - Loop N times
// - find Minimum and second minimum
// - create a new node, its left child contains the minimum and the right child contains the second minimum
// - minimum position points on the new node, and the second minimum's array position points on NULL
// - Browse the array till the unique non NULL element is encountered
// - invoke prefix traversal function
// - build the encoding of each character
// - display the letter and its characteristics when found.
// - Finally, read the output file to interpret its content
// - if root contains a character (A - Z), display character
// - else, if the current character is '0', browse the left leaf
// - else, if the current character is '1', browse the right leaf
//
//*******************************************************************
#include <stdio.h>
#define NBR_OF_LETTERS 26
#define LEFT 'L'
#define RIGHT 'R'
#define CODE_SIZE 128
#define TYPED_ALLOC(type) (type *) malloc( sizeof(type) )
#define BYTE_SIZE 8
#define IN_PATH "./files/in.txt"
#define OUT_PATH "./files/out.txt"
typedef struct tree_node_s {
float frequency;
char c;
char code[CODE_SIZE];
struct tree_node_s *left;
struct tree_node_s *right;
} tree_node_t;
tree_node_t *arr[NBR_OF_LETTERS], *letters[NBR_OF_LETTERS];
void findMinAndSecondMin(tree_node_t **, float *, int *, float *, int *);
void printTree(tree_node_t *);
void interpret(char *, int *, tree_node_t *);
void printTree(tree_node_t *);
void encode(tree_node_t *, tree_node_t **, char, short, char*);
/*
*
*/
int main() {
char str[CODE_SIZE];
int fileReadingVerdict;
int i, j, k, index, n;
float min, secondMin;
int minIndex, secondMinIndex;
int numberOfCharacters = 0;
tree_node_t *tree;
FILE *in = fopen(IN_PATH, "r");
FILE *out;
if ( in == NULL ) {
printf("\nFile not found");
return 0;
} else {
/*
* Begin: Array Initialization
*/
for (i = 'A'; i <= 'Z'; i++) {
index = i - 'A';
arr[index] = NULL;
}
/*
* End: Array Initialization
*/
numberOfCharacters = 0;
fileReadingVerdict = fgets(str, CODE_SIZE, in) != NULL;
while(!feof(in) || fileReadingVerdict) {
n = strlen(str);
printf("\n%s", str);
for (i = 0; i < n ; i ++ ) {
str[i] = toupper(str[i]);
if (str[i] >= 'A' && str[i] <= 'Z') {
numberOfCharacters ++;
index = str[i] - 'A';
if (arr[index] == NULL) {
arr[index] = TYPED_ALLOC(tree_node_t);// malloc(sizeof(tree_node_t));
arr[index]->c = str[i];
arr[index]->frequency = 1;
arr[index]->left = arr[index]->right = NULL;
} else {
arr[index]->frequency += 1;
}
}
}
if (fileReadingVerdict) {
fileReadingVerdict = fgets(str, CODE_SIZE, in) != NULL;
}
}
}
fclose(in);
for ( i = 0, n = 0 ; i < NBR_OF_LETTERS ; i ++ ) {
letters[i] = arr[i];
if (arr[i] != NULL) {
arr[i]->frequency /= numberOfCharacters; // Computing the frequency.
n ++; // n is the number of involved letters which is going to be consumed in the do while loop's condition
}
}
j = 1;
do {
findMinAndSecondMin(arr, &min, &minIndex, &secondMin, &secondMinIndex);
if (minIndex != -1 && secondMinIndex != -1 && minIndex != secondMinIndex) {
tree_node_t *temp;
tree = TYPED_ALLOC(tree_node_t);// malloc(sizeof(tree_node_t));
tree->frequency = arr[minIndex]->frequency + arr[secondMinIndex]->frequency;
tree->c = j;
tree->left = arr[minIndex];
temp = TYPED_ALLOC(tree_node_t);// malloc(sizeof(tree_node_t));
temp->c = arr[secondMinIndex]->c;
temp->frequency = arr[secondMinIndex]->frequency;
temp->left = arr[secondMinIndex]->left;
temp->right = arr[secondMinIndex]->right;
tree->right = temp;
arr[minIndex] = tree;
arr[secondMinIndex] = NULL;
}
j ++;
} while( j < n );
for ( i = 0 ; i < NBR_OF_LETTERS ; i ++ ) {
if (arr[i] != NULL) {
char code[CODE_SIZE];
strcpy(code, "");
encode(tree = arr[i], letters, 0, 0, code);
puts("\nSuccessful encoding");
printTree(arr[i]);
break;
}
}
in = fopen(IN_PATH, "r");
out = fopen(OUT_PATH, "w");
fileReadingVerdict = fgets(str, CODE_SIZE, in) != NULL;
while(!feof(in) || fileReadingVerdict) {
n = strlen(str);
for (i = 0; i < n ; i ++ ) {
str[i] = toupper(str[i]);
if (str[i] >= 'A' && str[i] <= 'Z') {
index = str[i] - 'A';
fputs(letters[index]->code, out);
}
}
if (fileReadingVerdict) {
fileReadingVerdict = fgets(str, CODE_SIZE, in) != NULL;
}
}
fclose(in);
fclose(out);
printf("\nFile size (only letters) of the input file: %d bits", numberOfCharacters * BYTE_SIZE);
out = fopen(OUT_PATH, "r");
fileReadingVerdict = fgets(str, CODE_SIZE, out) != NULL;
numberOfCharacters = 0;
while(!feof(out) || fileReadingVerdict) {
numberOfCharacters += strlen(str);
if (fileReadingVerdict) {
fileReadingVerdict = fgets(str, CODE_SIZE, out) != NULL;
}
}
fclose(out);
printf("\nFile size of the output file: %d bits", numberOfCharacters);
printf("\nInterpreting output file:\n");
out = fopen(OUT_PATH, "r");
fileReadingVerdict = fgets(str, CODE_SIZE, out) != NULL;
while(!feof(out) || fileReadingVerdict) {
n = strlen(str);
i = 0 ;
while(i < n) {
interpret(str, &i, tree);
}
if (fileReadingVerdict) {
fileReadingVerdict = fgets(str, CODE_SIZE, out) != NULL;
}
}
fclose(out);
puts("\n");
return 0;
}
/*
*
*/
void encode(tree_node_t *node, tree_node_t **letters, char direction, short level, char* code) {
int n;
if ( node != NULL ) {
if ((n = strlen(code)) < level) {
if (direction == RIGHT) {
strcat(code, "1");
} else {
if (direction == LEFT) {
strcat(code, "0");
}
}
} else {
if (n >= level) {
code[n - (n - level) - 1] = 0;
if (direction == RIGHT) {
strcat(code, "1");
} else {
if (direction == LEFT) {
strcat(code, "0");
}
}
}
}
if (node->c >= 'A' && node->c <= 'Z') {
strcpy(node->code, code);
strcpy(letters[node->c - 'A']->code, code);
}
encode(node->left, letters, LEFT, level + 1, code);
encode(node->right, letters, RIGHT, level + 1, code);
}
}
void printTree(tree_node_t *node) {
int n;
if ( node != NULL ) {
if (node->c >= 'A' && node->c <= 'Z') {
printf("\t%c - frequency: %.10f\tencoding: %s\n", node->c, node->frequency, node->code);
}
printTree(node->left);
printTree(node->right);
}
}
/*
* Begin: Minimum and second minimum
*/
void findMinAndSecondMin(tree_node_t *arr[], float *min, int *minIndex, float *secondMin, int *secondMinIndex) {
int i, k;
k = 0;
*minIndex = -1;
/*
* Skipping all the NULL elements.
*/
while (k < NBR_OF_LETTERS && arr[k] == NULL) k++;
*minIndex = k;
*min = arr[k]->frequency;
for ( i = k ; i < NBR_OF_LETTERS; i ++ ) {
if ( arr[i] != NULL && arr[i]->frequency < *min ) {
*min = arr[i]->frequency;
*minIndex = i;
}
}
k = 0;
*secondMinIndex = -1;
/*
* Skipping all the NULL elements.
*/
while ((k < NBR_OF_LETTERS && arr[k] == NULL) || (k == *minIndex && arr[k] != NULL)) k++;
*secondMin = arr[k]->frequency;
*secondMinIndex = k;
if (k == *minIndex) k ++;
for ( i = k ; i < NBR_OF_LETTERS; i ++ ) {
if ( arr[i] != NULL && arr[i]->frequency < *secondMin && i != *minIndex ) {
*secondMin = arr[i]->frequency;
*secondMinIndex = i;
}
}
/*
* End: Minimum and second minimum
*/
}
void interpret(char *str, int *index, tree_node_t *tree) {
int n = strlen(str);
if (tree->c >= 'A' && tree->c <= 'Z') {
printf("%c ", tree->c);
return ;
} else {
if ( *index < n ) {
if (str[*index] == '0') {
(*index) ++;
interpret(str, index, tree->left);
} else {
if (str[*index] == '1') {
(*index) ++;
interpret(str, index, tree->right);
}
}
}
}
}