Thread: Quick sorting an array of nodes in a linked list.

  1. #1
    Registered User HelpfulPerson's Avatar
    Join Date
    Jun 2013
    Location
    Over the rainbow
    Posts
    288

    Quick sorting an array of nodes in a linked list.

    Hello, I'm trying to sort the elements in a linked list which contain a variable amount of data in any given case. In the sample code, the code is more static, but I plan on adding it to much more dynamic code once I have it figured out. My main problem is that I am not sure how to sort the linked list while still keeping the correct pointers to the nodes. I thought about writing my own custom quick sort instead of using the C-standard library function, but how I would keep the pointers to the next nodes correct eluded me. I barely have any experience with data structures, so it would be nice if someone who studied this could help me. Here is my code so far :

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <time.h>
    
    
    /* ************************************************************************ */
    
    
    #define NUMBER_OF_NODES 6
    
    
    typedef struct linked_list
    {
        int x;
    
    
        struct linked_list * next;
    } linked_list;
    
    
    /* ************************************************************************ */
    
    
    linked_list * create( )
    {
        linked_list * temp = NULL;
    
    
        if ( !( temp = malloc( sizeof( linked_list ) ) ) )
        {
            perror( "Malloc" );
            exit( 1 );
        }
    
    
        return temp;
    }
    
    
    /* ************************************************************************ */
    
    
    linked_list * add( linked_list * head, int x )
    {
        linked_list * temp = NULL;
    
    
        if ( !head )
        {
            head = create( );
    
    
            head->x = x;
            head->next = NULL;
        }
        else
        {
            temp = create( );
            temp->next = head;
            head = temp;
    
    
            head->x = x;
        }
    
    
        return head;
    }
    
    
    /* ************************************************************************ */
    
    
    linked_list ** copy_list_to_array( linked_list * head, size_t * size )
    {
    
    
        linked_list ** list_array = NULL;
        linked_list * p1 = NULL;
    
    
        size_t array_size;
        int node_offset;
    
    
        for ( array_size = 0, p1 = head; p1; ++array_size, p1 = p1->next );
    
    
        list_array = malloc( sizeof( linked_list * ) * array_size );
    
    
        for ( node_offset = 0, p1 = head; p1; ++node_offset, p1 = p1->next )
            list_array[node_offset] = p1;
    
    
        *size = array_size;
    
    
        return list_array;
    }
    
    
    /* ************************************************************************ */
    
    
    int compare( const void * a, const void * b )
    {
        linked_list * p1 = ( linked_list * )a;
        linked_list * p2 = ( linked_list * )b;
    
    
        if ( p1->x < p2->x ) return -1;
        if ( p1->x == p2->x ) return 0;
        if ( p1->x > p2->x ) return 1;
    
    
        return 0;
    }
    
    
    /* ************************************************************************ */
    
    
    void print_list( linked_list * head )
    {
        linked_list * p1 = NULL;
    
    
        for ( p1 = head; p1; p1 = p1->next )
        {
            printf( "Node.x = %d\n", p1->x );
            printf( "---------------------------\n" );
        }
    }
    
    
    /* ************************************************************************ */
    
    
    void free_list( linked_list * head )
    {
        linked_list * p1 = head;
        linked_list * p2 = NULL;
    
    
        while ( p1 )
        {
            p2 = p1;
            p1 = p1->next;
            free( p2 );
    
    
            p2 = NULL;
        }
    }
    
    
    /* ************************************************************************ */
    
    
    int main( )
    {
        linked_list * head = NULL;
        linked_list ** list_array = NULL;
    
    
        size_t array_size;
        int n;
    
    
        srand( time( NULL ) );
    
    
        for ( n = 0; n < NUMBER_OF_NODES; n++ )
        {
            if ( n )
                head = add( head, rand( ) );
            else
                head = add( head, 0 );
        }
    
    
        list_array = copy_list_to_array( head, &array_size );
        qsort( list_array, ( array_size - 1 ), sizeof( linked_list * ), compare );
    
    
        print_list( list_array[0] );
        free_list( head );
        free( list_array );
    
    
        return 0;
    }
    "Some people think they can outsmart me, maybe. Maybe. I've yet to meet one that can outsmart bullet" - Meet the Heavy, Team Fortress 2

  2. #2
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    I see you're copying the list to an array and sorting that. That works, but it's somewhat inefficient, especially since you run through the list once just to count elements. Consider keeping the count of elements in a variable and incrementing it with every add. Also, you would fix the pointers by doing something like:
    Code:
    for (i = 0; i < array_size - 1; i++) {
        list_array[i]->next = list_array[i + 1];  // make node's next pointer point to next element in sorted array
    }
    list_array[i]->next = NULL;  // terminate list
    Several options/references/info to actually sorting a linked list (versus the copy-to-array-and-sort method): https://www.google.com/search?q=link...ing+algorithms.

    Another option is to insert the elements in sorted order, avoiding this all together. That does greatly increase the time for an insert.

    Note, your compare function doesn't not need to return specifically +1/-1. It can return any positive/negative number for greater/less than, so it can be simplified to:
    Code:
    return p1->x - p2->x;

  3. #3
    Registered User HelpfulPerson's Avatar
    Join Date
    Jun 2013
    Location
    Over the rainbow
    Posts
    288
    Quote Originally Posted by anduril462 View Post
    I see you're copying the list to an array and sorting that. That works, but it's somewhat inefficient, especially since you run through the list once just to count elements. Consider keeping the count of elements in a variable and incrementing it with every add. Also, you would fix the pointers by doing something like:
    Code:
    for (i = 0; i < array_size - 1; i++) {
        list_array[i]->next = list_array[i + 1];  // make node's next pointer point to next element in sorted array
    }
    list_array[i]->next = NULL;  // terminate list
    I tried that already, it didn't work. I end up getting this output.

    Code:
    Node.x = 24114
    ---------------------------
    Node.x = 11576
    ---------------------------
    Node.x = 28600
    ---------------------------
    Node.x = 17589
    ---------------------------
    Node.x = 11959
    ---------------------------
    Node.x = 0
    ---------------------------
    I'm not sure if for some reason the function didn't sort it or if I did something wrong somewhere, but it is obvious that the list is not sorted.

    Code:
    void re_link_list_array( linked_list ** list_array, size_t array_size )
    {
        int n;
    
    
        for ( n = 0; n < ( array_size - 1 ); n++ )
            list_array[n]->next = list_array[n + 1];
    
    
        return;
    }
    "Some people think they can outsmart me, maybe. Maybe. I've yet to meet one that can outsmart bullet" - Meet the Heavy, Team Fortress 2

  4. #4
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    You could create an array of pointers to the nodes, then sort the array of pointers, then set the head, tail, previous, and next pointers according to the array.

    You could create an array of 32 (or fewer) lists (head and tail pointers), plus 1 temp list, then merge the nodes into the array one at a time. array[0] has 1 node, array[1] has 2 nodes, array[2] has 4 nodes, array[3] has 8 nodes, array[x] has 2^x nodes. Once all nodes are merged into the array, you merge the lists from array[0] to array[31] (assuming an array of 32 lists) to result in a sorted list. This is how microsoft's STL performs sorts for linked lists.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Linked list and nodes
    By Lina_inverse in forum C Programming
    Replies: 2
    Last Post: 10-23-2012, 01:59 PM
  2. Replies: 11
    Last Post: 02-20-2012, 10:38 PM
  3. Adding nodes to a linked list
    By bluescreen in forum C Programming
    Replies: 4
    Last Post: 11-09-2006, 01:59 AM
  4. Linked List and Nodes
    By paperbox005 in forum C++ Programming
    Replies: 2
    Last Post: 08-04-2004, 09:12 AM
  5. Quick question on sorting a singly linked list
    By Ham in forum C++ Programming
    Replies: 1
    Last Post: 10-08-2001, 11:26 PM