Say you have a sorted array of characters:
char array[suitably_large_number] = { 'a', 'c', 'y', 'z' }
and you want to insert 'd'.
We can see just by looking that the insertion point is going to be between the 'c' and the 'y', but how do you determine that programmatically? Well, we're going to iterate through the array and look for the first character that is greater than 'd'. That character is going to be in the position we want our 'd' to be in. This is actually what
upper_bound does. It returns an iterator to the first element it encounters that is greater than the element we want to insert. (
lower_bound returns an iterator that points to the first element it encounters that is greater than or equal to the element we want to insert. Either would work here, but
upper_bound is going to be slightly more efficient.)
A simplified version of
upper_bound (for the problem just described) might look like this:
1 2 3 4 5 6 7 8 9 10 11 12
|
char* upper_bound(char* begin, char* end, char element)
{
char * current = begin ;
while ( current != end )
{
if ( *current > element )
break ;
++current ;
}
return currrent ;
}
|
So, now that we've found the insertion point, we need to move all elements at or to the right of the insertion point one element to the right, and make room for the element we want to insert. With the std library you could use
std::copy_backward, note that
std::copy isn't appropriate because the source and destination areas overlap.
Here is code using std::upper_bound and std::copy_backward. I've made an assumption based on your code (that the number of words in the file is on the first line of the file) which may cause problems if it isn't correct.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
|
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <algorithm>
void insert_ordered(std::string* words, const std::string& word, unsigned nWords )
{
if ( nWords == 0 )
words[0] = word ;
else
{
std::string* ub = std::upper_bound(words, words+nWords, word) ; // find the insertion point.
if ( ub != words+nWords ) // if the insertion point is not the
std::copy_backward(ub, words+nWords, ub+1) ; // end of the array, move some stuff.
*ub = word ;
}
}
int main()
{
using namespace std ;
ifstream fin("words.txt") ;
if(!fin.is_open())
{
cout << "Error opening file" << endl;
return 0 ;
}
unsigned totalWords ;
fin >> totalWords ;
std::string* words = new std::string[totalWords] ;
unsigned nWords = 0 ;
string word ;
while ( fin >> word )
insert_ordered(words, word, nWords++) ;
for (int i = 0; i < nWords; ++i)
cout << words[i] << endl;
}
|