TITLE("Tutorial") TOPIC_TEXT( "[ $$0,0#00000000000000000000000000000000:Default][l288;i704;a17;O9;~~~.992; $$1," "0#10431211400427159095818037425705:param][a83;*R6 $$2,5#3131016247420302412518841" "7583966:caption][b83;* $$3,5#07864147445237544204411237157677:title][b167;a42;C $" "$4,6#40027414424643823182269349404212:item][b42;a42; $$5,5#4541300047534217475409" "1244180557:text][l288;a17; $$6,6#27521748481378242620020725143825:desc][l321;t246" ";C@5;1 $$7,7#20902679421464641399138805415013:code][b2503; $$8,0#6514237545610002" "3862071332075487:separator][*@(0.0.255) $$9,0#83433469410354161042741608181528:ba" "se][t4167;C+117 $$10,0#37138531426314131251341829483380:class][l288;a17;*1 $$11,1" "1#70004532496200323422659154056402:requirement][i416;b42;a42;O9;~~~.416; $$12,12#" "10566046415157235020018451313112:tparam][b167;C $$13,13#9243045944346046191110808" "0531343:item1][a42;C $$14,14#77422149456609303542238260500223:item2][*@2$(0.128.1" "28) $$15,15#34511555403152284025741354420178:NewsDate][l321;*C$7 $$16,16#03451589" "433145915344929335295360:result][l321;b83;a83;*C$7 $$17,17#0753155046352950537122" "8428965313:result`-line][l160;t4167;*C+117 $$18,5#8860394944220582595880005322242" "5:package`-title][{_}%EN-US [s2; Tutorial - NTL in 10 steps&][s5; This tutorial i" "s as brief as is possible and should serve as basic overview of NTL. See referenc" "e documentation for further information.&][s3; 1. Vector basics&][s5; Let us star" "t with a simple [* Vector] of ints&][s7; -|[* Vector] v;&][s5; You can add e" "lements to the Vector as parameters of the [* Add] method&][s7; -|v.[* Add](1);&]" "[s7; -|v.Add(2);&][s7; -|v.Add(3);&][s5; To iterate Vector you can use indices&][" "s7; -|for(int i = 0; i < v.[* GetCount](); i`++)&][s7; -|-|cout << v[* `[]i[* `]]" " << 'n';&][s16; 1&][s16; 2&][s16; 3&][s5; or iterators&][s7; -|for(Vector" "`::[* Iterator] q = v.[* Begin](), e = v.[* End](); q != e; q`++)&][s7; -|-|cout " "<< [* *]q << 'n';&][s16; 1&][s16; 2&][s16; 3&][s3; 2. Vector operations&][s5; " "You can [* Insert] or [* Remove] elements at random posit") TOPIC_TEXT( "ions of Vector&][s7; -|Vector v;&][s7; -|v.Add(1);&][s7; -|v.Add(2);&][s7; " "-|&][s7; -|v.[* Insert](1, 10);&][s17; v = { 1, 10, 2 }&][s7; -|v.[* Remove](0);" "&][s17; v = { 10, 2 }&][s5; [* At] method returns element at specified position " "ensuring that such a position exists. If there is not enough elements in Vector, " "required number of elements is added. If second parameter of At is present, newly" " added elements are initialized to this value. As an example, we will create dist" "ribution of RandomValue with unknown maximal value&][s7; &][s7; -|v.Clear();&][s7" "; -|for(int i = 0; i < 10000; i`++)&][s7; -|-|v.[* At](RandomValue(), 0)`++;&][s1" "7; v = { 958, 998, 983, 1012, 1013, 1050, 989, 998, 1007, 992 }&][s5;* [* You ca" "n apply algorithms on containers, e.g. ]Sort&][s7; -|[* Sort](v);&][s17; v = { 9" "58, 983, 989, 992, 998, 998, 1007, 1012, 1013, 1050 }&][s3; 3. Transfer issues&][" "s5; Often you need to pass content of one container to another of the same type. " "For performance reasons, NTL containers follow [^dpp`:`/`/SourceDoc`/Containers`/" "pick`_^ default pick semantics], that means that source container is destroyed&][" "s7; -|Vector v;&][s7; -|v.Add(1);&][s7; -|v.Add(2);&][s7; &][s7; -|Vector v1 [* =] v;&][s5;^dpp`:`/`/SourceDoc`/Containers`/pick`_^ [^^ now source Vecto" "r ][C^^ v][^^ is destroyed - picked - and you can no longer access its content. " "Awful it might seem, it allows using containers as return values. If you really n" "eed to preserve value of source, you can use ]optional deep copy operator or cons" "tructor&][s7; -|v [* <<=] v1;&][s5; Now both containers have the same content. Co" "nstructor form of same operation is distinguished by an additional int parameter&" "][s7; -|Vector v2(v[* , 0]);&][s3; 4. Client types&][s5; So far we were usin" "g int as type of elements. In order to store client defined types into the Vector" " (and the Vector [^dpp`:`/`/SourceDoc`/Containers`/Overview^ flavor]) type must s" "atisfy [^dpp`:`/`/SourceDoc`/Containers`/Moveable^ moveab") TOPIC_TEXT( "le] requirement - in short, it must not contain back-pointers or virtual methods" ". Type must be marked as moveable in order to define interface contract using&][s" "7; -|struct Distribution : [* Moveable] {&][s7; -|-|string tex" "t;&][s7; -|-|Vector data;&][s7; -|};&][s5; Now to add Distrubution elements " "you cannot use Add with parameter, because it requires elements to have default d" "eep-copy constructor - and Distribution does not have one, as Vector has def" "ault pick-constructor, so Distribution itself has pick-constructor. It would no b" "e a good idea either, because deep-copy would involve expensive copying of inner" " Vector.&][s5; Instead, [* Add] without parameters has to be used - it default co" "nstructs (that is cheap) element in Vector and returns reference to it&][s7; -|Ve" "ctor dist;&][s7; -|for(n = 5; n <= 10; n`++) {&][s7; -|-|Distributi" "on`& d = dist.[* Add]();&][s7; -|-|char h`[20`];&][s7; -|-|sprintf(h, \"Test %d\"" ", n);&][s7; -|-|d.text = h;&][s7; -|-|for(i = 0; i < 10000; i`++)&][s7; -|-|-|d.d" "ata.At(rand() % n, 0)`++;&][s7; -|}&][s7; -|for(i = 0; i < dist.GetCount(); i`++)" "&][s7; -|-|cout << dist`[i`] << 'n';&][s7; &][s16; Test 5: { 2018, 1992, 2025, 1" "988, 1977 }&][s16; Test 6: { 1670, 1682, 1668, 1658, 1646, 1676 }&][s16; Test 7" ": { 1444, 1406, 1419, 1493, 1370, 1418, 1450 }&][s16; Test 8: { 1236, 1199, 1245" ", 1273, 1279, 1302, 1250, 1216 }&][s16; Test 9: { 1115, 1111, 1100, 1122, 1192, " "1102, 1089, 1064, 1105 }&][s16; Test 10: { 969, 956, 1002, 1023, 1006, 994, 1066" ", 1022, 929, 1033 }&][s5; Another possibility is to use AddPick method, which use" "s pick-constructor instead of deep-copy constructor. E.g. Distribution elements m" "ight be generated by some function &][s7; -|Distribution CreateDist(int n);&][s5;" " and code for adding such elements to Vector then looks like&][s7; -|for(n = 5; n" " <= 10; n`++)&][s7; -|-|dist.[* AddPick](CreateDist(n));&][s5; alternatively, you" " can use default-constructed variant too&][s7; -|-|dist.Add") TOPIC_TEXT( "() = CreateDist(); // alternative&][s3; 5. Array flavor&][s5; If elements do not" " satisfy requirements for Vector flavor, they can still be stored in Array flavor" ". Another reason for using Array is need for referencing elements - Array flavor " "never invalidates references or pointers to them.&][s5; E.g., std`::list implemen" "tation is often non-moveable, so you have to use Array&][s7; -|[* Array]< std`::l" "ist > al;&][s7; -|for(int i = 0; i < 4; i`++) {&][s7; -|-|std`::list`& " "l = al.Add();&][s7; -|-|for(int q = 0; q < i; q`++)&][s7; -|-|-|l.push_back(q);&]" "[s7; -|}&][s3; 6. Polymorphic Array&][s5; Array can even be used for storing poly" "morphic elements &][s7; -|struct Number {&][s7; -|-|virtual double Get() const = " "0;&][s7; -|};&][s7; &][s7; -|struct Integer : public Number {&][s7; -|-|int n;&][" "s7; -|-|virtual double Get() const { return n; }&][s7; -|&][s7; -|-|Integer(int n" ") : n(n) {}&][s7; -|};&][s7; &][s7; -|struct Double : public Number {&][s7; -|-|d" "ouble n;&][s7; -|-|virtual double Get() const { return n; }&][s7; -|&][s7; -|-|Do" "uble(double n) : n(n) {}&][s7; -|};&][s5; In this case, elements are added using " "Add with pointer to base element type parameter. Do not be confused by new and po" "inter, Array takes ownership of passed object and behaves like container of base" " type elements&][s7; -|Array num;&][s7; -|num.[* Add]([* new] Integer(3))" ";&][s7; -|num.Add(new Double(15.5));&][s7; -|num.Add(new Double(2.23));&][s7; -|n" "um.Add(new Integer(2));&][s7; -|num.Add(new Integer(20));&][s7; -|num.Add(new Dou" "ble(-2.333));&][s17; num = { 3, 15.5, 2.23, 2, 20, -2.333 }&][s5; Thanks to well" " defined algorithm requirements, you can e.g. directly apply Sort on such Array&]" "[s7; -|bool operator<(const Number`& a, const Number`& b)&][s7; -|{&][s7; -|-|ret" "urn a.Get() < b.Get();&][s7; -|}&][s7; &][s7; .......&][s7; &][s7; -|Sort(num);&]" "[s17; num = { -2.333, 2, 2.23, 3, 15.5, 20 }&][s3; 7. Bidirectional containers&]" "[s5; Vector and Array containers allow fast adding and re") TOPIC_TEXT( "moving elements at the end of sequence. Sometimes, same is needed at begin of se" "quence too (usually to support FIFO like operations). In such case, BiVector and " "BiArray should be used&][s7; -|BiVector n;&][s7; -|n.[* AddHead](1);&][s7; -" "|n.[* AddTail](2);&][s7; -|n.AddHead(3);&][s7; -|n.AddTail(4);&][s17; n = { 3, 1" ", 2, 4 }&][s7; -|n.[* DropHead]();&][s17; n = { 1, 2, 4 }&][s7; -|n.[* DropTail]" "();&][s17; n = { 1, 2 }&][s7; -|BiArray num;&][s7; -|num.AddHead(new Int" "eger(3));&][s7; -|num.AddTail(new Double(15.5));&][s7; -|num.AddHead(new Double(2" ".23));&][s7; -|num.AddTail(new Integer(2));&][s7; -|num.AddHead(new Integer(20));" "&][s7; -|num.AddTail(new Double(-2.333));&][s17; num = { 20, 2.23, 3, 15.5, 2, -" "2.333 }&][s3; 8. Index&][s5; Index is a container very similar to the plain Vecto" "r (it is random access array of elements with fast addition at the end) with one " "unique feature - it is able to fast retrieve position of element with required va" "lue using [* Find] method&][s7; -|[* Index] ndx;&][s7; -|ndx.[* Add](\"al" "fa\");&][s7; -|ndx.Add(\"beta\");&][s7; -|ndx.Add(\"gamma\");&][s7; -|ndx.Add(\"d" "elta\");&][s7; -|ndx.Add(\"kappa\");&][s17; ndx = { alfa, beta, gamma, delta, ka" "ppa }&][s7; -|DUMP(ndx.[* Find](\"beta\"))&][s17; ndx.Find(\"beta\") = 1&][s5; I" "f element is not present in Index, Find returns a negative value&][s7; -|DUMP(ndx" ".Find(\"something\"));&][s17; ndx.Find(\"something\") = -1&][s5; Any element can" " be replaced using [* Set] method&][s7; -|ndx.[* Set](0, \"delta\");&][s17; ndx " "= { delta, beta, gamma, delta, kappa }&][s5; If there are more elements with the " "same value, they can be iterated using [* FindNext] method&][s7; -|int fi = ndx.F" "ind(\"delta\");&][s7; -|while(fi >= 0) {&][s7; -|-|cout << fi << \" \";&][s7; -|-" "|fi = ndx.[* FindNext](fi);&][s7; -|}&][s7; -|cout << 'n';&][s17; 0 3-|&][s5; [*" " FindAdd] method retrieves position of element like Find, but if element is not p" "resent in Index, it is added&][s7; -|DUMP(ndx.[* FindAdd](\"one\"));&][s7; -|DUMP" "(n") TOPIC_TEXT( "dx.FindAdd(\"two\"));&][s7; -|DUMP(ndx.FindAdd(\"three\"));&][s7; -|DUMP(ndx.Fin" "dAdd(\"two\"));&][s7; -|DUMP(ndx.FindAdd(\"three\"));&][s7; -|DUMP(ndx.FindAdd(\"" "one\"));&][s7; &][s16; ndx.FindAdd(\"one\") = 5&][s16; ndx.FindAdd(\"two\") = 6" "&][s16; ndx.FindAdd(\"three\") = 7&][s16; ndx.FindAdd(\"two\") = 6&][s16; ndx." "FindAdd(\"three\") = 7&][s16; ndx.FindAdd(\"one\") = 5&][s5; Removing elements f" "rom random access sequence is always expensive, that is why rather than remove, I" "ndex supports [* Unlink] and [* UnlinkKey ]operations, which leave element in Ind" "ex but make it invisible for Find operation&][s7; -|ndx.[* Unlink](2);&][s7; -|nd" "x.[* UnlinkKey](\"kappa\");&][s7; &][s7; -|DUMP(ndx.Find(ndx`[2`]));&][s7; -|DUMP" "(ndx.Find(\"kappa\"));&][s7; &][s16; ndx.Find(ndx`[2`]) = -1&][s16; ndx.Find(\"" "kappa\") = -1&][s5; You can test whether element at given position is unlinked us" "ing [* IsUnlinked] method&][s7; -|DUMP(ndx.[* IsUnlinked](1));&][s7; -|DUMP(ndx.I" "sUnlinked(2));&][s7; &][s16; ndx.IsUnlinked(1) = 0&][s16; ndx.IsUnlinked(2) = 1" "&][s5; Unlinked positions can be reused by [* Put] method&][s7; -|ndx.[* Put](\"f" "oo\");&][s17; ndx = { delta, beta, foo, delta, kappa, one, two, three }&][s7; -|" "DUMP(ndx.Find(\"foo\"));&][s17; ndx.Find(\"foo\") = 2&][s5; You can also remove " "all unlinked elements from Index using [* Sweep] method&][s7; -|ndx.Sweep();&][s1" "7; ndx = { delta, beta, foo, delta, one, two, three }&][s5; As we said, operatio" "ns directly removing or inserting elements of Index are very expensive, but somet" "imes this might not matter, so they are available too&][s7; -|ndx.[* Remove](1);&" "][s17; ndx = { delta, foo, delta, one, two, three }&][s7; -|ndx.[* RemoveKey](\"" "two\");&][s17; ndx = { delta, foo, delta, one, three }&][s7; -|ndx.[* Insert](0," " \"insert\");&][s17; ndx = { insert, delta, foo, delta, one, three }&][s5; Final" "ly, [* PickKeys] operation allows you to obtain Vector of elements of Index in lo" "w constant time operation (while destroying source Index)&][s7; -|Vector " "d = ndx.[* Pic") TOPIC_TEXT( "kKeys]();&][s7; -|Sort(d);&][s17; d = { delta, delta, foo, insert, one, three }" "&][s3; 9. Index and client types&][s5; In order to store elements to Index, they " "must be moveable (you can use [* ArrayIndex] for types that are not) and they mus" "t have defined the operator== and a function to compute hash value. Notice usage " "of [* GetHashValue] for types already known to NTL (fundamental types and `[w`]st" "ring) and [* CombineHash] to combine both hash values into final result&][s7; -|s" "truct Person : Moveable {&][s7; -|-|string name;&][s7; -|-|string surname" ";&][s7; -|&][s7; -|-|Person(string name, string surname)&][s7; -|-|: name(name), " "surname(surname) {}&][s7; -|-|Person() {}&][s7; -|};&][s7; &][s7; -|unsigned [* G" "etHashValue](const Person`& p)&][s7; -|{&][s7; -|-|return [* CombineHash]([* GetH" "ashValue](p.name), &][s7; -|-| [* GetHashValue](p.surname));&][" "s7; -|}&][s7; &][s7; -|bool operator==(const Person`& a, const Person`& b)&][s7; " "-|{&][s7; -|-|return a.name == b.name `&`& a.surname == b.surname;&][s7; -|}&][s7" "; &][s7; .......&][s7; &][s7; -|Index p;&][s7; -|p.Add(Person(\"John\", \"" "Smith\"));&][s7; -|p.Add(Person(\"Paul\", \"Carpenter\"));&][s7; -|p.Add(Person(\"" "Carl\", \"Engles\"));&][s7; -| &][s7; -|DUMP(p.Find(Person(\"Paul\", \"Carpe" "nter\")));&][s17; p.Find(Person(\"Paul\", \"Carpenter\")) = 1&][s5; If type cann" "ot be stored in Index or if references to elements are required, [* ArrayIndex] c" "an be used&][s7; -|unsigned GetHashValue(const Number`& n)&][s7; -|{&][s7; -|-|re" "turn GetHashValue(n.Get());&][s7; -|}&][s7; &][s7; -|bool operator==(const Number" "`& a, const Number`& b)&][s7; -|{&][s7; -|-|return a.Get() == b.Get();&][s7; -|}&" "][s7; &][s7; .......&][s7; &][s7; -|[* ArrayIndex] n;&][s7; -|n.Add(new I" "nteger(100));&][s7; -|n.Add(new Double(10.5));&][s7; -|n.Add(new Integer(200));&]" "[s7; -|n.Add(new Double(20.5));&][s17; n = { 100, 10.5, 200, 20.5 }&][s7; -|DUMP" "(n.Find(Double(10.5)));&][s17; n.Find(Double(10.5)) = 1&][s3; 10. VectorMa") TOPIC_TEXT( "p&][s5; VectorMap is nothing more than a simple composition of Index and Vector." " You can use [* Add] methods to put elements into the VectorMap&][s7; -|[* Vector" "Map] m;&][s7; -|&][s7; -|m.[* Add](\"1\", Person(\"John\", \"Smit" "h\"));&][s7; -|m.Add(\"2\", Person(\"Carl\", \"Engles\"));&][s7; &][s7; -|Person`" "& p = m.[* Add](\"3\");&][s7; -|p.name = \"Paul\";&][s7; -|p.surname = \"Carpente" "r\";&][s5; VectorMap provides constant access to its underlying Index and Vector&" "][s7; -|DUMP(m.[* GetKeys]());&][s7; -|DUMP(m.[* GetValues]());&][s7; &][s16; m.G" "etKeys() = { 1, 2, 3 }&][s16; m.GetValues() = { John Smith, Carl Engles, Paul Car" "penter }&][s7; &][s5; You can use indices to iterate map contents&][s7; -|for(i =" " 0; i < m.GetCount(); i`++)&][s7; -|-|cout << m.[* GetKey](i) << \": \" << m[* `[" "]i[* `]] << 'n';&][s7; &][s16; 1: John Smith&][s16; 2: Carl Engles&][s16; 3: Paul" " Carpenter&][s7; &][s5; You can use [* Find] method to retrieve position of eleme" "nt with required key&][s7; -|DUMP(m.[* Find](\"2\"));&][s17; m.Find(\"2\") = 1&][" "s5; or [* Get] method to retrieve corresponding value&][s7; -|DUMP(m.[* Get](\"2\"" "));&][s17; m.Get(\"2\") = Carl Engles&][s5; Get method is also present in operato" "r form allowing VectorMap to act like functor&][s7; -|DUMP(m(\"1\"));&][s17; m(\"" "1\") = John Smith&][s5; Passing key not present in VectorMap as Get parameter is " "a logic error, but there exists two parameter version that returns second paramet" "er if key is not in VectorMap&][s7; -|DUMP(m.Get(\"33\", Person(\"unknown\", \"pe" "rson\")));&][s17; m.Get(\"33\", Person(\"unknown\", \"person\")) = unknown person" "&][s5; As with Index, you can use [* Unlink] to make elements invisible for Find " "operations&][s7; -|m.Unlink(1);&][s7; -|DUMP(m.Find(\"2\"));&][s17; m.Find(\"2\")" " = -1&][s5; You can use [* SetKey] method to change the key of the element&][s7; " "-|m.[* SetKey](1, \"33\");&][s7; -|DUMP(m.Get(\"33\", Person(\"unknown\", \"perso" "n\")));&][s17; m.Get(\"33\", Person(\"unknown\", \"person\")) = Carl Engles&][s5;" " If there are more elements with the ") TOPIC_TEXT( "same key in VectorMap, you can iterate them using [* FindNext] method&][s7; -|m." "Add(\"33\", Person(\"Peter\", \"Pan\"));&][s7; &][s16; m.GetKeys() = { 1, 33, 3, " "33 }&][s16; m.GetValues() = { John Smith, Carl Engles, Paul Carpenter, Peter Pan " "}&][s7; &][s7; -|int q = m.Find(\"33\");&][s7; -|while(q >= 0) {&][s7; -|-|cout <" "< m`[q`] << 'n';&][s7; -|-|q = m.[* FindNext](q);&][s7; -|}&][s7; -|&][s16; Carl " "Engles&][s16; Peter Pan&][s7; &][s5; You can reuse unlinked positions using [* Pu" "t] method&][s7; -|m.[* UnlinkKey](\"33\");&][s7; -|m.[* Put](\"22\", Person(\"Ali" "\", \"Baba\"));&][s7; -|m.Put(\"44\", Person(\"Ivan\", \"Wilks\"));&][s7; &][s16;" " m.GetKeys() = { 1, 22, 3, 44 }&][s16; m.GetValues() = { John Smith, Ali Baba, Pa" "ul Carpenter, Ivan Wilks }&][s7; &][s5; [* GetSortOrder] algorithm returns order " "of elements as Vector container. You can use it to order content of VectorMa" "p without actually moving its elements&][s7; -|bool operator<(const Person`& a, c" "onst Person`& b)&][s7; -|{&][s7; -|-|return a.surname == b.surname ? a.name < b.n" "ame&][s7; -| : a.surname < b.surname;&][s7; -|}&][s7" "; &][s7; .......&][s7; &][s7; -|Vector order = [* GetSortOrder](m.GetValues(" "));&][s17; order = { 1, 2, 0, 3 }&][s7; -|for(i = 0; i < order.GetCount(); i`++)&" "][s7; -|-|cout << m.GetKey(order`[i`]) << \": \" << m`[order`[i`]`] << 'n';&][s7;" " &][s16; 22: Ali Baba&][s16; 3: Paul Carpenter&][s16; 1: John Smith&][s16; 44: Iv" "an Wilks&][s7; &][s5; You can get Vector of values or keys using [* PickValues] r" "esp. [* PickKeys] methods in low constant time, while destroying content of sourc" "e VectorMap&][s7; -|Vector ps = m.[* PickValues]();&][s17; ps = { John Sm" "ith, Ali Baba, Paul Carpenter, Ivan Wilks }&][s5; If type of values does not sati" "sfy requirements for Vector elements or if references to elements are needed, you" " can use [* ArrayMap] instead&][s7; -|[* ArrayMap] am;&][s7; -|am" ".Add(\"A\", new Integer(1));&][s7; -|am.Add(\"B\", new Double(2.0));&][s7; &][s16" "; am") TOPIC_TEXT( ".GetKeys() = { A, B }&][s16; am.GetValues() = { 1, 2 }&][s7; &][s7; -|DUMP(am.Ge" "t(\"A\"));&][s7; -|DUMP(am.Find(\"B\"));&][s7; &][s16; am.Get(\"A\") = 1&][s16; a" "m.Find(\"B\") = 1")