473,545 Members | 2,003 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

questions about the STL sort()

STL sort() as an implementation of introsort, below is the code
snippet from the gnu stl.

template<typena me _RandomAccessIt erator, typename _Size>
void
__introsort_loo p(_RandomAccess Iterator __first,
_RandomAccessIt erator __last,
_Size __depth_limit)
{
typedef typename iterator_traits <_RandomAccessI terator>::value _type
_ValueType;

while (__last - __first _S_threshold)
{
if (__depth_limit == 0)
{
std::partial_so rt(__first, __last, __last);
return;
}
--__depth_limit;
_RandomAccessIt erator __cut =
std::__unguarde d_partition(__f irst, __last,
_ValueType(std: :__median(*__fi rst,
*(__first
+ (__last
- __first)
/ 2),
*(__last
- 1))));
std::__introsor t_loop(__cut, __last, __depth_limit);
__last = __cut;
}
}

my question is : why not use two recursive calls to __introsort_loo p,
it will have a clear view to present a divide-and-conquer algorithm.
Yes, it is a optimization,bu t tail recursion elimination is now a
common technique of today's cpp compiler.
another question is about the __final_inserti on_sort() placed after
the call to __introsort_loo p()
below is the code snippet.

template<typena me _RandomAccessIt erator>
void
__final_inserti on_sort(_Random AccessIterator __first,
_RandomAccessIt erator __last)
{
if (__last - __first _S_threshold)
{
std::__insertio n_sort(__first, __first + _S_threshold);
std::__unguarde d_insertion_sor t(__first + _S_threshold, __last);
}
else
std::__insertio n_sort(__first, __last);
}

why not just call one __insertion_sor t in the if-condition?
Jul 8 '08 #1
5 4906
Hello,

feverzsj wrote:
STL sort() as an implementation of introsort, below is the code
snippet from the gnu stl.
my question is : why not use two recursive calls to __introsort_loo p,
it will have a clear view to present a divide-and-conquer algorithm.
Yes, it is a optimization,bu t tail recursion elimination is now a
common technique of today's cpp compiler.
I'm not sure tail recursion does apply here. Since the code is there,
you could try out what the compilers do. I'm pretty sure that saving
one recursive call saves enough, e.g. initializing the iterators for
every recursive instance, to justify doing it that way. Automatically
transforming non-tail recursion away, even partially, is a pretty
complicated operation with too many problematic cases. I would not
expect any compiler sacrificing lots of time in fruitless analysis in
that area.
>

another question is about the __final_inserti on_sort() placed after
the call to __introsort_loo p()
below is the code snippet.

template<typena me _RandomAccessIt erator>
void
__final_inserti on_sort(_Random AccessIterator __first,
_RandomAccessIt erator __last)
{
if (__last - __first _S_threshold)
{
std::__insertio n_sort(__first, __first + _S_threshold);
std::__unguarde d_insertion_sor t(__first + _S_threshold, __last);
}
else
std::__insertio n_sort(__first, __last);
}

why not just call one __insertion_sor t in the if-condition?
__unguarded_ins ertion_sort saves bounds-checking, therefore it needs
some elements less or equal in the area before first + _S_threshold. It
will always read at least at position __first + _S_threshold - 1, and
it will sort arbitrarily far before __first + _S_threshold. The big
question is, why there must be an element less then all in range
[__first + _S_threshold, __last) in the range [__first, __first +
_S_threshold). An that can only be found when looking at the places
calling this function.

I think this splitting should make an easily measurable difference when
sorting containers of small elements like integer.

Bernd Strieder

Jul 8 '08 #2
feverzsj wrote:
my question is : why not use two recursive calls to __introsort_loo p,
it will have a clear view to present a divide-and-conquer algorithm.
Yes, it is a optimization,bu t tail recursion elimination is now a
common technique of today's cpp compiler.
What would be the advantage of not removing the second recursive call?
The only effect is that it will start relying on the tail recursion
optimization to exist and succeed, for no good reason.

