Creating an index table in STL

Source: Internet
Author: User

In "Creating an index table in STL," ("C/C ++ Tips #1," August 2000) craig Hicks points out that an index table is a useful tool with no direct support in the Standard C ++ library. however, there is a simple and flexible way to indirectly create one.

An index table is simply a specialized version of a common STL entity-a sequence of pointers. as everyone who has tried to sort a vector of pointers knows, by default, they will be sorted according to the order of the pointers-the ordering of the addresses in memory. most of the time you 'd rather sort them according to the ordering of the objects pointed. the simplest way to do this is to defineOperator <For the pointers:

 

bool operator < (Widget const *a, Widget const *b)   { return *a < *b; }

This solution won't work for an index table, because you can't redefineOperator <On built-in integer types, and you wouldn't want to if you cocould. luckily, the STL authors anticipated the need to sort using other criteria. you are allowed to pass a comparison function or function object to the sort routines.

 

In this case, the comparison function needs to know the index value and the sequence that is being indexed. this solution requires a function object to store the information pertaining to what is being sorted. though my solution uses onlyBeginIterator, I also storeEndIterator. That feels more natural to me, andEndIterator cocould be used for error-checking, so it's a good idea to have it available. Note that the iterators must be random-access iterators for this to work.

 

#include <vector>#include <algorithm>#include <iostream>template <class random_iterator>class IndexedComparison{   public:      IndexedComparison (random_iterator begin,         random_iterator end)         : p_begin (begin), p_end (end) {}      bool operator () (unsigned int a, unsigned int b) const         { return *(p_begin + a) < *(p_begin + b); }   private:      random_iterator const p_begin;      random_iterator const p_end;};// Setup and reporting code below by Craig Hicksint main(){   unsigned int i;   int ai[10] = { 15,12,13,14,18,11,10,17,16,19 };   std::cout << "#################" << std::endl;   std::vector<int> vecai(ai, ai+10);   std::vector<unsigned int> indices(vecai.size ());   for (i = 0; i < indices.size (); i++)      indices [i] = i;   std::sort (indices.begin (), indices.end (),      IndexedComparison<std::vector<int>::const_iterator>         (vecai.begin (), vecai.end ()));   for (i=0; i<10; i++)      std::cout << "i=" << i                << ", aidxtbl[i]=" << indices[i]                << ", ai[aidxtbl[i]]=" << ai[indices[i]]                << std::endl;   std::cout << "#################" << std::endl;   return 0;}

 

TheSortCall becomes a bit long-winded, but it does the job admirably. It creates a temporaryIndexedcomparisonObject, keyed toConst_iteratorOf the sequence being indexed, and initialized with itsBeginAndEndIterators. That function object then ensures that the index sequence is sorted properly.

Any kind of STL sort can be used this way.IndexedcomparisonObject can also be extended to allow you to pass in a comparison function for the objects being indexed, which wocould make this solution every bit as flexible as the STL sorts themselves.

Herb Suter pointed out a disadvantage of this approach: "It pushes logic out into the calling code, which now has to loop to build the array and then callSortWith the correctly typed Predicate-and this has to be repeated everywhere this is going to be used. The original was better encapsulated, with just a single function call that implies Ded the setup ."

Herb adds, "however, exposingSortDoes give a benefit, to wit, the ability to replace the sorting function to be used, which was a question left for readers on the original ."

Several other readers have contributed interesting solutions in response to tip #1, which we may have e in future tips. some of those solutions, like Craig Hicks 'solution, require creation of a temporary table of iterators-potentially costly in terms of space and performance. I like the solution above because it doesn't require creation of any intermediate tables. -MB

There are also three better versions:
# Include <vector>
# Include <map>
# Include <algorithm>

