473,804 Members | 2,983 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

attempt at qsort implementation

I had some spare time and decided to try to implement the standard library
qsort. This is a pretty simpleminded attempt, but it seems to be working. I
have to point out that efficiency is not at all an issue for me, and this is
purely a toy, so to speak. I'm quite aware that this is not the quickest way
to implement the quicksort algorithm, but I basically just wanted to try to
make a "generic function". I tested it with a few arrays of structures
containing all sorts of types (this, ofcourse, doesn't mean that it's
correct, even by a long shot :). I would appreciate any and all constructive
comments. The code below is a snippet. All the necessary headers are
included and uchar is a typedef for unsigned char.
Thank you.

void do_swap_(void *a, void *b, size_t sz)
{
uchar t;
uchar *i = a;
uchar *j = b;

while (sz) {
t = *i;
*i++ = *j;
*j++ = t;
--sz;
}
}
void quick_sort(void *v, size_t count, size_t sz, int (*cmp)(const void *,
const void *))
{
uchar *t = v;
uchar *x, *y;
uchar *r;

if (count) {
x = y = t;
r = t+(count-1)*sz;
for(; y<r; y += sz)
if (cmp(y, r)<0) {
do_swap_(x, y, sz);
x += sz;
}
do_swap_(x, r, sz);
quick_sort(t, (x-t)/sz, sz, cmp);
quick_sort(x+sz , count-(x-t)/sz - 1, sz, cmp);
}
}
Nov 14 '05 #1
13 2614
buda wrote:

I had some spare time and decided to try to implement the standard library
qsort. This is a pretty simpleminded attempt, but it seems to be working. I
have to point out that efficiency is not at all an issue for me, and this is
purely a toy, so to speak. I'm quite aware that this is not the quickest way
to implement the quicksort algorithm, but I basically just wanted to try to
make a "generic function". I tested it with a few arrays of structures
containing all sorts of types (this, ofcourse, doesn't mean that it's
correct, even by a long shot :).
I would appreciate any and all constructive
comments. The code below is a snippet. All the necessary headers are
included and uchar is a typedef for unsigned char.
Thank you.
This implementation will probably run out of memory
on large already ordered arrays.
If the array is in order prior to sorting,
then (x-t)/sz will be equal to count - 1
and you'll wind up with about count - 1, levels of recursion.
If count is large, the function could crash the program.
void do_swap_(void *a, void *b, size_t sz)
{
uchar t;
uchar *i = a;
uchar *j = b;

while (sz) {
t = *i;
*i++ = *j;
*j++ = t;
--sz;
}
}
void quick_sort(void *v, size_t count,
size_t sz, int (*cmp)(const void *,
const void *))
{
uchar *t = v;
uchar *x, *y;
uchar *r;

if (count) {
x = y = t;
r = t+(count-1)*sz;
for(; y<r; y += sz)
if (cmp(y, r)<0) {
do_swap_(x, y, sz);
x += sz;
}
do_swap_(x, r, sz);
quick_sort(t, (x-t)/sz, sz, cmp);
quick_sort(x+sz , count-(x-t)/sz - 1, sz, cmp);
}
}


--
pete
Nov 14 '05 #2
>I had some spare time and decided to try to implement the standard library
qsort. This is a pretty simpleminded attempt, but it seems to be working. I
have to point out that efficiency is not at all an issue for me, and this is
purely a toy, so to speak. I'm quite aware that this is not the quickest way
to implement the quicksort algorithm, but I basically just wanted to try to
make a "generic function".
qsort() is not required to implement any particular sort algorithm.
It's just supposed to sort. It's not specified HOW. A bubble sort
is not an invalid implementation. A recursive bogosort[*] (which
operates in time equivalent to O(e**infinity)) is probably an invalid
implementation since it NEVER finishes.
I tested it with a few arrays of structures
containing all sorts of types (this, ofcourse, doesn't mean that it's
correct, even by a long shot :). I would appreciate any and all constructive
comments. The code below is a snippet. All the necessary headers are
included and uchar is a typedef for unsigned char.
Thank you.


If count == 1, the algorithm does a compare anyway. I know you
weren't going for real efficiency here, but this seems a bit
strange.

If sz == 0, various wierd and obnoxious things will happen, but
the caller IS asking for it.