The code itself is not even intended to be looked at.
Jul 8 '08 #3
On Jul 8, 10:32 am, feverzsj <fever...@hotma il.comwrote:
STL sort() as an implementation of introsort, below is the
code snippet from the gnu stl.
template<typena me _RandomAccessIt erator, typename _Size>
void
__introsort_loo p(_RandomAccess Iterator __first,
_RandomAccessIt erator __last,
_Size __depth_limit)
{
typedef typename iterator_traits <_RandomAccessI terator>::value _type
_ValueType;
while (__last - __first _S_threshold)
{
if (__depth_limit == 0)
{
std::partial_so rt(__first, __last, __last);
return;
}
--__depth_limit;
_RandomAccessIt erator __cut =
std::__unguarde d_partition(__f irst, __last,
_ValueType(std: :__median(*__fi rst,
*(__first
+ (__last
- __first)
/ 2),
*(__last
- 1))));
std::__introsor t_loop(__cut, __last, __depth_limit);
__last = __cut;
}
}
my question is : why not use two recursive calls to __introsort_loo p,
Probably because the code was originally a quick sort (without
the __depth_limit), and they didn't want it to core dump due to
stack overflow.
it will have a clear view to present a divide-and-conquer
algorithm. Yes, it is a optimization, but tail recursion
elimination is now a common technique of today's cpp compiler.
First, I'm not sure that it's that common. Compilers optimize
for real code, and tail recursion isn't that frequent in C++.
And second, I'm not sure that the compiler can do the
optimization; if _RandomAccessIt erator has a non-trivial
destructor, it certainly can't.
another question is about the __final_inserti on_sort() placed after
the call to __introsort_loo p()
below is the code snippet.
template<typena me _RandomAccessIt erator>
void
__final_inserti on_sort(_Random AccessIterator __first,
_RandomAccessIt erator __last)
{
if (__last - __first _S_threshold)
{
std::__insertio n_sort(__first, __first + _S_threshold);
std::__unguarde d_insertion_sor t(__first + _S_threshold, __last);
}
else
std::__insertio n_sort(__first, __last);
}
why not just call one __insertion_sor t in the if-condition?
Probably optimization. Without seeing where this function is
called, and what the differences are between the two insertion
sorts, it's hard to say, but just guessing... this function is
called when the quick sort has partitionned the total range into
blocks of _S_threshold size, and all of the values in one block
are greater than the values in all previous blocks, and less
then the values in all following blocks. The standard insertion
sort will have to check for the bottom of the array in the inner
loop, something like (i and j are iterators):

for ( i = first + 1 ; i != last ; ++ i ) {
T tmp = *i ;
j = i ;
while ( j != first && *(j-1) tmp ) {
*j = *(j-1) ;
-- j ;
}
*j = tmp ;
}

If you're sorting anything but the first block after the
partitionning, you don't need the j != first test in the inner
loop.

--
James Kanze (GABI Software) email:ja******* **@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientier ter Datenverarbeitu ng
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jul 9 '08 #4
Hello,
Bernd Strieder wrote:
I'm not sure tail recursion does apply here. Since the code is there,
you could try out what the compilers do. I'm pretty sure that saving
one recursive call saves enough, e.g. initializing the iterators for
every recursive instance, to justify doing it that way. Automatically
transforming non-tail recursion away, even partially, is a pretty
complicated operation with too many problematic cases. I would not
expect any compiler sacrificing lots of time in fruitless analysis in
that area.
i see what u mean. STL is designed for both good portability and high
performance.
We can study a lot from it by comparing and rewriting.
If the __introsort_loo p() was written like this:

__introsort_loo p(/*...*/)
{
//...

if(__last - __first _S_threshold)
{
//....
}
std::__introsor t_loop(__cut, __last, __depth_limit);
std::__introsor t_loop(__first, __cut, __depth_limit);
}
Then, a tail recursion elimination could just simply replace the
params by the new one ,and goto the beginning of procedure.
The compiler may also identify only __last has changed , and just
replace the _last by __cut.
Finally ,we get the same effect as the GNU STL __introsort_loo p does.

