Thread: Sorting array of struct inside struct

  1. #1
    Registered User
    Join Date
    Apr 2012
    Location
    Malang, Indonesia
    Posts
    22

    Sorting array of struct inside struct

    I don't know how to sort it? Can somebody help me. I am already trying qsort and bubble sort from google but I can't get it works. This is my full code
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <conio.h>
    #include <string.h>
    #define SWAP(a,b)   { int t; t=a; a=b; b=t; }  // Macro for swapping
    
    
    typedef struct mhs mhs;
    typedef struct kelas kelas;
    
    
    struct mhs
    {
        char nama[31];
        char nim[16];
        int angkatan;
        float ipk;
    };
    
    
    struct kelas
    {
        char kls[13];
        int jml;
        mhs mhs[40];
        kelas *next;
    };
    
    
    kelas *head;
    kelas *phead;
    int nodeKelas;
    
    
    void init()
    {
        head=NULL;
        nodeKelas=0;
    }
    
    
    int menu()
    {
        int pil;
        printf("\t\t------------------------\n");
        printf("\t\t|Program Data Mahasiswa|\n");
        printf("\t\t------------------------\n\n\n");
        printf("1. Menambah kelas\n");
        printf("2. Memasukkan data mahasiswa\n");
        printf("3. Menghapus data mahasiswa\n");
        printf("4. Input data dari file\n");
        printf("5. Tulis ke dalam file\n");
        printf("Masukkan pilihan anda\t: ");scanf("%d",&pil);
        return pil;
    }
    
    
    
    
    void insertKelas(char *klas)
    {
       kelas *newNode=malloc(sizeof(kelas));
       if(newNode != NULL)
       {
          strcpy(newNode->kls,klas);
          newNode->jml=0;
          newNode->next=head;
          head=newNode;
          nodeKelas++;
       }
       else printf("Gagal menambah kelas");
       getch();
    }
    
    
    int cocokKelas(char *klas)
    {
        kelas *itr = head;
        while (itr != NULL)
        {
            if(strcmp(itr->kls,klas)==0)
            {
                phead=itr;
                return 1;
            }
            else itr=itr->next;
        }
    }
    
    
    
    
    int insertMhs(char *nama,char *nim,int angkatan,float ipk)
    {
        kelas *itr = phead;
        if(itr->jml<40)
        {
            int jmlMhs;
            jmlMhs=itr->jml;
            strcpy(itr->mhs[jmlMhs].nama,nama);
            strcpy(itr->mhs[jmlMhs].nim,nim);
            itr->mhs[jmlMhs].angkatan=angkatan;
            itr->mhs[jmlMhs].ipk=ipk;
            itr->jml++;
        }
        else printf("Jumlah Mahasiswa yang anda masukkan sudah terlalu banyak");
        getch();
    }
    
    
    void bubble_srt( int *a, int n )
    {
        int i, j;
    
    
        for(i = 0; i < n; i++)         // Make a pass through the array for each element
        {
            for(j = 1; j < (n-i); j++) // Go through the array beginning to end
            {
               if(a[j-1] > a[j])       // If the the first number is greater, swap it
                  SWAP(a[j-1],a[j]);
            }
        }
    }
    
    
    int sortByName(const void *a,const void *b)
    {
        kelas *ia = (kelas*)a;
        kelas *ib = (kelas*)b;
        return strcmp(ia->mhs->nama, ib->mhs->nama);
    }
    
    
    int sortByNim(const void *a,const void *b)
    {
        kelas *ia = (kelas *)a;
        kelas *ib = (kelas *)b;
        return strcmp(ia->mhs->nim, ib->mhs->nim);
    }
    
    
    int sortByAngkatan(const void *a,const void *b)
    {
        kelas *ia = (kelas *)a;
        kelas *ib = (kelas *)b;
        return (ia->mhs->angkatan - ib->mhs->angkatan);
    }
    
    
    int sortByIpk(const void *a,const void *b)
    {
        kelas *ia = (kelas *)a;
        kelas *ib = (kelas *)b;
        return (int)(ib->mhs->ipk - ia->mhs->ipk);
    }
    
    
    void printList()
    {
        kelas *itr = head;
        while (itr != NULL)
        {
            printf("Kelas\t: %s",itr->kls);
            printf("Jumlah\t: %d\n\n",itr->jml);
            int i;
            for(i=0;i<itr->jml;i++)
            {
                printf("\t%d. Nama\t: %s\n",i+1, itr->mhs[i].nama);
                printf("\t   NIM\t: %s\n",itr->mhs[i].nim);
                printf("\t   Angkatan\t: %d\n",itr->mhs[i].angkatan);
                printf("\t   IPK: %.2f\n\n",itr->mhs[i].ipk);
            }
            itr = itr->next;
        }
    }
    
    
    void freeMemory()
    {
        kelas *deleteNode;
        while (head != NULL)
        {
            deleteNode = head;
            head = head->next;
            free(deleteNode);
        }
    }
    
    
    int main()
    {
        mhs *mhs;
        kelas *kelas;
        char tambahKelas[21],masukKelas[21];
        int pil;
        size_t structlen;
        init();
        do
        {
            system("CLS");
            pil=menu();
            switch (pil)
            {
                case 1:
                    printf("Menambah kelas\t:");getchar();fgets(tambahKelas,21,stdin);
                    insertKelas(tambahKelas);
                    break;
                case 2:
                    printf("Memasukkan ke kelas\t:");getchar();fgets(masukKelas,21,stdin);
                    int jumlah;
                    if(cocokKelas(masukKelas)==1)
                    do
                        {
                            printf("Jumlah mahasiswa yang ingin anda masukkan di kelas %s\t",masukKelas);scanf("%d",&jumlah);
                            if (jumlah>40) printf("Jumlah mahasiswa yang ingin anda masukkan terlalu banyak");
                            else if (jumlah<=0) printf("Jumlah mahasiswa yang ingin anda masukkan tidak valid");
                            else
                            {
                                int i,angkatanMhs;
                                char namaMhs[31],nimMhs[16];
                                float ipkMhs;
                                for(i=0;i<40&&i<jumlah;i++)
                                {
                                    printf("%d. Nama\t: ",i+1);getchar();fgets(namaMhs,30,stdin);
                                    printf("   NIM\t: ");fgets(nimMhs,15,stdin);
                                    printf("   Angkatan\t: ");scanf("%d",&angkatanMhs);
                                    printf("   IPK\t: ");scanf("%f",&ipkMhs);
                                    insertMhs(namaMhs,nimMhs,angkatanMhs,ipkMhs);
                                }
                            }
    
    
                        }while(jumlah>40&&jumlah<=0);
                        break;
                case 3:
                    printList();
                    getch();
                    break;
                case 4:
                    structlen=sizeof(kelas)/sizeof(mhs)[0];
                    qsort(kelas,structlen,sizeof(mhs),sortByName);
                    //kelas->mhs->angkatan=bubble_srt(&kelas->mhs->angkatan,4);
                    printList();
                    getch();
                    break;
                default:
                    break;
            }
       }while(pil>=1&&pil<4);
        freeMemory();
        return 0;
    }
    And also why when I wanna use fgets I need to put getchar before it? If I not do it, my program will directly read it as "\n".
    Actually I already trying to ask it in my earlier thread Declaring linked list inside linked list
    But because I think its already different problem I make it as a new post. I hope nobody mind it.

  2. #2
    Registered User
    Join Date
    Aug 2005
    Location
    Austria
    Posts
    1,990
    Code:
                    structlen=sizeof(kelas)/sizeof(mhs)[0];
                    qsort(kelas,structlen,sizeof(mhs),sortByName);
    Seems that you want to use qsort on a linked list.
    That won't work. qsort() sorts arrays only.
    Kurt

  3. #3
    Registered User
    Join Date
    Apr 2012
    Location
    Malang, Indonesia
    Posts
    22
    yes. But actually I just need sorting array of struct in 1 struct at 1 time. Not the entire linked list.
    I also tried to change it like this
    Code:
    int sortByName(const void *a,const void *b) { mhs *ia = (mhs*)a; mhs *ib = (mhs*)b; return strcmp(ia->nama, ib->nama); } structlen=sizeof(kelas)/sizeof(mhs)[0]; qsort(mhs,structlen,sizeof(mhs),sortByName);
    Bublesort didn't help too. Can you help me finding another method which I need to try?

  4. #4
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    When I compiled your code I got several warnings that you may want to look into:
    main.c||In function ‘main’:|
    main.c|193|warning: declaration of ‘mhs’ shadows a global declaration|
    main.c|8|warning: shadowed declaration is here|
    main.c|194|warning: declaration of ‘kelas’ shadows a global declaration|
    main.c|9|warning: shadowed declaration is here|
    main.c||In function ‘insertMhs’:|
    main.c|108|warning: control reaches end of non-void function|
    main.c||In function ‘cocokKelas’:|
    main.c|88|warning: control reaches end of non-void function|
    main.c||In function ‘main’:|
    main.c|242|warning: ‘kelas’ may be used uninitialized in this function|
    The first four and the last one may be part of your problem

    Jim

  5. #5
    Registered User
    Join Date
    Apr 2012
    Location
    Malang, Indonesia
    Posts
    22
    What compiler do you use? I use codeblock which used gcc I think and DEV C++ it shows no error. If I don't redeclare it in my main my compiler didn't want to compile it.

  6. #6
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    I use codeblocks on Linux which is using gcc. You need to change your project settings to enable the warnings. Right click on your project in the Management window, then select build options. There are quite a few options you can check. I usually use these options:
    "-Wshadow"
    "-Winit-self"
    "-Wredundant-decls"
    "-Wcast-align"
    "-Wundef"
    "-Wfloat-equal"
    "-Winline"
    "-Wunreachable-code"
    "-Wmissing-declarations"
    "-Wmissing-include-dirs"
    "-Wswitch-enum"
    "-Wswitch-default"
    "-Wmain"
    "-pedantic-errors"
    "-pedantic"
    "-Wextra"
    "-Wall"
    "-g"
    "-std=c99"
    The last option you need to select the "Other options" tab and type it in.

    Part of your problem is you are naming your variable the same as the type:
    Code:
    int main()
    {
        mhs *mhs;
        kelas *kelas;
    You should never name a variable the same name as the type. Would you name an int variable int?


    Jim
    Last edited by jimblumberg; 04-22-2012 at 09:50 AM.

  7. #7
    Registered User
    Join Date
    Apr 2012
    Location
    Malang, Indonesia
    Posts
    22
    If I don't redeclare it, it will shows error and I can't compile it. If I rename it, it will crash when I try to access that function. :S

  8. #8
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    You either need to change your typedef to give this structure a different type name, or you need to change the variable name to something different. No matter which you change you will need to make these changes everywhere you use that name. But you can not name your variable the same as the type name.

    Jim

  9. #9
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Forget Bubble Sort, that is easy for an array, but too hard to get right for linked-lists.
    QuickSort an work, but you'd have to write it yourself because qsort is for arrays.

    The simplest possible linked-list sorting algorithm is "Insertion Sort".
    Go and look up "Linked List Insertion Sort" in your favourite search engine.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  10. #10
    Registered User
    Join Date
    Apr 2012
    Location
    Malang, Indonesia
    Posts
    22
    Am I declaring this insertion sort function right?
    I am using source from wikipedia. But it doesn't show anything.
    Code:
    kelas *SortList()
    {
      /* build up the sorted array from the empty list */
      kelas *pSorted = NULL;
    
    
      /* take items off the input list one by one until empty */
      while (head != NULL)
        {
          /* remember the head */
          kelas *itr  = head;
          /* trailing pointer for efficient splice */
          kelas **ppTrail = &pSorted;
          /* pop head off list */
          head = head->next;
    
    
          /* splice head into sorted list at proper place */
          while (1)
            {
              /* does head belong here? */
              if (*ppTrail == NULL || itr->siswa->angkatan < (*ppTrail)->siswa->angkatan)
                {
                  /* yes */
                  itr->next = *ppTrail;
                  *ppTrail = itr;
                  break;
                }
              else
                {
                  /* no - continue down the list */
                  ppTrail = &(*ppTrail)->next;
                }
            }
        }
    
    
      return pSorted;

  11. #11
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    The only thing wrong with that is that it's using global variables. It's actually causing you to do the wrong thing I think.
    Instead of acessing 'head' as a global variable, pass it into this function. Then also make sure that you assign the head of the sorted list that the call to this funtion returns back to the 'head' variable.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  12. #12
    Registered User
    Join Date
    Apr 2012
    Location
    Malang, Indonesia
    Posts
    22
    So do you mean I need to change my whole code to use head from my main? Not from global variables? or I just need to do on this function only?

  13. #13
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    I'm only referring to this fuction. Rather than always referring to some global variable, it should take the list to be sorted as a parameter, that way it can be used to sort any list, not just the one specific list you have in a certain global variable.

    Then by assigning the return value back to your head variable you would solve the problem. Of course it would probably also be nice to make that variable not a global.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  14. #14
    Registered User
    Join Date
    Apr 2012
    Location
    Malang, Indonesia
    Posts
    22
    After I try to implement and understand it, this method sort the value from linked list. Am I right?
    I don't need that. I need to compare the array of struct in my node. So in my node which contain struct mhs[40], it will only sort some data in struct mhs[40]. I don't need to sort it from node1 to node2 (next node). I hope you understand it.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 1
    Last Post: 05-12-2011, 01:02 AM
  2. struct holding data inside a linked list struct
    By icestorm in forum C Programming
    Replies: 2
    Last Post: 10-06-2009, 12:49 PM
  3. array inside struct
    By tat in forum C Programming
    Replies: 15
    Last Post: 11-13-2007, 12:36 PM
  4. initializing char array inside a struct
    By panos in forum C Programming
    Replies: 6
    Last Post: 06-01-2007, 06:43 PM
  5. Replies: 3
    Last Post: 06-11-2002, 12:57 PM