It seems like this algorithm could end up recursing a lot.
This could be a problem with large amounts of data.

One thing worth checking here is how well your algorithm will operate
with a bogus compare routine (e.g. one which always returns -1, or
one for which cmp(a,b) is not guaranteed to equal -cmp(b,a) ). Some
implementations end up going outside the passed-in array in such
circumstances.
[*] Technical note: a bogosort operates by creating all possible
orders of the sorted array, determining how many elements are out
of order, and returns the order with the least number of elements
out of order by sorting them and returning the first one. In other
words, it turns the problem of sorting N elements into one of sorting
N! elements.

A recursive bogosort uses bogosort to sort the possible orders by
number of elements out of order, thereby turning the problem of
sorting N elements into one of sorting N!!!!!!!!!!!!!! !!!!!!!!!!!!... .
elements. Bogosorts typically include other performance-wasting
code such as:
while (malloc(INT_MAX )) fork();
since they will never finish anyway.

Gordon L. Burditt

Nov 14 '05 #3
Gordon Burditt wrote:
I had some spare time and decided to try to
implement the standard library qsort.
qsort() is not required to implement any particular sort algorithm.
It's just supposed to sort. One thing worth checking here is how well your algorithm will operate
with a bogus compare routine (e.g. one which always returns -1, or
one for which cmp(a,b) is not guaranteed to equal -cmp(b,a) ).
Some implementations end up going outside the passed-in
array in such circumstances.


The behavior of qsort with a bogus compare routine, is undefined,
so what's the point?

--
pete
Nov 14 '05 #4
>>>I had some spare time and decided to try to
implement the standard library qsort.

qsort() is not required to implement any particular sort algorithm.
It's just supposed to sort.

One thing worth checking here is how well your algorithm will operate
with a bogus compare routine (e.g. one which always returns -1, or
one for which cmp(a,b) is not guaranteed to equal -cmp(b,a) ).
Some implementations end up going outside the passed-in
array in such circumstances.


The behavior of qsort with a bogus compare routine, is undefined,
so what's the point?


Testing. You do not want to get a segfault (or its undetected friends)
when a slightly faulty cmp() is provided.

If my first concern is being sure that everything works, I usually do
that with unit tests. There, I have usually conditional code I can
switch on for "do all checks" vs. assuming the "input is alright".

If I do not care for speed, I go for the former and try to handle
faulty input as well and provide test values (or in this case test
functions) which behave extreme or wrong or are, umh, don't know
the right word, "limit" cases, where the behaviour of the function
processing the input should change radically.

The bogus cmp() helps you to find such problems which could also
arise in some complicated and thus opaque real world applications.
One nice example is always people believing that floating point
variables could be treated as real numbers -- forgetting to account
for rounding errors in the operations as well as in the
representation of a number. Then they apply some operations, still
assuming the trichotomy of order or some such and wonder why their
results really do not fit, as they did not account for seemingly
impossible cases or the arbitraryness of some decisions based on
rounded values.
Cheers
Michael

Nov 14 '05 #5

"pete" <pf*****@mindsp ring.com> wrote in message
news:41******** ***@mindspring. com...
This implementation will probably run out of memory
on large already ordered arrays.
If the array is in order prior to sorting,
then (x-t)/sz will be equal to count - 1
and you'll wind up with about count - 1, levels of recursion.
If count is large, the function could crash the program.


As I said, trying to make this a useable qsort was not my intention in any
way. I'm aware of ways to improve worst case performance of the quicksort
algorithm (median of three/five, randomization.. .), but the sole purpose of
this attempt was to make a generic function, since I haven't done this yet
:)
Nov 14 '05 #6

In article <cj**********@i nfosun2.rus.uni-stuttgart.de>, Michael Mair <ma************ ********@ians.u ni-stuttgart.de> writes:

[Quoting pete <pf*****@mindsp ring.com> in message
<41**********@m indspring.com>. Please fix your newsreader to insert
proper attributions.]
The behavior of qsort with a bogus compare routine, is undefined,
so what's the point?


Testing. You do not want to get a segfault (or its undetected friends)
when a slightly faulty cmp() is provided.


