简体   繁体   中英

Sorting a linked-list of ints in C++

I have to make a type of linked-list that stores ints in order from smallest to largest. If you have or know how to make a sorting function for linked-lists please show if off here and / or teach me how to code it in C++.

I often sort linked lists via an index-pointer-list. To build one requires a memory allocation equivalent to the number of nodes (N) * the size of a node pointer. The concept is simple enough.

Note: this algorithm is in C, as I was not entirely sure if the OP meant to class this as a C++ question (who the hell uses linked lists in C++ with the standard containers at your disposal??)

  1. Determine the number (N) of nodes in the list
  2. Allocate a pointer-array for N node pointers .
  3. Load the pointer array with every node pointer in the list. Ie walk the list, and put a pointer in each slot of the pointer-array, incrementing as you go.
  4. Send this node pointer array to your sorting algorithm (I like the runtime library qsort() since it is standard-equipped).
  5. After sorting, walk the entire pointer array (less one), setting each node's "next" pointer to point to the one that follows. The last one sets its "next" pointer to NULL.
  6. Set the head pointer to be the first pointer [0] in the pointer array.
  7. Free the memory of the pointer array

Your linked list is sorted.


Assuming your node is something like this:

struct node
{
   ..data fields..
   int keyField;  // << determines sort order
   struct node *next;
};

Determine the number of nodes in your list. I'm assuming you have a proc that can do this, which is trivial:

size_t list_count(struct node* head)
{
   size_t count = 0;
   while (head)
   {
      ++count;
      head = head->next;
   }
   return count;
}

Allocate a pointer array the size of the list, where nItems is the list node count greater than 1 (no sense in bothering with a list of length zero or one):

struct node **ptrs = malloc(sizeof(*ptrs)*nItems);

Populate the pointer array with all the items in the list:

struct node *ptr = head;
size_t i=0;
for (;i<nItems;++i,ptr = ptr->next)
    ptrs[i] = ptr;

Now send this to qsort() with an appropriate comparision function. An example comparison function that sorts based on the keyField in our structure is below:

int compare_node_ptrs(const void* left, const void* right)
{
    struct node *l = *(struct node**)left;
    struct node *r = *(struct node**)right;
    return l->keyField - r->keyField;
}

Invoking qsort() looks like this:

qsort(ptrs, nItems, sizeof(*ptrs), compare_node_ptrs);

Now walk the entire list. rewiring "next" pointers:

for (i=0;i<(nItems-2);++i)
    ptrs[i]->next = ptrs[i+1];
ptrs[nItems-1] = NULL;

Rewire the head pointer.

head = ptrs[0];

And finally, free the pointer array.

free(ptrs);

Your linked list is sorted.


Sidebar merge-sort is the only O(nlogn) algorithm I know of that can sort a linked list with no added space requirements. A general solution that prototypes to the following would be nutz:

mergesort_list(void **head, size_t offset_ptr, int(*comp)(void*,void*))

head: address of the head pointer.
offset_ptr: offset in bytes from a node ptr where the 'link' pointer can be found.
comp: comparison function.

If we simply show you the code we will be doing you a great disservice. I will give you, instead, two different approaches and you can implement the one that you prefer.

The first approach is to "sort" as you insert: when you are inserting a value, say, 7, you follow this procedure starting with the first entry in your list until you run out of nodes:

If the node you are examining has a value that is greater than 7 you insert a new node before the node you are examining and return. Otherwise you look at the next node. If there is no next node, the. You insert a new node at the end of the list since that means that 7 is larger than al other entries in the list and return.

A second alternative is to sort the entire list using one of the many sorting algorithms. I would suggest that you use BubbleSort since it's easy to understand and implement. You can read more about bubblesort (ans many other sorting algorithms) on Wikipedia.

Good old quicksort will do the trick (C++03 friendly):

#include <algorithm>
#include <functional>
#include <iostream>
#include <iterator>
#include <list>

using namespace std;

void qsort(list<int>::iterator first, list<int>::iterator last)
{
    if (distance(first, last) < 2)
        return;
    int pivot = *first;

    list<int>::iterator it = partition(first, last, bind2nd(less<int>(), pivot));

    qsort(first, it);
    qsort(it, last);
}

int main()
{
    std::list<int> l;
    l.push_back(5);
    l.push_back(4);
    l.push_back(1);
    l.push_back(10);
    l.push_back(3);
    l.push_back(6);
    l.push_back(7);

    cout << "List:";
    copy(l.begin(), l.end(), std::ostream_iterator<int>(std::cout, " "));
    cout << endl;

    qsort(l.begin(), l.end());

    cout << "Sorted list:";
    copy(l.begin(), l.end(), std::ostream_iterator<int>(std::cout, " "));
    cout << endl;
    return 0;
}

Check: http://ideone.com/OOGXSp

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM