STL Standard Library for C++ Initial Knowledge
STL is an abbreviation for Standard Template Library, translated in Chinese as "Standard Template Library". STL is part of the C++ Standard Library.
Previously, we had a basic understanding of the template templet in C++ and the role of templates. It can be said that C++STL is a powerful set of C++ template classes that provide generic template classes and functions that implement a variety of popular and commonly used algorithms and data structures, such as vectors, chain tables, queues, stacks, etc. It also separates the data structure from the algorithm (templates allow you to implement an algorithm beyond a single data structure).
1. Three Core Components of C++ STL
The core of C++ STL consists of three components:
-
Containers
Containers are collections used to manage a class of objects. C++ provides different types of containers, such as deque, list, vector, map, and so on. Different containers are based on different data structures
-
Algorithms
Algorithms work on containers. They provide a way to perform various operations, including initialization, sorting, search, and conversion of container content. At the same time, thanks to the C++Templet, the implementation of the algorithm is also container independent.
-
iterators
Iterators are used to traverse elements of a collection of objects. These collections may be containers or subsets of containers.
In addition to the three core of STL described above, Algorithms in C++STL have another feature, that is, a step in the algorithm can be implemented by external user parameters (passing in a custom function), which greatly increases the diversity of algorithms.
2. Custom functions and algorithms operate on containers
For example, I believe that everyone has used the sort() sorting algorithm in Algorithms. The last parameter of the sort algorithm is passed in by the user to the comparison function. The sort() algorithm then sorts according to the user-defined comparison method. This allows us to ask the sort algorithm to sort from smallest to largest or from largest to smallest. In addition, if we pass in a class, the sort function will understand our intentions as long as we define in the comparison function how the sort of this class is compared by which member of the class. There is no need to redefine multiple sort algorithms.
Next, I will define my own algorithms and functions to solve sequence transformations (e.g., inversion, square, cube) and pixel transformations (binarization, gray stretching) using containers and iterators.
Custom action functions (analogous to sort()):
// Operations for sequential tables (using the custom operation function MyOperator) template <class T, class MyOperator> void transCalc(T a, T& b, int nNum, MyOperator op) { for(int i=0;i<nNum;i++) { b[i] = op(a[i]); } } // Operations for chain tables (using the custom operation function MyOperator) template <class inputIt, class outputIt, class MyOperator> void transCalcT(inputIt begInput, inputIt endInput, outputIt begOutput, MyOperator op) { for(;begInput!=endInput;begInput++,begOutput++){ *begOutput = op(*begInput); } }
Custom action templates (analogous to user-defined comparison functions):
// Operations templates are defined here to customize op operations: //Reverse template<class T> T InvT(T a) { return -a; } //square template<class T> T SqrT(T a) { return a*a; } // Class operation template, binary: // Since binarization requires an incoming threshold in addition to the incoming variable itself, classes are used to define it template<class T> class MyThreshold { public: int threshold; // n Default is 128 MyThreshold(int n=128):threshold(n){} // Overload operator'()'to execute customizations once the () incoming parameter is used: int operator()(T val) { return val > threshold; } }; //Compare Template Functions template<class T> bool MyCompare(T a, T b) { return a > b; } //Custom Compare Template Class template<class T> class MyComp { public: int op; // Custom comparison MyComp(int n):op(n){} bool operator()(T a, T b) { switch(op){ case 0: return a == b; break; case 1: return a > b; break; case -1: return a < b; break; } } };
Print functions for easy visualization:
// Print function template <class T> void outputCont(string strName, T beg, T end) { cout<<strName; for(;beg!=end;beg++){ cout<<*beg<<" "; } cout<<endl; }
Test sample:
void test_mystl() { const int N = 5; vector<int> a = {3,5,4,1,2}; vector<int> b(5); // Reverse transCalc(a,b,N,InvT<int>); outputCont("Inv a:", b.begin(), b.end()); // Square transCalc(a,b,N,SqrT<int>); outputCont("Sqr a:", b.begin(), b.end()); // Binarization transCalc(a,b,N,MyThreshold<int>(2)); outputCont("Sqr a:", b.begin(), b.end()); // The sort function uses a custom sort method sort(a.begin(), a.end(), MyCompare<int>); outputCont("Sort a by max:", a.begin(), a.end()); // The sort function uses a custom sort class sort(a.begin(), a.end(), MyComp<int>(-1)); outputCont("Sort a by min:", a.begin(), a.end()); }
Test results:
3. Simple digital image processing based on custom functions and operation templates
Image processing for this blog depends on the C++opencv open source algorithm package
First, define an operation template function:
// Operations for images (using the custom operation function MyOperator) template <class MyOperator> void transCalc(Mat &src, int w, int h, MyOperator op) { for(int row=0;row<h;row++){ for(int col=0;col<w;col++){ // Image Operation src.at<uchar>(row, col) = op(src.at<uchar>(row, col)); } } }
3.1 Image Gray Transform
// Class operation template, gray logarithmic transformation: // Since binarization requires an incoming threshold in addition to the incoming variable itself, classes are used to define it template<class T> class logTransform { public: int C; double Gamma; // n Default is 128 logTransform(int c=1, double gamma = 1.0):C(c),Gamma(gamma){} // Overload operator'()'to execute customizations once the () incoming parameter is used: int operator()(T val) { float Val = float(val)/255; return 255*C*log(1+Val*(Gamma-1)) / log(Gamma); } };
Test sample:
int main(int argc, char *argv[]) { // Open Grayscale Image Mat img = cv::imread("C:\\Users\\S.E\\Desktop\\c++\\opencv_qt\\rice.png", 0); int w = img.cols; int h = img.rows; imshow("original", img); transCalc(img, w, h ,logTransform<uchar>(1, 0.01)); imshow("gamma=0.01", img); waitKey(0); return 0; }
Test results:
3.2 Image Binarization
// Class operation template, binary: // Since binarization requires an incoming threshold in addition to the incoming variable itself, classes are used to define it template<class T> class MyThreshold { public: int threshold; // n Default is 128 MyThreshold(int n=128):threshold(n){} // Overload operator'()'to execute customizations once the () incoming parameter is used: int operator()(T val) { return (val > threshold)*255; } };
Test sample:
int main(int argc, char *argv[]) { // Open Grayscale Image Mat img = cv::imread("C:\\Users\\S.E\\Desktop\\c++\\opencv_qt\\rice.png", 0); int w = img.cols; int h = img.rows; imshow("original", img); transCalc(img, w, h ,MyThreshold<uchar>(128)); imshow("Threshold=128", img); waitKey(0); return 0; }
Test results:
4. First Identify STL Containers: set Collection
set is a container implemented by the c++stl standard library, which can automatically sort data. Its basic data structure is based on red-black trees, so it is more efficient to insert and delete than regular sequence containers, such as vector s.
Next, we will implement a very simple and super student management "system" based on set for a better understanding.
First, define the basic composition of a student's information and encapsulate it into a class:
// Student Class class studentInfo { public: int _strNo; // School Number string _strName; // Full name // Constructor studentInfo(int strNo, string strName){ _strNo = strNo; _strName =strName; } // Overload << Output friend ostream& operator<<(ostream& os, const studentInfo& info) { os<<endl<<info._strNo<<" "<<info._strName; return os; } // Override comparison operators (compare school numbers only) friend bool operator<(const studentInfo& info1, const studentInfo& info2) { return info1._strNo<info2._strNo; } };
Next, we define a class for managing student information, store each student information in a set, and define some basic methods for adding, deleting, and checking student information:
It is worth noting that an iterator can be automatically declared using auto when traversing a container with a for loop.
template <class T> class students { public: //Store student information set<studentInfo> stuSet; int stuNum = 0; // Constructor template <class t> students(t stud){ for(auto it:stud){ stuSet.insert(it); stuNum ++; } } // Add an element void add_single(T stu){ stuSet.insert(stu); stuNum ++; } // Add elements in bulk template <class t> bool add_batch(t stu){ for(auto it:stu){ stuSet.insert(it); stuNum ++; } return true; } // Delete elements by school number bool del(int No){ for(auto it:stuSet){ if(it._strNo == No){ stuSet.erase(it); stuNum --; return true; } } return true; } // Delete elements by name bool del(string Name){ for(auto it:stuSet){ if(!Name.compare(it._strName)){ stuSet.erase(it); stuNum --; return true; } } return true; } // Find names by number string searchName(int No){ for(auto it:stuSet){ if(it._strNo == No){ return it._strName; } } return "Not Found"; } // Find a school number by name int searchNo(string Name){ for(auto it:stuSet){ if(!Name.compare(it._strName)){ return it._strNo; } } return -1; } // Modify name according to school number void update_no(int No, string afterName){ for(auto it:stuSet){ if(it._strNo==No){ stuSet.erase(it); break; } } stuSet.insert(studentInfo(No, afterName)); } };
It is worth noting that in an implementation where set involves finding and deleting, if we have deleted a piece of data from the set, we should either return or break out of the lookup loop directly. This is because after deleting a piece of data, the tree structure in the set changes because of the tree traversal mechanism inside the set. This prevents erase from traversing back and forth from that starting point, so if the next data happens to be above the parent node of the current data, traversing back and forth will result in a field pointer error. That is:
... ... for(auto it:stuSet){ if(it._strNo==No){ stuSet.erase(it); break; } } ... ...
Test sample:
void testStuSet() { vector<studentInfo> stu1; stu1.push_back(studentInfo(11, "haotianY")); stu1.push_back(studentInfo(13, "jinyuG")); stu1.push_back(studentInfo(47, "jiawenL")); vector<studentInfo> stu2; stu2.push_back(studentInfo(41, "zhaohongH")); stu2.push_back(studentInfo(19, "chenxiS")); stu2.push_back(studentInfo(22, "yihaoW")); stu2.push_back(studentInfo(49, "haohaoW")); students<studentInfo> stuSet(stu1); // increase stuSet.add_batch(stu2); stuSet.add_single(studentInfo(22, "xiangdongX")); // Delete stuSet.del(22); // change stuSet.update_no(47, "xiuwenL"); // Modify name according to school number // check cout<<stuSet.searchName(49)<<endl; // Find names by number cout<<stuSet.searchNo("haohaoW")<<endl; // Find a school number by name outputCont("student Set:\n", stuSet.stuSet.begin(), stuSet.stuSet.end()); }
Test results:
5. First Identify STL Containers: Map (Associated Container)
A map is an associated container that provides one-to-one data processing capabilities (the first is called a key and the second is called a value). The values of different keys can be the same. Because of this feature, it provides a fast path programmatically when we process one-to-one data. Also, like set, map is automatically sorted inside.
Map: Enter a string, use map to count the number of occurrences of each character, and output the characters and their corresponding times.
//Enter a string and use map to count the number of occurrences of each character and output the character and its corresponding number of occurrences void countStr(string str){ map<char, int> count; for(int i = 0;i<str.length();i++){ // Assign 1 if first occurrence if(count.find(str[i])==count.end()){ count[str[i]] = 1; } // Otherwise++. else{count[str[i]]++;} } // Print the number of occurrences of each word for(auto i:count){ cout<<i.first<<": "<<i.second<<" "; } }
Test sample:
int main() { countStr("iuewfhjsdbfkrhedjskjloisgjipjdzzsvdfgkzlkjbhgvdvjj"); return 0; }
Test results:
epilogue
Based on the template templet introduced in the previous experiment and STL Library in C++ standard library, this experiment implements a custom algorithm and functions and performs a simple digital image processing. At the same time, through two examples of student information management and counting the number of occurrences of each letter in the string, the basic usage of set and map is preliminarily understood. So far, c++ has formally opened the door to me, revealing a little insignificant light.
More C++ based applications will be presented as my settings for this semester.