Iteratoren in C++ (Iteratoren in C++), Lektion, page 722670
https://www.purl.org/stefan_ram/pub/iteratoren_c++ (permalink) is the canonical URI of this page.
Stefan Ram
C++-Kurs

Bereichsfunktionen in C++ 

Unter einer Bereichsfunktion  verstehen wir hier eine Funktion, die einen Bereich  akzeptiert. Jener Bereich wird durch zwei Argumente der Bereichsfunktion angegeben: Die Anfangs- und die Deckelposition.

Binäres Suchen

Die binäre Suche ist besonders effizient und in der Regel schneller als eine lineare Suche, die bei einer nicht-sortierten Folge nötig ist.

Das folgende Beispiel zeigt die Implementation einer binären Suche mit »lower_bound«.

Wir benötigen »#include <algorithm>«.

Die Funktion »binary_find« akzeptiert einen Bereich, der zu einer aufsteigend sortierten Folge gehört, und einen Wert und ergibt, ob der Wert im Bereich vorkommt.

Die Funktion »binary_find« soll den Inhalt des ihr übergebenen Bereichs nicht  verändern. Die Funktion »::std::binary_search« benötigt daher keine  Schreibpositionen (also Positionen, über welche sie die Folge verändern  könnte). Wir können also »cbegin« und »cend« verwenden; es Qist nicht nötig, »begin« und »end« zu verwenden.

main.cpp

#include <algorithm>
#include <initializer_list>
#include <iostream>
#include <iterator>
#include <ostream>
#include <string>

template< class ForwardIterator, class T >
ForwardIterator binary_find( ForwardIterator first, ForwardIterator last, const T& value )
{ ForwardIterator iter = lower_bound( first, last, value );
if( iter !=last && *iter == value )return iter;
return last; }

int main()
{ ::std::string str{ "abcdefghijklmnopqrstuvwxyz" };
::std::cout << binary_find( cbegin( str ), cend( str ), 'c' )- cbegin( str )<< '\n';
::std::cout << binary_find( cbegin( str ), cend( str ), '#' )- cbegin( str )<< '\n'; }

transcript
2
26

Die Standardfunktion »::std::binary_search« ergibt hingegen keine Fundstelle, sondern nur, ob der Wert gefunden wurde.

main.cpp

#include <algorithm>
#include <initializer_list>
#include <iostream>
#include <iterator>
#include <ostream>
#include <string>

int main()
{ ::std::string str{ "abcdefghijklmnopqrstuvwxyz" };
::std::cout << binary_search( cbegin( str ), cend( str ), 'c' )<< '\n';
::std::cout << binary_search( cbegin( str ), cend( str ), '#' )<< '\n'; }

transcript
1
0

Ausgeben eines Initialisierungslistenobjekts

Die Funktion »::std::for_each« ruft ihr drittes Argument für jede Position eines Objektes des Bereiches auf. Dabei wird der Funktion der Inhalt  jenes Objektes übergeben.

main.cpp

#include <algorithm>
#include <initializer_list>
#include <iterator>
#include <ostream>
#include <iostream>

void print( char const c ){ ::std::cout << c << '\n'; }

int main()
{ ::std::initializer_list< char >l{ 'a', 'b', 'c' };
::std::for_each( cbegin( l ), cend( l ), print ); }

transcript
a
b
c

Die Positionen einer Initialisierungsliste werden – wie bei einer Reihung – durch Adressen  der Objekte angegeben. Die Objekte haben hier den Typ »char«. Daher findet ADL im Typ »char *« keinen Hinweis auf den Namensraum »::std«.

Erst durch Verwendung von Positionen könnnen wir Initialisierungslistenobjekte überhaupt ausgeben.

Das Besondere an den Bereichsfunktionen ist es, daß sie für alle möglichen Bereiche in einheitlicher Weise verwendet werden können, egal wo diese herkommen.

Wir können das eben gezeigte Verfahren zur Ausgabe eines Bereichs also genauso gut auch für Zeichenfolgen, Vektoren oder Reihungen verwenden!

main.cpp

#include <algorithm>
#include <initializer_list>
#include <iostream>
#include <iterator>
#include <ostream>

static void print( char const c ){ ::std::cout << c << '\n'; }

