Basically for my assignment I need to implement code to do Huffman coding. For that I need to take input as a string and then create a list of characters and their frequencies. I need to create a new node when there is a new character. I have tried doing it in C with no result. When I try to print my linked list I simply cannot get any output. I believe I have failed in creating the list from the start.
My C code is below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
struct node {
char character;
int frequency;
struct node *next;
}head;
struct node *insert(int frequency, char character) {
struct node *newNode = malloc(sizeof(struct node));
newNode->character = frequency;
newNode->character = character;
return newNode;
}
void create_freq_list(struct node *initial, int str_size, char str[]) {
int i;
struct node *temp;
bool has_node;
for (i = 0; i < str_size; i++) {
temp = initial;
has_node = false;
while (temp->next != NULL) {
if (temp->character == str[i]) {
has_node = true;
temp->frequency++;
}
temp = temp->next;
}
if (has_node == false) {
while (temp->next != NULL) {
temp = temp->next;
if (temp->next == NULL) {
temp->next = insert(0, str[i]);
}
}
}
}
}
int main() {
struct node *temp;
char str[100];
gets_s(str, 100);
create_freq_list(&head, 100, str);
temp = &head;
while (temp->next != NULL) {
printf("'%c' : %d", temp->character, temp->frequency);
temp = temp->next;
}
getch();
exit(0);
}
There are multiple issues in your code:
Your handling of the head node is incorrect: head should be defined as a node * and you should pass its address to create_freq_list().
There is a typo in the insert() function: newNode->character = frequency;
You should not iterate on characters of the string beyond the null terminator.
The output loop is incorrect: it should iterate while (head), not while (head->next). As coded, the initial node is output but meaningless and the last node is ignored.
Here is a modified version:
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
char character;
int frequency;
struct node *next;
};
struct node *insert(int frequency, char character) {
struct node *newNode = malloc(sizeof(struct node));
if (newNode != NULL) {
newNode->frequency = frequency;
newNode->character = character;
}
return newNode;
}
void create_freq_list(struct node **headp, const char str[]) {
for (int i = 0; str[i]; i++) {
struct node **tailp = *headp;
struct node *temp;
while ((temp = *tailp) != NULL) {
if (temp->character == str[i]) {
temp->frequency++;
break;
}
tailp = &temp->next;
}
if (temp == NULL) {
*tailp = insert(1, str[i]);
}
}
}
int main() {
struct node *head = NULL;
char str[100];
gets_s(str, 100);
create_freq_list(&head, str);
for (struct node *temp = head; temp != NULL; temp = temp->next) {
printf("'%c': %d\n", temp->character, temp->frequency);
}
getch();
return 0;
}
Note that it is much simpler to use an array with 256 elements to compute the character frequencies.
May I propose a variant, using macros of the excellent <sys/queue.h>
This is not a standard include, but every well packaged system should have it.
Well, it's probably less pedagogical than coding linked-list by hands, but it's more secure ;-)
Have a look at man queue (or man LIST_INIT) to see features.
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/queue.h>
typedef LIST_HEAD(listhead, entry) nodes_t;
typedef struct entry {
char character;
int frequency;
LIST_ENTRY(entry) entries;
} node_t;
void insert(nodes_t *list, char character) {
node_t *newNode = malloc(sizeof(node_t));
if (newNode != NULL) {
newNode->frequency = 1;
newNode->character = character;
LIST_INSERT_HEAD(list, newNode, entries);
}
}
node_t *get_node(nodes_t *list, char character) {
node_t *n;
LIST_FOREACH(n, list, entries)
if (n->character == character)
return n;
return NULL;
}
void create_freq_list(nodes_t *list, const char str[]) {
node_t *n;
for (int i = 0; str[i]; i++) {
n = get_node(list, str[i]);
if (n == NULL)
insert(list, str[i]);
else
n->frequency++;
}
}
void print_list(nodes_t *list) {
node_t *n;
LIST_FOREACH(n, list, entries)
printf("'%c': %d\n", n->character, n->frequency);
}
int main(int argc, char* argv[]) {
nodes_t list;
if (argc != 2) {
fprintf(stderr, "Usage: %s <string>\n", argv[0]);
return -1;
}
LIST_INIT(&list);
create_freq_list(&list, argv[1]);
print_list(&list);
return 0;
}
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I'm trying to insert values into a linked list, but keep having the program crash on me. I know I'm doing something wrong I'm just not sure what and after spending 8 hrs trying different methods, I'm ready to ask for help.
I've tried many different ways to get this to work. Sometimes I seem to be able to get the nodes stored and connected, but then when I try to print, it will either only print the first node or print nothing at all.
typedef struct histogram {
char *word;
int count;
struct histogram *next;
} List;
static List *createWord(char word[]) {
char *wordPtr = word;
List *node = (List *)malloc(sizeof(List));
node->word = wordPtr;
node->count = 1;
return node;
}
static void insertAtTail(List **head, List *node) {
List *previous = *head;
if (*head == NULL) {
*head = node;
} else {
while (previous->next != NULL) { // error location
previous = previous->next;
}
previous->next = node;
node->next = NULL;
}
}
void readMain(char *fileName) {
// responsible for read operatons and list storage.
// Counts total words and uniques than stores words in linked list.
char word[100];
char *wordArray[1500] = { NULL };
static int noOfWords = 0;
static int uniqueWords = 0;
List *head = NULL;
List *temp = NULL;
fileRead(inputFile);
while (fscanf(inputFile, "%s", word) == 1) {
if (determineIfWord(word) == 0) {
noOfWords++;
temp = createWord(word);
insertAtTail(&head, temp); // error occurs here
if (!compareWords(wordArray, word, uniqueWords)) {
wordArray[uniqueWords] = calloc(strlen(word) + 1,
sizeof(char));
if (wordArray[uniqueWords] == NULL) {
printf("calloc failed to allocate memory\n");
exit(0);
}
strcpy(wordArray[uniqueWords], word);
uniqueWords++;
}
}
fclose(inputFile);
freeArray(wordArray, uniqueWords);
noOfWords -= 1;
printf("\n%s processed: %i unique words found.\n\n", fileName, uniqueWords);
}
I need the nodes to be stored and linked together allowing me to access the linked list.
You write way too complicated code.
#include <stdbool.h>
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define STRING(x) #x
#define STRINGIFY(x) STRING(x)
#define BUFFER_SIZE 100
typedef struct node_tag {
char *data;
struct node_tag *next;
} node_t;
node_t* node_create(char const *word)
{
node_t *new_node = calloc(1, sizeof *new_node);
if (!new_node)
return NULL;
new_node->data = malloc(strlen(word) + 1);
if (!new_node->data) {
free(new_node);
return NULL;
}
strcpy(new_node->data, word);
return new_node;
}
void node_free(node_t *node)
{
assert(node && node->data);
free(node->data);
free(node);
}
node_t* node_advance(node_t *node)
{
assert(node);
return node->next;
}
typedef struct list_tag {
node_t *head;
node_t *tail;
size_t length;
} list_t;
list_t list_create(void)
{
list_t list = { NULL, NULL, 0 };
return list;
}
void list_free(list_t *list)
{
assert(list);
for (node_t *current_node = list->head; current_node;) {
node_t *next_node = node_advance(current_node);
node_free(current_node);
current_node = next_node;
}
}
bool list_append(list_t *list, char const *word)
{
assert(list && word);
node_t *new_node = node_create(word);
if (!new_node) {
return false;
}
if (!list->tail) {
list->head = list->tail = new_node;
}
else {
list->tail->next = node_create(word);
list->tail = list->tail->next;
}
++(list->length);
return true;
}
bool list_contains(list_t *list, char const *word)
{
assert(list && word);
for (node_t *current_node = list->head; current_node; current_node = node_advance(current_node)) {
if (strcmp(current_node->data, word) == 0)
return true;
}
return false;
}
void list_print(list_t *list)
{
assert(list);
for (node_t *current_node = list->head; current_node; current_node = node_advance(current_node)) {
puts(current_node->data);
}
}
int main(void)
{
char const *filename = "test.txt";
FILE *input = fopen(filename, "r");
if (!input) {
fprintf(stderr, "Couldn't open \"%s\" for reading :(\n\n", filename);
return EXIT_FAILURE;
}
size_t unique_words = 0;
list_t words_list = list_create();
for (char buffer[BUFFER_SIZE + 1]; fscanf(input, "%" STRINGIFY(BUFFER_SIZE) "s", buffer) == 1;) {
if (!list_contains(&words_list, buffer))
++unique_words;
if (!list_append(&words_list, buffer)) {
fclose(input);
list_free(&words_list);
fputs("Not enough memory :(\n\n", stderr);
return EXIT_FAILURE;
}
}
puts("Words found:");
list_print(&words_list);
printf("\nNumber of unique words: %zu\n\n", unique_words);
fclose(input);
list_free(&words_list);
}
Here are some problems in the code:
the header files are missing. You need at least <stdio.h>, <stdlib.h> and <string.h>
There is a missing } before the fclose(inputFile);.
The function createWord should allocate a copy of the word, otherwise all nodes point to the same array in main(), where fscanf() writes the last word read from the file.
you should protect against buffer overflow by telling fscanf() the maximum number of characters to store to the destination array: fscanf(inputFile, "%99s", word)
Here is a modified version of createWord:
static List *createWord(const char *word) {
List *node = (List *)malloc(sizeof(List));
if (node) {
node->word = strdup(wordPtr);
node->count = 1;
}
return node;
}
I want to create binary search tree which I get the elements (words) from a text file. But, my compare-function always compares the two same words. When I call the insert function, root and data have the same value. Therefore the insert function always adds the elements to left child. I don't understand why.
But maybe it is about the do-while loop.
When I execute it, the output is the last word of the file a hundred times.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
struct n
{
char *data;
struct n *left;
struct n*right;
};
typedef struct n node;
void in_Order(node *root)
{
if (root == NULL)
return;
printf("%s ", root->data);
in_Order(root->left);
in_Order(root->right);
}
int compare(node *root, char data[14])
{
if (strcmp(root->data, data) <= 0)
return 1;
else return -1;
}
node *getNewNode(char *data)
{
node *newNode = (node *)malloc(sizeof(node));
newNode->left = NULL;
newNode->right = NULL;
newNode->data = data;
return newNode;
}
node *insert(node *root, char *data)
{
if (root == NULL)
{
root = getNewNode(data);
return root;
}
if (compare(root,data) == 1)
root->left = insert(root->left, data);
else
root->right = insert(root->right, data);
return root;
}
int main()
{
node *root = NULL;
FILE *fptr = fopen("File.txt", "r");
char *buffer = (char *)malloc(sizeof(char)*15);
int status;
do
{
fscanf(fptr, "%s", buffer);
root = insert(root, buffer);
} while (status = fgetc(fptr) != EOF);
in_Order(root);
}
I'm currently creating a linked list of strings that user enters. As of right now I have my linked list working (I just have to free the memory). However, I'm trying to detect for commas in the user input. If there is a comma make the linked list print out a new line, and just ignore the commas.
Any advice?
For example:
Enter a string:
hello,world,how,are,you
The output is currently:
hello,world,how,are,you
The output should be:
hello
world
how
are
you
Here's my current code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
struct Word
{
char* data;
struct Word* next;
};
struct Word* ptr = NULL;
void insert(char c)
{
struct Word* temp = (struct Word*)malloc(sizeof(struct Word));
temp->data = c;
temp->next = NULL;
if (ptr) {
struct Word* temp1 = ptr;
while(temp1->next != NULL) {
temp1 = temp1->next;
}
temp1->next = temp;
} else {
ptr = temp;
}
}
void print() {
struct Word *temp;
temp = ptr;
while(temp != NULL) {
printf("%c", temp->data);
temp = temp->next;
}
printf("\n");
}
int main(int argc, char *argv[])
{
int c;
printf("enter a string\n");
while (((c=getchar())!=EOF) && c!='\n') {
insert((char)c);
}
print(); /*print the list*/
return 0;
}
To print every word in the new line you just have to modify your print statement to check for , character in the linked list.
void print() {
struct Word *temp;
temp = ptr;
char c;
while(temp != NULL) {
if (temp->data == ',') {
printf("\n");
temp = temp->next;
} else {
printf("%c", temp->data);
temp = temp->next;
}
}
printf("\n");
}
This will check if there is a , in the linked list and print a \n to print newline character and move to the next node.
Also you should free your linked list after the program is complete to avoid memory leaks.
void freeData(struct Word* head)
{
struct Word* tmp;
while (head != NULL)
{
tmp = head;
head = head->next;
free(tmp);
}
}
Code link
Just try it out.
I am trying to sort a linked list in alphabetical order using bubble sort, but I am getting a segfault when I run the program. I can print off the names before sorting, but when I sort them and try to display them, it doesn't work.
Here is the code that I have and the output I want is to just display the names in order.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define MAX_STR_LEN 25
typedef struct Data_ {
char *name;
struct Data_ *next;
} Data;
Data* bubble_sort(Data *list);
Data* read_from_file(const char *file, const int size);
void display(Data *list);
void push(Data **head, char *name);
int main(int argc, char **argv) {
if(argc != 2){
printf("Not enough parameters!");
exit(0);
}
Data *head = NULL;
int size = 10;
head = read_from_file(argv[1], size);
printf("\nBefore sort");
display(head);
printf("\nBubble Sort\n");
head = bubble_sort(head);
display(head);
}
Data* bubble_sort(Data *head) {
int count = 0, i;
Data *start = head;
Data *curr = NULL;
Data *trail = NULL;
Data *temp = NULL;
//grab the count
while(start != NULL) {
count++;
start = start->next;
}
for( i = 0; i < count; ++i) {
curr = trail = head; //set curr and trail at the start node
while(curr->next != NULL){
if(strcmp(curr->name, curr->next->name) > 0) {
temp = curr->next;
curr->next = curr->next->next;
temp->next = curr;
if(curr==head)
head = trail = temp;
else
trail->next = temp;
curr = temp;
}
trail = curr;
curr = curr->next;
}
}
return head;
}
void push(Data **head, char *name) {
Data *temp = malloc(sizeof(Data));
temp->name = strdup(name);
temp->next = *head;
*head = temp;
}
Data* read_from_file(const char *file, const int size) {
FILE *input;
input = fopen(file, "r");
Data *new_ = (Data*)malloc(sizeof(Data*));
new_->next = NULL;
int i;
char name[MAX_STR_LEN];
for(i = 0; i < size; i++) {
fscanf(input, "%24s", &name);
push(&new_, name);
}
return new_;
}
void display(Data *list) {
Data *current = list;
while(current->next != NULL) {
printf("\n%s", current->name);
current = current->next;
}
}
The list of names that I read in is
Derek
Drew
Randell
Terrell
Carmen
Colin
Eddy
Pablo
Lamont
Dexter
In addition to the problem pointed out by BLUEPIXY there were a couple of other problems in the code. I tested this and it seems to work.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define MAX_STR_LEN 25
typedef struct Data_ {
char *name;
struct Data_ *next;
} Data;
Data* bubble_sort(Data *list);
Data* read_from_file(const char *file);
void display(Data *list);
void push(Data **head, char *name);
int main(int argc, char **argv) {
if(argc != 2){
printf("Not enough parameters!");
exit(0);
}
Data *head = NULL;
head = read_from_file(argv[1]);
printf("\nBefore sort");
display(head);
printf("\nBubble Sort\n");
head = bubble_sort(head);
display(head);
}
Data* bubble_sort(Data *head) {
int i = 1;
Data *curr = NULL;
Data *trail = NULL;
Data *temp = NULL;
Data *after = NULL;
while( i == 1) { // keep sorting
i = 0; // if not changed loop will exit
curr = trail = head; //set curr and trail at the start node
while(curr->next != NULL){
if(strcmp(curr->name, curr->next->name) > 0) {
i = 1; // still sorting
after = curr->next;
temp = after->next; // temp may be NULL. thats ok
after->next = curr;
curr->next = temp;
if(curr==head) {
head = after;
}
else {
trail->next = after;
}
curr = after;
}
trail = curr;
curr = curr->next;
}
}
return head;
}
void push( Data **head, char *name) {
Data *temp = malloc(sizeof(Data));
temp->name = strdup(name);
temp->next = *head;
*head = temp;
}
Data* read_from_file(const char *file) {
FILE *input;
Data *new_ = NULL; // allocation will take place in push
input = fopen(file, "r");
char name[MAX_STR_LEN];
while( fscanf(input, "%24s", name) == 1) { // scan until scan fails to return one value
push( &new_, name);
}
return new_;
}
void display(Data *list) {
Data *current = list;
while(current != NULL) {
printf("\n%s", current->name);
current = current->next;
}
}
I'm trying to write a code that'll check 2 words if they are anagrams,using linked lists.To do that,I guess it should receive 2 words from the user and pass every letter they contain to linked list's nodes,and compare the nodes if they have the same letter,if so,remove the same letter from the second word.When the process is done,if the second list is empty,then they are anagrams.Even if 1 letter is not matching,it should return 0,but I don't know how to determine the length of these words,here is what I wrote so far
#include <stdio.h>
#include <stdlib.h>
struct node
{
struct node *prev;
struct node *next;
char data;
};
typedef struct node *NODE,NOD;
NODE last(NODE list)
{
if(list!=NULL)
while(list->next!=NULL)
list=list->next;
NODE lst;
lst=list;
return lst;
}
void insert( char letter, NODE list)
{
NODE nod;
nod=(NODE)malloc(sizeof(NOD));
nod->next=NULL;
nod->prev=NULL;
nod->data=letter;
if(list==NULL)
{
list=nod;
}
else
{
nod->prev=last(list);
last(list)->next=nod;
}
}
Just check that each word has the same number of each letter in it.
int anagrams(const char *a, const char *b) {
int counts[256] = {0};
while (*a) counts[*a++]++;
while (*b) counts[*b++]--;
for (int i = 0; i < 256; i++) {
if (counts[i]) return 0;
}
return 1;
}
Why use linked lists for such an easy problem?
O(N) solution:
Calculate frequencies of every letter for each word and then compare these 2 histograms. If they're equal, then one word can be obtained from another.
If you want to use your linked-list-based solution, then, the length of the word is, indeed:
Length of each input word (they must have the same length) - it can be calculated with a single traversal from the linked list head to the tail.
Amount of removed symbols
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct node {
char data;
struct node *prev;
struct node *next;
} NODE;
NODE *newNode(char ch){
NODE *p = malloc(sizeof(NODE));
if(p){
p->data = ch;
p->prev = p->next = NULL;
}
return p;
}
void insert(NODE **list, NODE *node){
if(*list == NULL){
*list = node;
return ;
}
NODE *curr = *list;
while(curr){
if(curr->data >= node->data){//insert sort
if(curr->prev == NULL)
*list = node;
else
curr->prev->next = node;
node->prev = curr->prev;
curr->prev = node;
node->next = curr;
break;
}
if(curr->next == NULL){
curr->next = node;
node->prev = curr;
break;
} else
curr = curr->next;
}
}
NODE *input_word(){
NODE *word=NULL;
int ch;
while(EOF!=(ch=getchar()) && ch != '\n'){
insert(&word, newNode(ch));
}
return word;
}
bool isAnagram(NODE *word1, NODE *word2){
while(word1 && word2){
if(word1->data != word2-> data)
return false;
word1 = word1->next;
word2 = word2->next;
}
return word1 == NULL && word2 == NULL;
}
int main(){
NODE *word1, *word2;
printf("input word : ");
word1 = input_word();
printf("input other word : ");
word2 = input_word();
if(isAnagram(word1, word2))
printf("YES\n");
else
printf("NO\n");
//drop(word1);drop(word2);
return 0;
}