C + + Experiment 4 STL

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

Tags: C++

Posted on Fri, 26 Nov 2021 04:01:24 -0500 by charliez