int main()
{ using ::std::cbegin;
using ::std::cend;
::std::initializer_list< char > l{ 'a', 'b', ' ' };
::std::string s{ 'c', 'd', ' ' };
::std::vector< char > v{ 'e', 'f', ' ' };
char a[] = "gh ";
::std::for_each( cbegin( l ), cend( l ), print );
::std::for_each( cbegin( s ), cend( s ), print );
::std::for_each( cbegin( v ), cend( v ), print );
::std::for_each( cbegin( a ), cend( a ), print ); }

transcript
a
b

c
d

e
f

g
h

»using« wurde oben zur Vereinheitlichung der Schreibweise für die Reihung verwendet.

Weitere Beispiele

Verwürfeln und Sortieren

Im folgenden Programm wird ein Bereich mit »::std::shuffle« verwürfelt und danach mit »::std::sort« sortiert.

main.cpp

#include <iostream>
#include <ostream>
#include <string>
#include <iterator>
#include <algorithm>
#include <initializer_list>
#include <random> // std::default_random_engine
#include <chrono> // std::chrono::system_clock

int main()
{ auto const seed{ ::std::chrono::system_clock::now().time_since_epoch().count() };
auto engine{ ::std::default_random_engine( seed )};

::std::string str{ "abcdefghijklmnopqrstuvwxyz" }; ::std::cout << str << "\n";
shuffle( begin( str ), end( str ), engine ); ::std::cout << str << "\n";
sort( begin( str ), end( str )); ::std::cout << str << "\n"; }

transcript
abcdefghijklmnopqrstuvwxyz
mnjibtkceqdfswxvgzauropylh
abcdefghijklmnopqrstuvwxyz

Beispiel 6 aus 49

main.cpp

#include <algorithm> // ::std::random_shuffle, ::std::copy_n
#include <array>
#include <iostream>
#include <iterator> // ::std::ostream_iterator
#include <numeric> // ::std::iota
#include <ostream>
#include <random>

int main()
{ using num = int;
using size_type = ::std::vector< num >::size_type;
auto output = ::std::ostream_iterator< int >( ::std::cout, " " );

constexpr size_type total_size = 49;
constexpr size_type selection_size = 6;

::std::array< num, total_size >a;
{ constexpr num offset = 1; ::std::iota( begin( a ), end( a ), offset ); }
copy_n( begin( a ), selection_size, output ); ::std::cout << '\n';
shuffle( begin( a ), end( a ), ::std::mt19937{} );
copy_n( begin( a ), selection_size, output ); ::std::cout << '\n'; }

transcript

1 2 3 4 5 6

33 44 27 35 32 3

Wird »::std::mt19937{}« durch »::std::mt19937{ ::std::random_device{}() }« ersetzt, verwendet man Zufallszahlen mit einem umgebungsabhängigen Startwert. (Dies ist aber 2016 unter MinGW gestört. Dort kann ersatzweise »::std::mt19937( ::std::time( 0 )* ::std::time( 0 ))« verwendet werden.)

UEBUNG E (nach der Behandlung von Bereichsfunktionen)

Schreiben Sie eine Funktion, die einen Vektor von int-Werten als Argument akzeptiert und unter Verwendung der Bereichsfunktion »accumulate« die Summe aller Werte des Vektors zurückgibt. Hierzu können Sie alle möglichen Informationsquellen heranziehen (Web, Bücher), um sich über die Verwendung dieser Funktion zu informieren.

About this page, Impressum  |   Form for messages to the publisher regarding this page  |   "ram@zedat.fu-berlin.de" (without the quotation marks) is the email-address of Stefan Ram.   |   A link to the start page of Stefan Ram appears at the top of this page behind the text "Stefan Ram".)  |   Copyright 1998-2014 Stefan Ram, Berlin. All rights reserved. This page is a publication by Stefan Ram. relevant keywords describing this page: Stefan Ram Berlin slrprd slrprd stefanramberlin spellched stefanram722670 stefan_ram:722670 Iteratoren in C++ Stefan Ram, Berlin, and, or, near, uni, online, slrprd, slrprdqxx, slrprddoc, slrprd722670, slrprddef722670, PbclevtugFgrsnaEnz Erklärung, Beschreibung, Info, Information, Hinweis,

Copyright 1998-2014 Stefan Ram, Berlin. All rights reserved. This page is a publication by Stefan Ram.
https://www.purl.org/stefan_ram/pub/iteratoren_c++