0

Here I have a really detailed explanation of my homework and the problems in the code. There are two parts of the homework, and the code for the first part works, but after modifying it for the second part, it doesn't work anymore.

The homework: Save the person's name and fastest running time using Dictionary(with open hashing, that is, Dictionary is represented with hash-table which is an array with B elements, where each element of the array is a linked list of elements of type celltype. Hash table is using hash function h(name) where for i=1,...,B-1, if h(name)=i, then data about the person with the 'name' is saved in the linked list in the i-th element of the Dictionary. People are sorted by their name.)

Here's how it looks like.

#define B 20
typedef struct celltag{
    char name[11];
    double time;
    struct celltag *next;
} celltype;

typedef celltype **Dictionary;

int h(char name[]){
    int i, sum=0;
    for(i=0;name[i]!='\0';i++) {
        sum+=name[i];
    }
    return sum % B;
}

void DiMakeNull (Dictionary *Ap){
    int i;
    for(i=0;i<B;i++) (*Ap)[i]=NULL;
}

void DiInsert(char name[], double time, Dictionary *Ap){
    int bucket;
    celltype *oldheader;
    if(DiMember(name, *Ap)==0){
        bucket=h(name);
        oldheader=(*Ap)[bucket];
        (*Ap)[bucket]=(celltype*)malloc(sizeof(celltype));
        strcpy((*Ap)[bucket]->name, name);
        (*Ap)[bucket]->time= time;
        (*Ap)[bucket]->next=oldheader;
    }
}

(Function DiMember(char name[], Dictionary A) returns 1 if person is in the dictionary, 0 if not.)

This part works as it should.

Now, the next part of the homework: Sort the people by their running time using another pointer array, where the first element of the array points to the data of the fastest person, the second element to the second fastest person etc.

My idea was to make another Dictionary, let's call it Dictionary Array. Now, while inserting a new person's data into the original Dictionary Ap, I wanted to call another function void Sort(celltype *Data, Dictionary *Array) which takes celltype in which the new person's data is stored and the Array in which we will insert it sorted by the time.

Because I would use this in DiInsert, I modified it into

void DiInsert(char name[], double time, Dictionary *Ap, Dictionary *Array){
    int bucket;
    celltype *oldheader;
    if(DiMember(name, *Ap, 0)==0){
        bucket=h(name);
        oldheader=(*Ap)[bucket];
        (*Ap)[bucket]=(celltype*)malloc(sizeof(celltype));
        strcpy((*Ap)[bucket]->name, name);
        (*Ap)[bucket]->time= time;
        (*Ap)[bucket]->next=oldheader;

        celltype *send;
        send=(*Ap)[bucket];
        send->next=NULL;
        Sort(send, Array);
    }
}

(Everything is the same, except I added another parameter into the function, and I added that bit (celltype *send; ... Sort(send, Array);) at the end.)

And this is how the function looks:

void Sort(celltype* Data, Dictionary *Array){
     if ((*Array)[0]==NULL){
         (*Array)[0]=Data;
         (*Array)[0]->next=NULL;
     }

    else{
        int i;
        for(i=0;(*Array)[i]!=NULL;i++){
            if(Data->time < (*Array)[i]->time){
                celltype *new;
                new=(*Array)[i];
                (*Array)[i]=new;
                (*Array)[i]->next=NULL;
                int j=i+1;
                while((*Array)[j]!=NULL){
                    celltype *old;
                    old=(*Array)[j];
                    (*Array)[j]=new;
                    (*Array)[j]->next=NULL;
                    new=old;
                    j++;
                }
                (*Array)[j]=new;
                (*Array)[j]->next=NULL;
                break;
            }
        }
    }
}

