Experimental environment
Operating system: win10
gcc: 8.1.0
Development software: qt5.14.2
Introduction to STL
STL (Standard Template Library), namely standard template library, is an industrial strength and efficient C + + program library. It is contained in the C++ Standard Library. It is the latest and revolutionary part of ANSI/ISO C + + standard. The library contains many basic data structures and algorithms commonly used in the field of computer science. It provides an extensible application framework for C + + programmers, which highly reflects the reusability of software.
An important feature of STL is the separation of data structure and algorithm. Although this is a simple concept, this separation does make STL very general. For example, because the sort() function of STL is completely general, you can use it to operate almost any data set, including linked lists, containers and arrays;
Another important feature of STL is that it is not object-oriented. In order to have enough generality, STL mainly depends on template rather than encapsulation, inheritance and virtual function (polymorphism) - the three elements of OOP. You can't find any obvious class inheritance relationship in STL. This may seem like a setback, but it is the underlying feature that makes STL components universal. In addition, because STL is based on template, the use of inline function makes the generated code short and efficient;
From the logical level, the idea of generic programming is embodied in STL, and many new terms are introduced, such as requirements, concept, model, container, algorithm, iterator, etc. Like polymorphism in OOP (object oriented programming), generics is also a software reuse technology;
From the implementation level, the whole STL is implemented in a type parameterization way, which is based on a language feature - template, which did not appear in the previous C + + standard.
In short, STL is a universal standard template library. For example, when we sometimes need to use some basic algorithms such as heap, stack, queue and linked list in the program, and you really don't want to implement the cumbersome algorithms in the data structure textbook, you can consider using STL. In addition, STL is a standard to facilitate communication and master it, On the one hand, you can make the program you write easy for others to understand. On the other hand, you can also easily understand the program written by others.
The use of STL also needs to pay attention to the following three concepts
- Container: it can be understood as a place to store data. Some commonly used containers include list stack dynamic array vector deque queue map
- Iterator: it can be understood as pointer type. Many functions in STL need them as parameters
- Algorithms: they usually need to be used with containers and cursors. Using them, you can easily perform various common operations on the data in the container, such as sorting, finding the largest element, etc
Example - sequence and pixel transformation
After understanding the basic concept of STL, let's actually try to use STL to complete two small examples, that is, the transformation between sequence and pixel.
The first is to write their own functions to realize the negation, sum of squares and legislation of the sequence. Because this part is relatively simple, only the function part is given.
void transInv(int a[],int b[],int nNum) //Negate element { for(int i=0;i<nNum;i++) { b[i] = -a[i]; } } void transSqr(int a[],int b[],int nNum) //Square elements { for(int i=0;i<nNum;i++) { b[i] = a[i]*a[i]; } } void transPow(int a[],int b[],int nNum) //Cube elements { for(int i=0;i<nNum;i++) { b[i] = a[i]*a[i]*a[i]; } }
Then we use the template function to implement
template <typename T> void transInvT(T a[],T b[],int nNum) //Negate element { for(int i=0;i<nNum;i++) { b[i] = -a[i]; } } template <typename T> void transSqrT(T a[],T b[],int nNum) //Square elements { for(int i=0;i<nNum;i++) { b[i] = a[i]*a[i]; } } template <typename T> void transPow(T a[],T b[],int nNum) //Cube elements { for(int i=0;i<nNum;i++) { b[i] = a[i]*a[i]*a[i]; } } template<typename T> T InvT(T a) { return -a; } template <typename inputIter,typename outputIter,typename MyOperator> void transInvT(inputIter begInput,inputIter endInput,outputIter begOutput,MyOperator op) //Negate element { for(;begInput!=endInput;begInput++,begOutput++) { *(begOutput) = op(*begInput); } } template <typename T> void outputCont(string strName,ostream& os,T begin,T end) //Output element { os<<strName<<":"; for(;begin!=end;begin++) { os<<*begin<<"\t"; } os<<endl; };
In fact, the knowledge points used in the above examples have been involved in previous experiments. There are not too many comments here. Next, write a small test function and try to run it to verify the above results.
const int N=5; int a[N] = {1,2,3,4,5}; outputCont("a",cout,a,a+N); int b[N]; vector<double> vb(N); //container transInv(a,b,N); outputCont("Inv a",cout,b,b+N); transSqr(a,b,N); outputCont("Sqr a",cout,b,b+N); transPow(a,b,N); outputCont("Pow a",cout,b,b+N); transInvT(a,b,N); outputCont("InvT a",cout,b,b+N); transSqrT(a,b,N); outputCont("SqrT a",cout,b,b+N); transInvT(a,a+N,b,InvT<int>); outputCont("InvT a",cout,b,b+N); transInvT(a,a+N,vb.begin(),InvT<int>); //container outputCont("InvT a(vector)",cout,vb.begin(),vb.end()); //container transInvT(a,a+N,vb.begin(),MyThreshold<int>(2)); outputCont("InvT a by treshold",cout,vb.begin(),vb.end());
Note the last four lines in the above example; The last two lines are applied to the following functions
template<typename T> class MyThreshold { public: int _nThreshold; MyThreshold(int n=128):_nThreshold(n){} int operator()(T val) { return val<_nThreshold?0:1; //Less than_ nThreshold returns 0 } }
That is, this process is similar to binary pixel transformation. The embodiment here is that greater than 1 is 1, and vice versa is 0.
transInvT(a,a+N,vb.begin(),InvT<int>); //container outputCont("InvT a(vector)",cout,vb.begin(),vb.end()); //container
The above two lines apply to the concept of container; As mentioned above, the following incidentally gives the built-in function of vector in STL
v.capacity(); //Container capacity v.size(); //Container size v.at(int idx); //The usage is the same as [] operator v.push_back(); //Tail insertion v.pop_back(); //Tail deletion v.front(); //Get header element v.back(); //Get tail element v.begin(); //Iterator for header element v.end(); //Iterator for tail element v.insert(pos,elem); //pos is the position of the inserted element of the vector v.insert(pos, n, elem) //Insert n element elem at pos v.insert(pos, begin, end); v.erase(pos); //Remove the element at the pos position and return the position of the next data v.erase(begin, end); //Remove the data in the [begin, end) interval and return the position of the next element v.reverse(pos1, pos2); //Store the elements of pos1~pos2 in the vector in reverse order
Finally, the actual operation screenshot of the above example is given
Instance -- use set to build storage information
In this part, we will use the container class set as a small example of student information storage. Set is a standard association container in STL. Its bottom layer uses a balanced search tree - red black tree. When inserting and deleting, it only needs a pointer to operate the node, which does not involve memory movement and copying, so it is more efficient. Set, as the name suggests, is "set" Elements are unique in a set. By default, elements are automatically arranged in ascending order. Some set operations such as intersection, difference, and symmetry difference of the set are supported. If you need to allow repetition of elements in the set, you can use multiset.
In order to facilitate understanding, some common set built-in functions are given below
s.begin(); //Returns the first element of the set container s.end(); //Returns the last element of the set container s.clear(); //Delete all elements in the set container s.empty(); //Determine whether the set container is empty s.insert(); //Insert an element s.erase(); //Delete an element s.size(); //Returns the number of elements in the current set container
Then enter the instance
Firstly, the construction of experimental information class required by this experiment is completed
class studentInfo { public: studentInfo(string strNo, string strName) { _strNo = strNo; _strName = strName; } string _strNo; string _strName; friend ostream& operator<<(ostream& os, const studentInfo& info) { os << info._strNo << " " << info._strName; return os; } friend bool operator<(const studentInfo& info1, const studentInfo& info2) { return info1._strNo < info2._strNo; } }; //Output function template template < typename T> void outputCont(string strNme, ostream& os, T begin, T end) { os << strNme << ": "; for (; begin != end; begin++) { os << *begin << " |"; } os << endl; }
Here is a brief explanation of the above code. It implements a student class containing student name and student number, and contains two overloads for output, sorting and comparison.
It is actually a very simple example. Next, try to write a test function to test the common set functions mentioned above.
vector<studentInfo> students; students.push_back(studentInfo("1", "aa")); students.push_back(studentInfo("2", "bb")); students.push_back(studentInfo("3", "cc")); students.push_back(studentInfo("4", "dd")); students.push_back(studentInfo("5", "ee")); set<studentInfo> studentSet(students.begin(), students.end()); outputCont("origin", cout, studentSet.begin(), studentSet.end()); studentSet.insert(studentInfo("6", "ff")); outputCont("after insret", cout, studentSet.begin(), studentSet.end()); studentSet.erase(studentInfo("3", "cc")); outputCont("after erase", cout, studentSet.begin(), studentSet.end()); stuTemp.strName = "dd"; stuTemp.strNo = "6"; iter = studentSet.find(stuTemp); if(iter != studentSet.end()) { cout << (*iter).strName<< endl; } else { cout << "Cannot fine the student!" << endl; } return 0;
The above example simply tests the use effect of the three functions insret, erase and find in set. It is obvious that this can form a simple demo of addition, deletion, modification and query. Next, paste the screenshot of the actually running test
Instance -- use map to count the number of characters in a string
map is one of the associated containers, which stores pair objects (key value pairs). The key and value of each key value pair can be any data type, including C + + basic data types (char, int, double, etc.), user-defined structures or classes. The key value can neither be repeated nor modified.
It has the function of mapping. It adopts red black tree to sort automatically according to key values. Sort all key value pairs in ascending order according to the size of the key. Of course, according to the needs of the actual situation, we can manually specify the sorting rules of the map container. We can choose other sorting rules provided in the STL standard library or customize the sorting rules.
Common map functions are given according to convention
begin() Return point map Iterator for head clear() Delete all elements count() Returns the number of occurrences of the specified element empty() If map If it is blank, return true end() Return point map Iterator at the end equal_range() Returns an iterator pair for a special entry erase() Delete an element find() Find an element get_allocator() return map Configurator for insert() Insert element key_comp() Return comparison element key Function of lower_bound() Return key value>=The first position of a given element max_size() Returns the maximum number of elements that can be accommodated rbegin() Returns a pointer map Tail inverse iterator rend() Returns a pointer map Inverse iterator of header size() return map Number of elements in swap() Swap two map upper_bound() Return key value>The first position of a given element value_comp() Return comparison element value Function of
Next is a simple demo
void test() { map<char, int> str; //A map used to store the number of letter occurrences string test("thisisastringfortest"); for(int i=0;i<test.length();i++) { if(str.find(test[i])==str.end()) { str[test[i]]=1; } else { str[test[i]]++; } } for(auto i:str) { cout<<i.first<<": "<<i.second<<" "; } return 0; }
It should be added that frist and second refer to the key of map and the value of map respectively; Let's take a look at the actual operation results.
Supplement - red black tree
As mentioned above, the implementation of set and map is based on red black tree, so what is red black tree? The English name of red black tree is "red black tree", or R-B Tree for short. It is a loose balanced binary search tree, as shown below
The nodes in the red black tree are marked black and red. In addition, a red black tree also needs to meet the following requirements:
- The root node is black;
- Each leaf node is a black empty node (NIL), that is, the leaf node does not store data (the black and empty leaf nodes are omitted in the figure);
- Any adjacent nodes cannot be red at the same time, that is, red nodes are separated by black nodes;
- Each node, all paths from the node to its leaf node, contain the same number of black nodes;
The above explanation is taken from the next blog. If you need to know, you can move on
https://blog.csdn.net/xiaofeng10330111/article/details/106080394