From 373fdba95bf6e37230090ecb768ec4143112824a Mon Sep 17 00:00:00 2001 From: Jidong Xiao Date: Thu, 9 Nov 2023 15:06:33 -0500 Subject: [PATCH] adding lecture 21 --- lectures/21_hash_tables_II/README.md | 164 ++++++++++++++++++ .../p1451_rearrange_words_in_a_sentence.cpp | 46 +++++ 2 files changed, 210 insertions(+) create mode 100644 lectures/21_hash_tables_II/README.md create mode 100644 leetcode/p1451_rearrange_words_in_a_sentence.cpp diff --git a/lectures/21_hash_tables_II/README.md b/lectures/21_hash_tables_II/README.md new file mode 100644 index 0000000..0bdb1be --- /dev/null +++ b/lectures/21_hash_tables_II/README.md @@ -0,0 +1,164 @@ +# Lecture 21 --- Hash Tables, part II + +## Today’s Lecture + +- Function Objects +- Continuing with Hash Tables +- STL Queue and STL Stack + +## 21.1 Function Objects, a.k.a. Functors + +- In addition to the basic mathematical operators + - * / < > , another operator we can overload for our C++ +classes is the function call operator. + Why do we want to do this? This allows instances or objects of our class, to be used like functions. It’s weird +but powerful. +- Here’s the basic syntax. Any specific number of arguments can be used. + +```cpp +class my_class_name { +public: +// ... normal class stuff ... +my_return_type operator() ( /* my list of args */ ); +}; +``` + +## 21.2 Why are Functors Useful? + +- One example is the default 3rd argument for std::sort. We know that by default STL’s sort routines will use +the less than comparison function for the type stored inside the container. How exactly do they do that? +- First let’s define another tiny helper function: + +```cpp +bool float_less(float x, float y) { +return x < y; +} +``` + +- Remember how we can sort the my_data vector defined above using our own homemade comparison function +for sorting: + +```cpp +std::sort(my_data.begin(),my_data.end(),float_less); +``` + +If we don’t specify a 3rd argument: + +```cpp +std::sort(my_data.begin(),my_data.end()); +``` + +This is what STL does by default: + +```cpp +std::sort(my_data.begin(),my_data.end(),std::less()); +``` + +- What is std::less? It’s a templated class. Above we have called the default constructor to make an instance +of that class. Then, that instance/object can be used like it’s a function. Weird! + +- How does it do that? std::less is a teeny tiny class that just contains the overloaded function call operator. + +``` +template +class less { +public: +bool operator() (const T& x, const T& y) const { return x < y; } +}; +``` + +- You can use this instance/object/functor as a function that expects exactly two arguments of type T (in this +example float) that returns a bool. That’s exactly what we need for std::sort! This ultimately does the +same thing as our tiny helper homemade compare function! + +## 21.3 Another more Complicated Functor Example + +Constructors of function objects can be used to specify internal data for the functor that can then be used +during computation of the function call operator! For example: + +```cpp +class between_values { +private: +float low, high; +public: +between_values(float l, float h) : low(l), high(h) {} +bool operator() (float val) { return low <= val && val <= high; } +}; +``` + +- The range between low & high is specified when a functor/an instance of this class is created. We might +have multiple different instances of the between_values functor, each with their own range. Later, when the +functor is used, the query value will be passed in as an argument. The function call operator accepts that +single argument val and compares against the internal data low & high. +- This can be used in combination with STL’s find_if construct. For example: + +```cpp +between_values two_and_four(2,4); +if (std::find_if(my_data.begin(), my_data.end(), two_and_four) != my_data.end()) { + std::cout << "Found a value greater than 2 & less than 4!" << std::endl; +} +``` + Alternatively, we could create the functor without giving it a variable name. And in the use below we also +capture the return value to print out the first item in the vector inside this range. Note that it does not print +all values in the range. + +```cpp +std::vector::iterator itr; +itr = std::find_if(my_data.begin(), my_data.end(), between_values(2,4)); +if (itr != my_data.end()) { + std::cout << "my_data contains " << *itr + << ", a value greater than 2 & less than 4!" << std::endl; +} +``` + +## 21.5 Using STL’s Associative Hash Table (Map) + +- Using the default std::string hash function. + – With no specified initial table size. +```cpp +std::unordered_map m; +``` + – Optionally specifying initial (minimum) table size. +```cpp +std::unordered_map m(1000); +``` +- Using a home-made std::string hash function. Note: We are required to specify the initial table size. + – Manually specifying the hash function type. +```cpp +std::unordered_map > m(1000, MyHashFunction); +``` + – Using the decltype specifier to get the “declared type of an entity”. +```cpp +std::unordered_map m(1000, MyHashFunction); +``` +- Using a home-made std::string hash functor or function object. + – With no specified initial table size. +```cpp +std::unordered_map m; +``` + – Optionally specifying initial (minimum) table size. +```cpp +std::unordered_map m(1000); +``` + +## 21.6 Additional STL Container Classes: Stacks + + + +– Stacks allow access, insertion and deletion from only one end called the top + - There is no access to values in the middle of a stack. + - Stacks may be implemented efficiently in terms of vectors and lists, although vectors are preferable. + - All stack operations are O(1) + +## 21.7 Additional STL Container Classes: Queues + +- Queues allow insertion at one end, called the back and removal from the other end, called the front + - There is no access to values in the middle of a queue. + - Queues may be implemented efficiently in terms of a list. Using vectors for queues is also possible, +but requires more work to get right. + - All queue operations are O(1) + +## 21.8 Leetcode Exercises + +- [Leetcode problem 1451: Rearrange Words in a Sentence](https://leetcode.com/problems/rearrange-words-in-a-sentence/). Solution: [p1451_rearrange_words_in_a_sentence.cpp](../../leetcode/p1451_rearrange_words_in_a_sentence.cpp). diff --git a/leetcode/p1451_rearrange_words_in_a_sentence.cpp b/leetcode/p1451_rearrange_words_in_a_sentence.cpp new file mode 100644 index 0000000..bca8b35 --- /dev/null +++ b/leetcode/p1451_rearrange_words_in_a_sentence.cpp @@ -0,0 +1,46 @@ +// solution to leetcode 1451 + +class Solution { + public: + static bool cmp(std::pair p1, std::pair p2){ + //bool cmp(string p1, string p2){ + int len1 = p1.first.length(); + int len2 = p2.first.length(); + if(len1==len2){ + // keep the original order + return (p1.second> v1; + string word; + int index; + char c; + c=tolower(text[0]); + text[0]=c; + // store the words and its index into v1. + stringstream ss(text); + while(ss >> word){ // if there are n words, O(n) + v1.push_back({word, index}); + index++; + } + std:sort(v1.begin(), v1.end(), cmp); + int size; + size = v1.size(); + for(int i=0;i