// Solution 1 does some basic cleanup but still preserves the general structure
// Of the original's approach. We're down to 17 lines (even if you count "public :"
// And "Private:" As lines), where the original had 23.
//
Namespace solution1 {
Template <class ITER>
Class sort_idxtbl_pair {
Public:
Void set (const ITER & it, int I) {It _ = it; I _ = I ;}

Bool operator <(const sort_idxtbl_pair & Other) const
{Return * It _ <* Other. It _;}

Operator int () const {return I _;}
PRIVATE:
ITER it _;
Int I _;
};

// This function is where most of the clarity savings came from; it has 5 lines,
// Where the original had 13. After each code line, I'll show the corresponding
// Original code for comparison. prefer to write code that is clear and concise,
// Not unnecessarily complex or obscure!
//
Template <class iterin, class iterout>
Void sort_idxtbl (iterin first, iterin last, iterout out ){
STD: vector <sort_idxtbl_pair <iterin> V (last-first );
// Int idst = last-first;
// Typedef STD: vector <sort_idxtbl_pair <raiter> V;
// V (idst );

For (INT I = 0; I <last-first; ++ I)
V [I]. Set (first + I, I );
// Int I = 0;
// Raiter it = first;
// V: iterator Vit = V. Begin ();
// For (I = 0; it <last; it ++, Vit ++, I ++)
// (* VIT). Set (it, I );

STD: Sort (V. Begin (), V. End ());
// STD: Sort (V. Begin (), V. End ());

STD: Copy (V. Begin (), V. End (), OUT );
// Int * Pi = pidxtbl;
// Vit = V. Begin ();
// For (; Vit <v. End (); Pi ++, Vit ++)
// * Pi = (* VIT). I;
}
}

// Solution 2 uses a pair instead of reinventing a pair-like helper class. Now we're
// Down to 13 lines, from the original 23. Of the 14 lines, 9 are purpose-specific,
// And 5 are directly reusable in other contexts.
//
Namespace solution2 {
Template <class T, Class U>
Struct comparepair1stderef {
Bool operator () (const STD: pair <t, u> & A, const STD: pair <t, u> & B) const
{Return * A. First <* B. First ;}
};
Template <class iterin, class iterout>
Void sort_idxtbl (iterin first, iterin last, iterout out ){
STD: vector <STD: pair <iterin, int> S (last-first );
For (INT I = 0; I <S. Size (); ++ I)
S [I] = STD: make_pair (first + I, I );

STD: Sort (S. Begin (), S. End (), comparepair1stderef <iterin, int> ());

For (INT I = 0; I <S. Size (); ++ I, ++ out)
* Out = s [I]. Second;
}
}
// Solution 3 just shows a couple of alternative details? It uses a map to avoid
// Separate sorting step, and it uses STD: Transform () instead of a handcrafted loop.
// Here we still have 15 lines, but more are reusable. This version uses more space
// Overhead and probably more time overhead too, so I prefer solution 2, but this
// Is an example of finding alternative approaches to a problem.
//
Namespace solution3 {
Template <class T>
Struct comparederef {
Bool operator () (const T & A, const T & B) const
{Return * A <* B ;}
};
Template <class T, Class U>
Struct pair2nd {
Const U & operator () (const STD: pair <t, u> & A) const {return a. Second ;}
};

Template <class iterin, class iterout>
Void sort_idxtbl (iterin first, iterin last, iterout out ){
STD: multimap <iterin, Int, comparederef <iterin> V;
For (INT I = 0; first! = Last; ++ I, ++ first)
V. insert (STD: make_pair (first, I ));

STD: Transform (V. Begin (), V. End (), Out, pair2nd <iterin const, int> ());
}
}

// I left the test harness essential unchanged, failed t to demonstrate putting
// The output in an output iterator (instead of necessarily an int *) and using
// Source array directly as a container.
//
# Include <iostream>

Int main (){
Int Ai [10] = {15, 12, 13, 14, 18, 11, 10, 17, 16, 19 };

STD: cout <"###############" <STD: Endl;
STD: vector <int> aidxtbl (10 );

// Use another namespace name to test a different solution
Solution3: sort_idxtbl (AI, AI + 10, aidxtbl. Begin ());

For (INT I = 0; I <10; ++ I)
STD: cout <"I =" <I
<", Aidxtbl [I] =" <aidxtbl [I]
<", Ai [aidxtbl [I] =" <AI [aidxtbl [I]
<STD: Endl;
STD: cout <"###############" <STD: Endl;
}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.