There is a QoI issue here, but it's not clear that handling broken
comparison routines is the proper answer. That could have a
significant adverse effect on performance, which is probably one
of the reasons why the Standard makes a broken comparison routine
UB, rather than requiring implementations to, say, signal an error
in some fashion.

I've seen reports of commercial qsort implementations crashing if
given a broken comparison routine, and the response they've elicited
from other developers has generally been that the comparison routine
should be fixed, not that the qsort implementation should be made
more tolerant.

The C standard library generally favors efficiency over safety. We
may approve or disapprove, but trying to fix that in one particular
case is probably not worth any great effort. Someone who passes a
bad comparison routine to qsort will make a similar error with some
other library function elsewhere.

--
Michael Wojcik mi************@ microfocus.com

"We are facing a dire shortage of clowns," said Erickson, also known as
Jingles.
Nov 14 '05 #7
>> > The behavior of qsort with a bogus compare routine, is undefined,
> so what's the point?
Testing. You do not want to get a segfault (or its undetected friends)
when a slightly faulty cmp() is provided.


There is a QoI issue here, but it's not clear that handling broken
comparison routines is the proper answer. That could have a
significant adverse effect on performance, which is probably one
of the reasons why the Standard makes a broken comparison routine
UB, rather than requiring implementations to, say, signal an error
in some fashion.


Reliably detecting a broken comparison routine would probably mean
a big performance hit (e.g. running cmp(a,b) and cmp(b,a) and
checking that the results are negatives of each other, and even
that's not a thorough test). I'm not asking for that, I'm just
suggesting that arranging to not segfault would be a good idea.
And I'm not sure it means a big (or even any) performance hit to do that.

Consider the tech support issues. If it segfaulted in qsort, it's
obviously qsort's fault, right? How many times have we seen posters
claim to have found a bug in malloc() or free() when a debugger
indicates the segfault happened while executing one of those
functions?
I've seen reports of commercial qsort implementations crashing if
given a broken comparison routine, and the response they've elicited
from other developers has generally been that the comparison routine
should be fixed, not that the qsort implementation should be made
more tolerant.
But the commercial outfit's tech support line still takes a $$ hit,
doesn't it?
The C standard library generally favors efficiency over safety. We
may approve or disapprove, but trying to fix that in one particular
case is probably not worth any great effort. Someone who passes a
bad comparison routine to qsort will make a similar error with some
other library function elsewhere.


I think of this code more as user code, not something to replace a routine
in the standard library. User code should be able to handle bad input
without invoking UB.

Gordon L. Burditt
Nov 14 '05 #8
buda wrote:

"pete" <pf*****@mindsp ring.com> wrote in message
news:41******** ***@mindspring. com...
This implementation will probably run out of memory
on large already ordered arrays.
If the array is in order prior to sorting,
then (x-t)/sz will be equal to count - 1
and you'll wind up with about count - 1, levels of recursion.
If count is large, the function could crash the program.
As I said, trying to make this a useable qsort
was not my intention in any way.
I'm aware of ways to improve worst case performance of the quicksort
algorithm (median of three/five, randomization.. .),


Those are methods of improving speed and reducing the probability
of having the sort go quadratic.
but the sole purpose of this attempt was to make a
generic function, since I haven't done this yet
:)


What you have, is a function that can crash with valid input,
and by that, I mean abnormally terminate the program.

There is a way to rewrite your function
without improving it's speed in any way,
which will prevent it from recursing nmemb levels deep.

What you have to do, is find out which partition is smaller
and recurse that one.
The larger partitions should be handled
by making the function body into a loop.

Here's an example of the variation:
q0sort will crash for large ordered arrays,
q_sort won't.

void q0sort(void *base, size_t nmemb, size_t size,
int (*compar)(const void*, const void*))
{
unsigned char *middle, *left, *last, *right;
unsigned char swap, *p1, *p2, *end;

if (nmemb > 1) {
last = middle = left = base;
right = (nmemb - 1) * size + last;
do {
middle += size;
if (compar(left, middle) > 0) {
last += size;
BYTE_SWAP(middl e, last);
}
} while (middle != right);
BYTE_SWAP(left, last);
q0sort(last + size, (right - last) / size, size, compar);
q0sort(left , (last - left) / size, size, compar);
}
}