__introsort_loo p(/*...*/)
{
//...

recu: if(__last - __first _S_threshold)
{
//....
}

std::__introsor t_loop(__cut, __last, __depth_limit);
// tail recursion elimination could be just simply like this
__first=__first ;
__last=__cut;
__depth_limit=_ _depth_limit;
goto recu;
}

__unguarded_ins ertion_sort saves bounds-checking, therefore it needs
some elements less or equal in the area before first + _S_threshold. It
will always read at least at position __first + _S_threshold - 1, and
it will sort arbitrarily far before __first + _S_threshold. The big
question is, why there must be an element less then all in range
[__first + _S_threshold, __last) in the range [__first, __first +
_S_threshold). An that can only be found when looking at the places
calling this function.

I think this splitting should make an easily measurable difference when
sorting containers of small elements like integer.
yeah ,that's a speed-up trick, but I have the same question as you
mentioned.
The place calling this function makes me doubt ,how could there must
be an element less then all in range [__first + _S_threshold, __last)
in the range [__first, __first + _S_threshold]

sort(_RandomAcc essIterator __first, _RandomAccessIt erator __last)
{

if (__first != __last)
{
std::__introsor t_loop(__first, __last, __lg(__last - __first) * 2);
std::__final_in sertion_sort(__ first, __last); // the only palce it
calls
}
}

or the __introsort_loo p() has assured such thing?

Furthermore ,the __unguarded_par tition() uses a simple 2-way
partitioning with no bound check, becuz the median-of-three method has
assured so. I think a 3-way partitioning could be a better partition
routine for common use with a slight overhead
Jul 9 '08 #5
hello:

James Kanze wrote:
Probably because the code was originally a quick sort (without
the __depth_limit), and they didn't want it to core dump due to
stack overflow.
First, I'm not sure that it's that common. *Compilers optimize
for real code, and tail recursion isn't that frequent in C++.
And second, I'm not sure that the compiler can do the
optimization; if _RandomAccessIt erator has a non-trivial
destructor, it certainly can't.
thx,you remind me of cpp's RAII feature, and i'm still on the road
from "c+" to "c++", a long way to pass through.

Probably optimization. *Without seeing where this function is
called, and what the differences are between the two insertion
sorts, it's hard to say, but just guessing... this function is
called when the quick sort has partitionned the total range into
blocks of _S_threshold size, and all of the values in one block
are greater than the values in all previous blocks, and less
then the values in all following blocks. *The standard insertion
sort will have to check for the bottom of the array in the inner
loop, something like (i and j are iterators):

* * for ( i = first + 1 ; i != last ; ++ i ) {
* * * * T tmp = *i ;
* * * * j = i ;
* * * * while ( j != first && *(j-1) tmp ) {
* * * * * * *j = *(j-1) ;
* * * * * * -- j ;
* * * * }
* * * * *j = tmp ;
* * }

If you're sorting anything but the first block after the
partitionning, you don't need the j != first test in the inner
loop.
below r the routines of __insertion_sor t() and the
__unguarded_ins ertion_sort().
looks like __insertion_sor t() is just a common implementation of
insertion sort,
and __unguarded_ins ertion_sort() is some kind insertion sort without
bound check
they'll be called right after the __introsort_loo p(/*...*/).
__insertion_sor t(_RandomAccess Iterator __first,
_RandomAccessIt erator __last)
{
if (__first == __last)
return;

for (_RandomAccessI terator __i = __first + 1; __i != __last; ++__i)
{
typename iterator_traits <_RandomAccessI terator>::value _type
__val = *__i;
if (__val < *__first)
{
std::copy_backw ard(__first, __i, __i + 1);
*__first = __val;
}
else
std::__unguarde d_linear_insert (__i, __val);
}
}