These are my problems:

  1. There is a problem in the call of the function Sort/function parameters. I still have some problems understanding pointers so I'm not really sure how to fix it.

  2. Before modifying the DiInsert, the first bit of code worked. Now, after modifying and adding the void Sort(), for some reason it sometimes doubles the data in the original Dictionary Ap and saves it in the correct i-th bracket, but also in some other bracket as well.

  3. It also doubles the data in the Dictionary Array. For example, if I input 'Mark' as name and 10.1 as time, h(Mark)=15, so it saves Mark's data in the 15-th bracket of the Dictionary Ap. Then, it saves Mark's data in the 0th bracket in the Dictionary Array (as it should, because Mark's data is the first data inputed and he's the fastest one for now) but then it ALSO saves it in the 16-th bracket. Why?

  • Please read [Is it a good idea to typedef pointers?](https://stackoverflow.com/questions/750178/is-it-a-good-idea-to-typedef-pointers), to which the TL;DR is "usually No". You have `typedef celltype **Dictionary;` which is a typedef for pointer-to-pointer. You're a braver human than I am to be working with pointers to `Dictionary` ([Three-Star Programmer](http://c2.com/cgi/wiki?ThreeStarProgrammer) isn't a complement). Occasionally such extreme pointer-to-pointer-to-pointer work is necessary; it is not often necessary. – Jonathan Leffler Feb 05 '19 at 01:36

1 Answers1

0

You usually can't use a dictionary for storing sorted results, because those are data structures designed for fast random access, not sorted access. You should use an array and sort that array.

But as you already have all elements in the dictionary it will be simple to generate the array and then do the sort. As this is a homework, after all, I'll onlu sketch the idea and let you fill out the rest:

  1. count the number of celltype elements in your dictionary and store it to total_elements
  2. allocate a new array of type celltype * of length total_elements with name sort_array
  3. write a function that goes through your dictionary and adds the address of each celltype element to sort_array
  4. write a comparison function suitable that implements the sorting order you want to achieve with the name sort_compare_func()
  5. run the sort algorithm on sort_array with total_elements using sort_compare_func()

I'm not sure if your homework requires you to implement your own sort algorithm. My code fragment will use the standard POSIX function qsort():

// compare function for sort algorithm
static int sort_compare_func(const void *a, const void *b) {
     // called with pointers to (celltype *) elements in array
     double timeA = (*(celltype **) a)->time;
     double timeB = (*(celltype **) b)->time;

     // <  0 : a faster than b
     if (timeA < timeB) return(-1);
     // >  0 : b faster than a
     if (timeB < timeA) return( 1);
     // == 0 : a same time as b
     return(0);
}
....

unsigned int total_elements = count_elements_in_dictionary(Ap);
celltype **sort_array       = malloc(total_elements * sizeof(celltype *));

// fill the array
fill_sort_array_from_dictionary(Ap, sort_array);

// sort_array[0]                  points to the first celltype element found in Dictionary
// sort_array[total_elements - 1] points to the last  celltype element found in Dictionary

// sort array using POSIX quick sort implementation
qsort(sort_array, total_elements, sizeof(celltype *), sort_compare_func);

// sort_array[0]                  points to the celltype element with the smallest time
// sort_array[total_elements - 1] points to the celltype element with the largest time

celltype *winner = sort_array[0];
printf("and the winner is: %s with %f\n", winner->name, winner->time);

Simple test code: 100 elements with random time from 0 to 100:

#include <stdlib.h>
#include <time.h>

.... 
unsigned int total_elements = 100;
....
//fill_sort_array_from_dictionary(Ap, sort_array);
srand(time(NULL));
celltype *data = malloc(total_elements * sizeof(celltype));
for (int i = 0; i < total_elements; i++) {
   sprintf(data[i].name, "%04d", i);
   data[i].time  = (rand() * 100.0) / RAND_MAX;
   sort_array[i] = &data[i];
}
...

Some test runs:

$ gcc -Wall -o dummy dummy.c
$ ./dummy 
and the winner is: 0085 with 0.165149
and the looser is: 0066 with 99.612887
$ ./dummy 
and the winner is: 0044 with 0.484525
and the looser is: 0006 with 98.964099
$ ./dummy 
and the winner is: 0066 with 0.293111
and the looser is: 0016 with 99.822637

Hope this helps.

Stefan Becker
  • 5,695
  • 9
  • 20
  • 30