void q_sort(void *base, size_t nmemb, size_t size,
int (*compar)(const void*, const void*))
{
unsigned char *middle, *left, *last, *right;
size_t nmemb_right;
unsigned char swap, *p1, *p2, *end;

left = base;
while (nmemb > 1) {
last = middle = left;
right = (nmemb - 1) * size + last;
do {
middle += size;
if (compar(left, middle) > 0) {
last += size;
BYTE_SWAP(middl e, last);
}
} while (middle != right);
BYTE_SWAP(left, last);
nmemb = (last - left) / size;
nmemb_right = (right - last) / size;
if (nmemb_right > nmemb) {
q_sort(left, nmemb, size, compar);
left = last + size;
nmemb = nmemb_right;
} else {
q_sort(last + size, nmemb_right, size, compar);
}
}
}

--
pete
Nov 14 '05 #9
Michael Mair wrote:
I had some spare time and decided to try to
implement the standard library qsort.

qsort() is not required to implement any particular sort algorithm.
It's just supposed to sort.

One thing worth checking here is how well your algorithm will operate
with a bogus compare routine (e.g. one which always returns -1, or
one for which cmp(a,b) is not guaranteed to equal -cmp(b,a) ).
Some implementations end up going outside the passed-in
array in such circumstances.


The behavior of qsort with a bogus compare routine, is undefined,
so what's the point?


Testing. You do not want to get a segfault (or its undetected friends)
when a slightly faulty cmp() is provided.


I disagree. You want the segfault.
It's better to wrong than vague.

--
pete
Nov 14 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

11
2861
by: William Buch | last post by:
I have a strange problem. The code isn't written by me, but uses the qsort function in stdlib. ALWAYS, the fourth time through, the memory location of variable list (i.e. mem location = 41813698) becomes 11, then the program crashes. It is obviously qsort that may me overwritten the used memory location. The weird thing is that it is ALWAYS the fourth time running the program. Below is the code MEMORY LOCATION OK HERE for (i = 0; i...
5
3866
by: Steve | last post by:
can someone tell me how qsort function in <stdlib.h> is used (qsort(..........))? the function has a buffer, two void * parameters and the a pointer to a compare function. Thanks.
17
2672
by: Trent Buck | last post by:
The fourth argument is a comparator that returns `an integer less than, equal to, or greater than zero' depending on the ordering of its arguments. If I don't care about the order and simply want qsort() to run as quickly as possible, how should the comparator be defined? If qsort were stable, the following would be best: int
32
4564
by: John Smith | last post by:
I'm trying to figure out qsort(). I haven't seen any practical examples, only synopsis. In the code below, the array is not sorted. Can someone give me some help? #include <stdio.h> #include <stdlib.h> int compare(const void* a, const void* b); int main(void) {
23
6354
by: yatindran | last post by:
hai this is my 2d array. int a = { {5,2,20,1,30,10}, {23,15,7,9,11,3}, {40,50,34,24,14,4}, {9,10,11,12,13,14}, {31,4,18,8,27,17}, {44,32,13,19,41,19}, {1,2,3,4,5,6},
8
2349
by: Max | last post by:
Hi everybody, suppose you have to order a list of integers which refer to points located in the 3D space. The compare() function is based on the distance that these points have with respect to the origin (0,0,0). So, using the standart qsort() function, I think this task should be accomplished as follows: qsort(int_vector, (size_t)no_of_points, sizeof(int), compare_function);
14
2588
by: subramanian100in | last post by:
What is meant by stable qsort ?
10
2255
by: gauss010 | last post by:
Suppose I have an object A of type char. Each A is a buffer containing a string, and I want to sort the M strings of A using the strcmp function. The description of the qsort function says that I must pass a pointer to the first object of the array to be sorted. This leads me to write the following: char A; int cmp(const void *a, const void *b) { int v = strcmp(*(char (*))a, *(char (*))b); if (v < 0) return -1;
61
5862
by: Ron Ford | last post by:
K&R has three different versions of qsort, and the ultimate one is supposed to be like the one in the std library. I'm trying to implement the first, which is in §4.10. I think I'm pretty close with this: void qsort(int v, int left, int right) { int i, last;
0
9705
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9576
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10568
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
1
10311
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
10074
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
1
7613
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5647
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
4292
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
3813
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.