__unguarded_ins ertion_sort(_Ra ndomAccessItera tor __first,
_RandomAccessIt erator __last)
{
typedef typename iterator_traits <_RandomAccessI terator>::value _type
_ValueType;

for (_RandomAccessI terator __i = __first; __i != __last; ++__i)
std::__unguarde d_linear_insert (__i, _ValueType(*__i ));
}

as you mentioned:
>...the total range into blocks of _S_threshold size, and all of the valuesin one block are greater than the values in all previous blocks, and less then the values in all following blocks
it could be possibile, but i think the __unguarded_par tition() may
fail to partition the array with reduplicate keys.

__unguarded_par tition(_RandomA ccessIterator __first,
_RandomAccessIt erator __last, _Tp __pivot)
{
while (true)
{
while (*__first < __pivot)
++__first;
--__last;
while (__pivot < *__last)
--__last;
if (!(__first < __last))
return __first;
std::iter_swap( __first, __last);
++__first;
}
}
Jul 10 '08 #6

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

Similar topics

4
1616
by: tridion | last post by:
Could someone answer the following questions for me : 1. Discuss this C++ code fragment. Do you see any potential problems ? BSTR bsValue = _bstr_t("a string"); pComInterface->DoSomething(bsValue); 2. Give examples of the problems inherent in using the C preprocessor. When might you want to use it ?
3
12984
by: Alan | last post by:
I have some questions about the STL template "vector": - Do I need to do anything (e.g., "delete") to free memory when I`m done with a vector? I just declare it, and I know it allocates memory as needed. Just not sure about it releasing memory. - Does the STL algorithm "sort" work on vectors of complex objects? (The simplistic examples I...
8
5216
by: Mike | last post by:
Hello, I have a few rather urgent questions that I hope someone can help with (I need to figure this out prior to a meeting tomorrow.) First, a bit of background: The company I work for is developing a web-based application, one part of which involves allowing the user the ability to page through transaction "history" information. The...
4
1982
by: Megan | last post by:
Okay, I have a few questions regarding an Access database our company has. I should first mention that I'm not that knowledgable in Access and don't really know how to use it, but I am learning. We use Access as a Rolodex with names and addresses of clients and vendors, so it's made up of forms. First question: when I first open Access and the...
162
14730
by: techievasant | last post by:
hello everyone, Iam vasant from India.. I have a test+interview on C /C++ in the coming month so plz help me by giving some resources of FAQS, interview questions, tracky questions, multiple choice questions.etc.. I'll be indebted to everyone.. Thanks in advance.. regards vasant shetty Bangalore
4
2796
by: PCHOME | last post by:
Hi! I have questions about qsort( ). Is anyone be willing to help? I use the following struct: struct Struct_A{ double value; ... } *AA, **pAA;
2
1156
by: jy836 | last post by:
Firstly, is there a way to find out which column header a user has clicked on? And secondly, is there then an easy way (or any way, for that matter) to sort the items by that column (either alphabetically or numerically)? Thanks in advance.
0
32082
by: Jobs | last post by:
All answers to the below interview questions are at http://www.geocities.com/dotnetinterviews/ or you can download the complete answer zip file from http://www.questpond.com/ProjectManagementInterviewQuestions.zip What is project management?
4
1520
by: Schüle Daniel | last post by:
Hello, first question In : cmp("ABC",) Out: 1 against what part of the list is the string "ABC" compared? second question
3
1512
by: JJ | last post by:
I've done a little multi-threading on winform apps some time ago now, so I'm not a complete beginner, but best assume I am for any explanations..: This is an asp.net 2.0 website, using c#: I have a thread whose job is to send several emails (i.e. a long task that mustn't be run by more that one user at a time). It all works fine, but I am...
0
7478
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...
0
7410
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...
0
7668
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. ...
1
7437
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...
0
7773
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...
1
5343
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...
0
3466
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in...
1
1901
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
0
722
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating...

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.