diff --git a/.gitignore b/.gitignore index cd6a651..f1876ed 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,186 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Roslyn cache directories +*.ide/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# If using the old MSBuild-Integrated Package Restore, uncomment this: +#!**/packages/repositories.config + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ # Compiled Object files *.slo *.lo diff --git a/ch01/README.md b/ch01/README.md deleted file mode 100644 index 85d8e7f..0000000 --- a/ch01/README.md +++ /dev/null @@ -1,4 +0,0 @@ -1 The Role of Algorithms in Computing ------------------------------------- - -No implementation for this chapter. diff --git a/ch01/ex1 b/ch01/ex1 deleted file mode 100644 index 9688a5b..0000000 --- a/ch01/ex1 +++ /dev/null @@ -1,32 +0,0 @@ -@alan - -1.1-1 -Grading system needs the sorting. - -1.1-2 -Scalability,correctness - -1.1-3 -array,whose size must be fixed when define it, but quite handy to use. - -1.1-4 -Both are looking the best path for the lowest cost. However, the destination and the source are different for the shortest-path probelem, where they are the same in the travelling-salesman problem - -1.1-5 -Scarces resources allocation always looks for the best option. A student grading system can accept sorting algorithms that are not the fastest one. -##################### -1.2-1 -Image processing.It need all kinds of algorithms such as thresholding, learning and so on. - -1.2-2 -Based on the problem, an equation was obtained as: - 8n^2 = 64nlgn -which could be simplified as: - n = 8lgn -where n belongs to the region (2,3). -Hence for value 1,2 insertion sort beat merge sort. - -1.2-3 -An equation was obtained as: - 100n^2 < 2^n -Hence the smallest value is 15. diff --git a/ch02/README.md b/ch02/README.md index 9525254..cdf9fff 100644 --- a/ch02/README.md +++ b/ch02/README.md @@ -1,26 +1,386 @@ -2 Getting Started ------------------------------------ - -- insertion_sort.hpp - - INSERTION-SORT - - ex2.1-2 - - ex2.3-4 -- merge_sort.hpp - - MERGE - - MERGE-SORT -- linear_search.hpp - - ex2.1-3 -- binary_search.hpp - - ex2.3-5 - - ex2.3-7 ★ -- selection_sort.hpp - - ex2.2-2 -- merge_with_insertion_sort.hpp - - problem 2-1 Insertion sort on small arrays in merge sort -- bubble_sort.hpp - - problem 2-2 Correctness of bubblesort -- horner_rule.hpp - - problem 2-3 Correctness of Horner’s rule -- inversions.hpp - - problem 2-4 Inversions +##Ex2.1-1 +```cpp +algorithm begin: + {31,[41],59,26,41,58} (index = 1) -> + {31,41,[59],26,41,58} (index = 2) -> + {[26],31,41,59,41,58} (index = 3) -> + {26,31,41,[41],59,58} (index = 4) -> + {26,31,41,41,[58],59} (index = 5) +end +``` +##Ex2.1-2 + * A functor for comparison can be passed in to specify order direction, such as `std::greater` or `std::less` + * Implementation: `insertion_sort.hpp` + * Test: `test_insertion_sort.cpp` + +##Ex2.1-3 + * Pseudocode: +```cpp +Linear-Search(arr, val) +1 for i = 0 to arr.length - 1 +2 if val == arr[i] +3 return i +4 return Nil +``` + * Loop invariant: +```cpp +At the start of each iteration of the for loop, no item preceeding arr[i] is equal to val. +``` + * Proof: + +```cpp +I: + i = 0 -> + nothing preceeds index 0 -> + trivially, no item preceeding index 0 is equal to val. -> + I holds. + +M: + suppose it holds for i = 0 to k. For i = k + 1, to continue the loop, arr[k + 1] must be unequal to val. -> + after this iteration the loop invariant holds for i = k + 1. -> + M holds. + +T: + the termination conditions are either that i is equal to arr.length or that the item equal to val is found. -> + for the first case, all items preceeding index arr.lengh, aka the entire array at this moment, are unequal to val, so Nil is returned; for the second case, the index that points to the value equal to val will be returned. -> + both case return results as desired. -> + T holds. + +I and M and T -> +this algorithm is correct. +``` + +##Ex2.1-4 + * Problem description: +```cpp +Input: two arrays lhs and rhs which store two n-bit binary numbers respectively +Output: one array that stores an n+1-bit binary number, such that it is equal to the sum of lhs and rhs +``` + * Pseudocode: +```cpp +Add-Binary-Numbers(lhs, rhs) +1 def sum as an array with sum.length = lhs.lengh + 1 +2 def carry = 0 +3 for i = lhs.lengh - 1 to 0 +4 sum[i + 1] = (carry + lhs[i] + rhs[i]) % 2 +5 carry = (carry + lhs[i] + rhs[i]) / 2 +6 sum[0] = carry +7 return sum +``` +* Implementation : `add_binary_numbers.hpp` +* Test : `test_add_binary_numbers.cpp` + +##Ex2.2-1 +```cpp +\theta(n^3) +``` + +##Ex2.2-2 + * Pseudocode: +```cpp +Selection-Sort(arr) +1 for i = 0 to arr.length - 2 <- c1 x (n - 1) +2 def index_for_min = arr[i] <- c2 x (n - 2) +3 for j = i to arr.length - 1 <- c3 x (n - 2) x n / 2 +4 if arr[min] > arr[j] <- c4 x (n - 2) x (n / 2 - 1) +5 index_for_min = j <- time belongs to range [0, c5 x (n - 2) x (n / 2 - 1)] +6 swap arr[i] and arr[min] <- c6 x (n - 2) x (n / 2 - 1) +7 return arr <- c7 +``` + + * Loop invariant: +```cpp +At the start of each iteration of the for loop, +all items in range [0, i) are less than any item in range [i, length - 1); +Also items in range [0, i) have been sorted. +``` + * With n = arr.length, when i == n - 1 , only one item left in range[n - 1, n). If this algorithm runs n times, what it does in the last run will always be swap (arr[arr.length - 1], arr[arr.length - 1]). Hence, n - 1 times is enogh. + * Time complexity: +```cpp +For best case, time complexity for line 5 equals to 0. Total time required : \theta(n^2) +For worst case, time complexity for line 5 equals to c5 x (n - 2) x (n / 2 - 1). Total time required : \theta(n^2) +``` + * Implementaion: `selection_sort.hpp` + * Test: `test_selection_sort.cpp` + +##Ex2.2-3 + * n/2 elements need to be checked on average. + * For worst case, n elements need to be checked. + * For average-case, `theta(n/2) -> theta(n)` + * For worst case, `theta(n)` + +##Ex2.2-4 +Not sure about this question.Perhaps a precheck can be carried out to see if the input is desired already. + +##Ex2.3-1 +```cpp + {3, 9, 26, 38, 41, 49, 52, 57} + {3, 26, 41, 52} {9, 38, 49, 57} +{3, 41} {26, 52} {38, 57} {9, 49} +{3} {41} {52} {26} {38} {57} {9} {49} +``` + +##Ex2.3-2 + * Implementation: `merge_sort.hpp` + * Test: `test_merge_sort.cpp` + +##Ex2.3-3 +```cpp +basis: + n = 1 + -> LHS = 2 and RHS = 2 x lg(2) = 2 x 1 = 2 + -> LHS == RHS + +induction: + suppose: the equaltion is correct for n = 2^k, where k > 1. + -> T(2^k) = 2^k x lg(2^k) + = (2^k) x k -- eq2 + + for n = k + 1: + LHS = 2T(2^(k+1)/2) + 2^(k+1) + = 2T(2^k) + 2^(k+1) + using eq2: + = 2k(2^k) + 2^(k+1) + = k(2^(k+1)) + 2^(k+1) + = (2^(k+1)) x (k+1) + + RHS = (2^(k+1)) x lg(2^(k+1)) + = (2^(k+1)) x (k+1) + + LHS = RHS + -> This equation is correct. +``` + +##Ex2.3-4 + * Pseudocode: +```cpp +Insertion-Sort-by-Recursion(arr) + if arr.length < 2 //theta(1) + return arr //theta(1) + else //theta(1) + arr = Insertion-Sort-by-Recursion(arr[:-1]) + arr[-1] //T(n - 1) + theta(1) + def key = arr[-1] //theta(1) + def curr = arr.length - 1 //theta(1) + for (curr = arr.length - 1 to 1) and (arr[curr] > key) //O(n - 1) + arr[curr + 1] = arr[curr] //O(n - 2) + arr[curr + 1] = key //theta(1) + return arr //theta(1) +``` + * Recurrence: +```cpp +T(n) = theta(1) , if n = 1 + = T(n - 1) + O(n) , if n > 1 +``` + +##Ex2.3-5 + * Pseudocode: +```cpp +Binary-Search-by-Recursion(arr, val) + low = 0 + high = arr.length - 1 + while low <= high //T(n/2) + mid = (low + high)/2 + if arr[mid] > val + high = mid - 1 + else if arr[mid] < val + low = mid + 1 + else + return mid + return Nil +``` + * Proof for time complexity +```cpp +From the pseudocode +-> T(n) = T(n/2) + theta(1) +-> T(n) = theta(lg(n)) +``` + +##Ex2.3-6 + * No. lines 5 - 7 from Insertion-Sort are doing two things: Firstly, it finds the correct position to insert; Secondly, it pushes elements with greater value backwards. For an arrry, binary search can't improve the pushing part, For a linked list, binary seach can't handle the first task. + +##Ex2.3-7 +* Pseudocode +```python +#Combine sorting and binary search together. +Are-There-Two-Elements-That-Have-Sum-As-Specified(set, sum) + set.sort() #O(n lg n) + for curr = 0 to set.length - 1 #O(n) + if Nil != binary_search(arr = set[curr:], val = sum - set[curr]) #O(n lg n) + return true + return false +``` + +##Problem 2-1 Merge-Sort + Insertion-Sort + * a. Time complexity for sorting n/k sublists with insertion sort: +```cpp + (n/k) x theta(k^2) = theta(nk) +``` + * b. Time complexity for merging all sublists + +```cpp +As shown in Figure 2.5: + it takes theta(n) to merge each level in recursion tree. + total height of the recursion is theta(lg(n)) + merging start from the first level to lg(k): + theta(n(lg(n) - lg(k))) = theta(n(lg(n/k))) +Hence, it takes T(n) = theta(n(lg(n/k))) to merge the sublists. +``` + * c. k = lg(n) is the largest value that meets requirement. +```cpp + +T(n) = theta(n + n x lg(n)) , if k = 1 + This is exact merge sort with no optimization. + +T(n) = theta(n x lg(n) + n x lg(n / lg(n))), if k = lg(n) + Since n is supposed to be greater than 2, the first term n x lg(n) is the significant part. + Anything greater than lg(n) will make the first term greater than theta(n x lg(n)) and the second term is always postive. + Hence the largest value is k = lg(n) +``` + * d. The desired value can be found by testing values from range [1, lg(n)]. + +##Problem 2-2 Bubble-Sort + * a. One more thing need to prove is that no item in A has been deleted nor item added into A'.In another word, A' must be a permutation of A. + * b. Loop invariant and its proof for lines 2-4 +```cpp +Loop invariant: + Prior to each iteration of the for loop, A[j] = min(s) , where set s = { x | x <- A[j, A.length] } . + +Proof +I: + Prior to the first iteration + -> j = A.length, s = { x | x <- A[A.length, A.length] } + -> A[A.length] is the only element in s + -> I holds. + +M: + Let loop invariant holds before j = k + -> A[k] = min(s), where s = { x | x <- A[k, A.length] } -- equation 1 + + The semantics of lines 3 and 4 + -> swap A[k] and A[k-1], if A[k] < A[k - 1] + -> decrement k to k - 1 + + Applying equation 1 + -> j becomes k - 1 + -> A[k - 1] = min(s), where s = { x | x <- A[k - 1, A.length] } + -> loop invariant holds before next iteration + -> M holds. + +T: + Termination condition is j = i + -> A[i] = min(s), where s = { x | x <- A[i, A.length] } + -> this property is useful and exactly expected + -> T holds. + +I and M and T -> loop invariant holds +``` + + * c. Loop invariant and its proof for lines 1-4 +```cpp +Loop invariant: + Prior to each iteration of the for loop, + all elements in subarray [ : i - 1] are smaller than anything in subarray [i : ], + and are sorted. + +Proof +I: + Prior to the first iteration, [ : i - 1] is empty + -> I holds. + +M: + Suppose LI holds before i = i + -> all elements in subarray A[ : i - 1] are smaller than anything in subarray A[i : ], and are sorted. + + Applying the property T from part b and above + -> A[i] = max( left_set ), A[i] = min( right_set ) + where left_set = { x | x <- A[ : i ]} + right_set = { x | x <- A[ i : ]} + + increment i to i + 1 + -> LI holds before next iteration + +T: + i = A.length is the termination condition + -> subarray A[ : A.length - 1] has been sorted and A[A.length], the only element in subarray A[A.length, A.length], is greater than or equal to the largest element in A[ : A.length - 1] + -> A is sorted. + +I.M.T -> LI holds. +``` + + * d. time complexity = theta(n^2). Insertion-Sort is better. Because for average case and best case Insertion-Sort doesn't have to carry out theta(n) for its nested loop. whereas Bubble-Sort has to do so for any case. + +##Problem 2-3 Horner’s rule + * code : `polynomial.hpp`, `test_polynomial.hpp` + * Time complexity : theta(n) + * pseudocode +```python +Naive-Polynomial-Evaluation(arr, x) + y = 0 + for i = 0 to arr.length - 1 + X = 1 + for k = i downto 1 + X *= x + y += X * arr[i] + return y +``` + + * LI and proof +```cpp +(To avoid Greek letter Sigma, here is using sum(head, tail)() function instead) +L.I.: + At the start of each iteration of the for loop of lines 2–3, + y = sum(k = 0, k = n - (i + 1)) (a(k + i + 1) * x ^ k) + +I.: + Prior to the first iteration, + y = sum(k = 0, k = -1) (a(k + i + 1) * x ^ k) + upper limit is lower than lower limit, this equation is meaningless, y = 0 + Hence, I holds. + +M.: + Suppose L.I. holds before i = i + y = sum(k = 0, k = n - (i + 1)) (a(k + i + 1) * x ^ k) + + by line 2 - 3, LHS becomes: + y = a(i) + x * y + = a(i) + x * ( a(i + 1) + a(i + 2) * x + ... + a(n) * x^(n - i - 1) + = a(i) + a(i + 1) * x + a(i + 2) * x^2 + ... + a(n) * x^(n - i) + + when i = i - 1 RHS becomes + sum(k = 0, k = n - i) (a(k + i) * x ^ k) + = a(i) + a(i + 1) * x + a(i + 2) * x^2 + ... + a(n) * x^(n - i) + + LHS = RHS, hence M holds for next iteration. + +T.: + The termination condition is i = -1 + y = sum(k = 0, k = n - (-1 + 1)) (a(k - 1 + 1) * x ^ k) + = sum(k = 0, k = n) (a(k) * x ^ k) + Hence, T holds. + +L.I. holds. +``` + + * As shown above, this code fragment correctly evaluates a polynomial. + +##Problem 2-4 Inversions + * Five inversions: +```cpp +{2,1}, {3,1}, {8,1}, {6,1}, {8,6} +``` + * set {n, n-1, n-2, ...,2, 1}, i.e. numbers in descending order has most inversions. +``` +number of inversions = n(n - 1)/2 +``` + * As shown below, the expression `A[i] > key` in line 5 Insertion-Sort is in essence checking for an inversion. So a function can be made to describe the relationship between the running time and number of inversions: +```cpp +T(n) = theta(number_of_inversions + n) +``` + * Algorithm to find inversions in theta(n(lg(n))): +```cpp +Modify Merge-Sort as following: +1 Pass count as a reference or a pointer into procedure Merge and Merge-Sort +2 add statement : count += n1 - i into Merge between line 16 and line 17 +``` + * code : `find_inversions.hpp` and `test_find_inversions.cpp`. diff --git a/ch02/alan.hpp b/ch02/alan.hpp deleted file mode 100644 index bd14f8b..0000000 --- a/ch02/alan.hpp +++ /dev/null @@ -1,74 +0,0 @@ -/*************************************************************************** - * @file alan.hpp - * @author alan.w - * @date 13 August 2014 - * @remark CLRS Algorithms implementation in C++ templates. - * Custom utilites - ***************************************************************************/ - -#ifndef ALAN_HPP -#define ALAN_HPP - -#include -#include - -namespace alan { - -/** - * @brief print_container - * @param rng - */ -template -inline void -print_container(const Range& rng) -{ - for(const auto& elem : rng) - std::cout << elem << " "; -} - -/** - * @brief green - */ -std::string green(const std::string& str) -{ - return "\033[1;32m" + str + "\033[0m"; -} - -/** - * @brief red - */ -std::string red(const std::string& str) -{ - return "\033[1;31m" + str + "\033[0m"; -} - -/** - * @brief yellow - */ -std::string yellow(const std::string& str) -{ - return "\033[1;33m" + str + "\033[0m"; -} - -/** - * @brief prompt - * @param description - */ -void prompt(std::string&& description = "the output is") -{ - std::cout << std::move(green(description + "\n")); -} - -/** - * @brief end - * @param description string - */ -void end(std::string&& description = "exit normally") -{ - std::cout << std::move(green("\n" + description + "\n")); -} - - -}//namespaces - -#endif // ALAN_HPP diff --git a/ch02/binary_search.hpp b/ch02/binary_search.hpp deleted file mode 100644 index 5a4e87f..0000000 --- a/ch02/binary_search.hpp +++ /dev/null @@ -1,138 +0,0 @@ -/*************************************************************************** - * @file binary_search.hpp - * @author Alan.W - * @date 24 Aug 2014 - * @version 2 - * @remark CLRS Algorithms implementation in C++ templates. - ***************************************************************************/ -//! -//! ex2.3-5 -//! Referring back to the searching problem (see Exercise 2.1-3), observe that if the -//! sequence A is sorted, we can check the midpoint of the sequence against and -//! eliminate half of the sequence from further consideration. The binary search al- -//! gorithm repeats this procedure, halving the size of the remaining portion of the -//! sequence each time. Write pseudocode, either iterative or recursive, for binary -//! search. Argue that the worst-case running time of binary search is O(lg n). -//! -//! ex2.3-7 ★ -//! Given a set S of n intergers and another integer x. -//! Describe a O(nlog2(n))- time algorithm to determine whether or not there exist -//! two elements in S whose sum is exactly x. -//! -// step 1: merge sort -- O(n lg n) -// step 2: iterate the sorted sequence -- O(n) -// step 2.1 binary_search(sum - *iter) -- O(lg n) -// running time = O(n lg n) + O(n) * O(lg n) = 2 * O(n lg n) = O(n lg n) -// check is_sum below for implementation. -//! - -#ifndef BINARY_SEARCH_HPP -#define BINARY_SEARCH_HPP - -#include -#include "iterator.hpp" -#include "merge_sort.hpp" - -namespace clrs{namespace ch2{ - -/** - * @brief binary_search - * @param first - * @param last - * @param val - * @return the iterator pointing to the element looked for - * or last iterator when nothing found - * @ex2.3-5 - * @complx O(lg n) - */ -template -Iter binary_search(Iter first, Iter last, const IterValue& val) -{ - //! define a lambda for real work - Iter nil; - using Lambda = std::function; - Lambda recur = [&](Iter first, Iter last) - { - auto mid = first + (last - first)/2; - - if(*mid == val) return mid; - else if(mid == first) return nil; - else if(*mid > val) return recur(first,mid); - else return recur(mid,last); - }; - - //! call the lamda and return result - auto ret = recur(first, last); - return ret == nil? last : ret; -} - -/** - * @brief is_sum - * @param first - * @param last - * @param sum - * - * @ex2.3-7 ★ - * @complx O(n lg n) - */ -template -bool is_sum(Iter first, Iter last, const IterValue& sum) -{ - //! sort -- O(n lg n) - clrs::ch2::merge_sort(first, last); - - //! iteration and binary search -- O(n lg n) - auto ret = last; - for(auto it = first; it != last && ret == last; ++it) - ret = binary_search(first, last, sum - *it); - - return ret != last; -} - -}}//namespace -#endif // BINARY_SEARCH_HPP - - -//! @test binary_search -//! -//#include -//#include -//#include "alan.hpp" -//#include "binary_search.hpp" -//int main() -//{ -// std::vector v{1,2,3,4,5,6,32,99}; - -// auto ret = clrs::ch2::binary_search(v.begin(),v.end(),32); -// std::cout << *ret; - -// alan::end(); -// return 0; -//} - -//! @output -//! -//32 -//exit normally - - -//! @test is_sum for ex2.3-7 ★ -//! -//#include -//#include -//#include "alan.hpp" -//#include "binary_search.hpp" -//int main() -//{ -// std::vector v{1,2,3,4,5,6,32,99}; - -// auto ret = clrs::ch2::is_sum(v.begin(), v.end(), 100); -// std::cout << ret; - -// alan::end(); -// return 0; -//} -//! @output -//! -//1 -//exit normally diff --git a/ch02/bubble_sort.hpp b/ch02/bubble_sort.hpp deleted file mode 100644 index d615abb..0000000 --- a/ch02/bubble_sort.hpp +++ /dev/null @@ -1,61 +0,0 @@ -/*************************************************************************** - * @file bubble_sort.hpp - * @author Alan.W - * @date 27 Aug 2014 - * @version 2 - * @remark CLRS Algorithms implementation in C++ templates. - ***************************************************************************/ -//! -//! @problem 2-2 Correctness of bubblesort -//! - - -#ifndef BUBBLE_SORT_HPP -#define BUBBLE_SORT_HPP - -#include "assert.h" -#include - -namespace clrs { namespace ch2 { - -/** - * @brief bubble_sort - * @param first - * @param last - * - * @ex problem 2-2 Correctness of bubblesort - * @complx O(n^2) - */ -template -void bubble_sort(Iter first, Iter last) -{ - assert(last > first); - - for(auto ex = first; ex != last - 1; ++ex) - for(auto in = last - 1; in != ex; --in) - if(*in < *(in - 1)) std::swap(*in, *(in - 1)); -} - -}}//namespace -#endif // BUBBLE_SORT_HPP - -//! @test bubble_sort -//! for problem 2-2 -//#include -//#include -//#include "alan.hpp" -//#include "bubble_sort.hpp" - -//int main() -//{ -// std::vector v{1,6,88,2,0,77}; -// clrs::ch2::bubble_sort(v.begin(), v.end()); -// alan::print_container(v); - -// alan::end(); -// return 0; -//} -//! @output -//! -//0 1 2 6 77 88 -//exit normally diff --git a/ch02/ch02.pro b/ch02/ch02.pro deleted file mode 100644 index 7a19109..0000000 --- a/ch02/ch02.pro +++ /dev/null @@ -1,21 +0,0 @@ -TEMPLATE = app -CONFIG += console -CONFIG -= app_bundle -CONFIG -= qt -CONFIG += c++11 - -SOURCES += \ - main.cpp - -HEADERS += \ - insertion_sort.hpp \ - alan.hpp \ - iterator.hpp \ - linear_search.hpp \ - merge_sort.hpp \ - binary_search.hpp \ - selection_sort.hpp \ - merge_with_insertion_sort.hpp \ - bubble_sort.hpp \ - horner_rule.hpp \ - inversions.hpp diff --git a/ch02/ch02.sln b/ch02/ch02.sln new file mode 100644 index 0000000..003b062 --- /dev/null +++ b/ch02/ch02.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.31101.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "src", "src\src.vcxproj", "{BA9819D5-BA49-490C-AACD-11BC927CBA56}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test\test.vcxproj", "{3C8BB254-56A9-4953-A3FB-27D273CC1E07}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BA9819D5-BA49-490C-AACD-11BC927CBA56}.Debug|Win32.ActiveCfg = Debug|Win32 + {BA9819D5-BA49-490C-AACD-11BC927CBA56}.Debug|Win32.Build.0 = Debug|Win32 + {BA9819D5-BA49-490C-AACD-11BC927CBA56}.Release|Win32.ActiveCfg = Release|Win32 + {BA9819D5-BA49-490C-AACD-11BC927CBA56}.Release|Win32.Build.0 = Release|Win32 + {3C8BB254-56A9-4953-A3FB-27D273CC1E07}.Debug|Win32.ActiveCfg = Debug|Win32 + {3C8BB254-56A9-4953-A3FB-27D273CC1E07}.Debug|Win32.Build.0 = Debug|Win32 + {3C8BB254-56A9-4953-A3FB-27D273CC1E07}.Release|Win32.ActiveCfg = Release|Win32 + {3C8BB254-56A9-4953-A3FB-27D273CC1E07}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/ch02/horner_rule.hpp b/ch02/horner_rule.hpp deleted file mode 100644 index e626077..0000000 --- a/ch02/horner_rule.hpp +++ /dev/null @@ -1,104 +0,0 @@ -/*************************************************************************** - * @file horner_rule.hpp - * @author Alan.W - * @date 27 Aug 2014 - * @version 2 - * @remark CLRS Algorithms implementation in C++ templates. - ***************************************************************************/ -//! -//! @problem 2-3 Correctness of Horner’s rule -//! - -#ifndef HORNER_RULE_HPP -#define HORNER_RULE_HPP - -#include "iterator.hpp" - -namespace clrs {namespace ch2 { - -/** - * @brief horner_rule - * @param first - * @param last - * @param x - * - * @ex problem 2-3 - * @complx O(n) - */ -template -inline clrs::IterValue -horner_rule(Iter first, Iter last, const clrs::IterValue& x) -{ - clrs::IterValue ret = 0; - for(auto it = last - 1; it != first - 1; --it) - ret = *it + x * ret; - - return ret; -} - -/** - * @brief power - * @param order - * @param x - * - * @ex problem 2-3 part c - * @complx O(n) - */ -template -inline ValueType -power(int order, const ValueType& x) -{ - return order > 0? x * power(order - 1, x) : 1; -} - -/** - * @brief naive polynomial evaluate - * @param first - * @param last - * @param x - * - * @complx O(n^2) - */ -template -clrs::IterValue -polynomial_evaluate(Iter first, Iter last, const clrs::IterValue& x) -{ - IterValue ret = 0; - int order = 0; - for(auto it = first; it != last; ++it) - ret += *it * power(order++, x); - - return ret; -} - -}}//namespace - -#endif // HORNER_RULE_HPP - -//! @test horner_rule for problem 2-3 -//! -//#include -//#include -//#include "alan.hpp" -//#include "horner_rule.hpp" - -//int main() -//{ -// std::vector v{1,6,88,2,3,77}; - -// auto by_horner = clrs::ch2::horner_rule(v.begin(), v.end(),3); -// auto by_naive = clrs::ch2::polynomial_evaluate(v.begin(), v.end(), 3); -// std::cout << "by horner : " << by_horner << std::endl; -// std::cout << "by naive : " << by_naive << std::endl; - -// alan::end(); -// return 0; -//} - -//! @output -//! -//by horner : 19819 -//by naive : 19819 - -//exit normally - diff --git a/ch02/insertion_sort.hpp b/ch02/insertion_sort.hpp deleted file mode 100644 index 80e7ee8..0000000 --- a/ch02/insertion_sort.hpp +++ /dev/null @@ -1,145 +0,0 @@ -/*************************************************************************** - * @file insertion_sort.hpp - * @author Alan.W - * @date 22 Aug 2014 - * @version 2 - * @remark CLRS Algorithms implementation in C++ templates. - ***************************************************************************/ -//! -//! ex2.1-2 -//! Rewrite the INSERTION-SORT procedure to sort into nonincreasing instead of non- -//! decreasing order. -//! -//! -//! ex2.3-4 -//! We can express insertion sort as a recursive procedure as follows. In order to sort -//! A[1..n], we recursively sort A[1..n-1] and then insert A[n] into the sorted array -//! A[1..n-1]. Write a recurrence for the running time of this recursive version of -//! insertion sort. -//! - -#ifndef INSERTION_SORT_HPP -#define INSERTION_SORT_HPP - -#include -#include -#include - -namespace clrs { namespace ch2 { - -/** - * @brief insertion_sort - * @param first - * @param last - * - * @typename Iter iterator - * @typename Comp callable - * - * @pseudocode INSERTION-SORT, Page 18, CLRS - * @exercise ex2.1-2, Page 22, CLRS - * @complx O(n^2) - */ -template > > -void insertion_sort(Iter first, Iter last, Comp compare = Comp()) -{ - //! trivial case - if(last - first < 2) return; - - //! when more than two elements - for(auto curr = first + 1; curr != last; ++curr) - { - auto key = *curr; - - //! insert into the sorted sequence - auto prev = curr - 1; - while(prev != first - 1 && compare(*prev, key)) - { - *(prev + 1) = *prev; - --prev; - } - *(prev + 1) = key; - } -} - -/** - * @brief insertion_sort_recur - * @param first - * @param last - * - * @typename Iter iterator - * @typename Comp callable - * - * @exercise ex2.3-4, Page 39, CLRS - * @complx O(n^2) - */ -template > > -void insertion_sort_recur(Iter first, Iter last, Comp compare = Comp()) -{ - if(last - first > 1) - { - auto curr = last - 1; - insertion_sort_recur(first, curr); //recur - - //! find the right place - auto prev = curr - 1; - auto key = *curr; - while(prev != first - 1 && compare(*prev, key)) - { - *(prev + 1) = *prev; - --prev; - } - //! insert - *(prev + 1) = key; - } -} - -}}//namespace -#endif // INSERTION_SORT_HPP - - -//! @test insertion_sort -//! insertion_sort with predicate, for ex2.1-2 -//! -//! @output -//! -//! the sorted sequence: -//! 0 1 2 3 6 99 -//! exit normally -//! -//#include -//#include -//#include "insertion_sort.hpp" -//#include "alan.hpp" - -//int main() -//{ -// std::vector v = {3,2,1,6,99,0}; -// clrs::ch2::insertion_sort(v.begin(), v.end(), std::greater()); - -// alan::prompt("the sorted sequence:"); -// alan::print_container(v); -// alan::end(); -// return 0; -//} - -//! @test insertion_sort_recur for ex2.3-4 -//! -//! @output -//! 0 33 a22 s11 -//! exit normally -//#include -//#include -//#include "alan.hpp" -//#include "insertion_sort.hpp" - -//int main() -//{ -// std::vector v{"a22","s11","33","0"}; - -// clrs::ch2::insertion_sort_recur(v.begin(), v.end()); -// alan::print_container(v); - -// alan::end(); -// return 0; -//} - diff --git a/ch02/inversions.hpp b/ch02/inversions.hpp deleted file mode 100644 index ed17cb5..0000000 --- a/ch02/inversions.hpp +++ /dev/null @@ -1,111 +0,0 @@ -/*************************************************************************** - * @file merge_with_insertion_sort.hpp - * @author Alan.W - * @date 28 Aug 2014 - * @version 2 - * @remark CLRS Algorithms implementation in C++ templates. - ***************************************************************************/ -//! -//! @problem 2-4 Inversions -//! - -#ifndef INVERSIONS_HPP -#define INVERSIONS_HPP - -#include "iterator.hpp" - -namespace clrs { namespace ch2 { - -/** - * @brief count_n_merge - * @param first - * @param mid - * @param last - * - * the merge part - */ -template -std::size_t count_n_merge(Iter first, Iter mid, Iter last) -{ - using Vector = std::vector>; - Vector left{first, mid}; - Vector right{mid, last}; - - auto l = left.begin(); - auto r = right.begin(); - auto it = first; - std::size_t count = 0; - while(l != left.end() && r != right.end() && it != last) - { - if(*r < *l) - { - *it++ = *r++; - count += left.end() - l; - //! @note ^^^^^^^^^^^^^^ - //! since left and right are sorted, left.end() - l are inversions - } - else - *it++ = *l++; - } - - //! when left exausted - if(l == left.end()) - while(it != last) - *it++ = *r++; - - //! when right exausted - if(r == right.end()) - while(it != last) - *it++ = *l++; - - return count; -} - -/** - * @brief return the number of inversions - * @param first - * @param last - * - * @complx O(n lg n) - * - * for problem 2-4 - */ -template -std::size_t inversions_count(Iter first, Iter last) -{ - std::size_t count = 0; - if(first + 1 < last) - { - auto mid = first + (last - first)/2; - count += inversions_count(first, mid ); - count += inversions_count(mid , last); - - count += count_n_merge(first, mid, last); - } - return count; -} - -}}//namespace -#endif // INVERSIONS_HPP - -//! @test inversions for problem 2-4 -//! -//#include -//#include -//#include "alan.hpp" -//#include "inversions.hpp" - -//int main() -//{ -// std::vector v{2,3,8,6,1}; -// auto count = clrs::ch2::inversions_count(v.begin(), v.end()); -// std::cout << count; - -// alan::end(); -// return 0; -//} - -//! @output -//! -//5 -//exit normally diff --git a/ch02/iterator.hpp b/ch02/iterator.hpp deleted file mode 100644 index bef07a3..0000000 --- a/ch02/iterator.hpp +++ /dev/null @@ -1,24 +0,0 @@ -/*************************************************************************** - * @file iterator.hpp - * @author Alan.W - * @date 22 Aug 2014 - * @version 2 - * @remark CLRS Algorithms implementation in C++ templates. - ***************************************************************************/ - -#ifndef ITERATOR_HPP -#define ITERATOR_HPP - -#include - -namespace clrs { - -/** - * @brief aliasing for value type an iterator points to - */ -template -using IterValue = typename std::iterator_traits::value_type; - -} - -#endif // ITERATOR_HPP diff --git a/ch02/linear_search.hpp b/ch02/linear_search.hpp deleted file mode 100644 index 895084f..0000000 --- a/ch02/linear_search.hpp +++ /dev/null @@ -1,61 +0,0 @@ -/*************************************************************************** - * @file insertion_sort.hpp - * @author Alan.W - * @date 22 Aug 2014 - * @version 2 - * @remark CLRS Algorithms implementation in C++ templates. - ***************************************************************************/ -//! -//! ex2.1-3 -//! Write pseudocode for linear search, which scans through the sequence, looking -//! for . Using a loop invariant, prove that your algorithm is correct. Make sure that -//! your loop invariant fulfills the three necessary properties. -//! - -#ifndef LINEAR_SEARCH_HPP -#define LINEAR_SEARCH_HPP - -#include - -namespace clrs { namespace ch2 { - -/** - * @brief linear_search - * @param first - * @param last - * @param val - * - * @complexity O(n) - * for ex2.1-3 - */ -template -Iter linear_search(Iter first, Iter last, const IterValue& val) -{ - for(auto curr = first; curr != last; ++curr) - if(*curr == val) - return curr; - - return last; -} - -}}//namespace -#endif // LINEAR_SEARCH_HPP - -//! @test -//! -//#include -//#include -//#include "alan.hpp" -//#include "linear_search.hpp" -//int main() -//{ -// std::vector v = {3,2,1,6,99,0}; -// std::cout << *clrs::ch2::linear_search(v.begin(),v.end(),99); - -// alan::end(); -// return 0; -//} -//! @output: -//! -//99 -//exit normally diff --git a/ch02/main.cpp b/ch02/main.cpp deleted file mode 100644 index 58c685e..0000000 --- a/ch02/main.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include -#include -#include "alan.hpp" -#include "merge_sort.hpp" - -int main() -{ - std::vector v{3,2,1}; - - clrs::ch2::merge_sort(v.begin(), v.end()); - alan::print_container(v); - - alan::end(); - return 0; -} diff --git a/ch02/merge_sort.hpp b/ch02/merge_sort.hpp deleted file mode 100644 index 1274b70..0000000 --- a/ch02/merge_sort.hpp +++ /dev/null @@ -1,90 +0,0 @@ -/*************************************************************************** - * @file merge_sort.hpp - * @author Yue.Wang - * @date 23 Aug 2014 - * @update 02 Dec 2014 - * @version 3 - * @remark CLRS Algorithms implementation in C++ templates. - ***************************************************************************/ -#ifndef MERGE_SORT_HPP -#define MERGE_SORT_HPP - -#include -#include "iterator.hpp" -#include - - -namespace clrs {namespace ch2 { - - -/** - * @brief merge - * @param first - * @param mid - * @param last - * - * @pseudocode MERGE, page 31, clrs. - * @complx O(n) - */ -template -void merge(Iter first, Iter mid, Iter last ) -{ - using Vector = std::vector>; - Vector left(first, mid), right(mid, last); - auto l = left.cbegin(), r = right.cbegin(); - auto it = first; - - //! compare and copy, until either one exausted - for(; l != left.end() and r != right.end(); *it++ = *(*r < *l ? r : l)++); - - //! copy the rest. - for(auto rest = (l == left.end() ? r : l); it != last; *it++ = *rest++); -} - - -/** - * @brief merge_sort - * @param first - * @param last - * - * @pseudocode MERGE-SORT, page 34, clrs. - * @complx O(n lg n) - */ -template -void merge_sort(Iter first, Iter last) -{ - if(first+1 < last){ - auto mid = first + (last-first)/2; - merge_sort(first, mid ); - merge_sort(mid , last); - merge(first, mid, last); - } -} - - -}}//namespace -#endif // MERGE_SORT_HPP - - -//! @test merge sort -//! -//#include -//#include -//#include "alan.hpp" -//#include "merge_sort.hpp" - -//int main() -//{ -// std::vector v{"99","22","z55","s11","b33"}; - -// clrs::ch2::merge_sort(v.begin(), v.end()); -// alan::print_container(v); - -// alan::end(); -// return 0; -//} - -//! @output -//! -//22 99 b33 s11 z55 -//exit normally diff --git a/ch02/merge_with_insertion_sort.hpp b/ch02/merge_with_insertion_sort.hpp deleted file mode 100644 index 3cfc596..0000000 --- a/ch02/merge_with_insertion_sort.hpp +++ /dev/null @@ -1,63 +0,0 @@ -/*************************************************************************** - * @file merge_with_insertion_sort.hpp - * @author Alan.W - * @date 27 Aug 2014 - * @version 2 - * @remark CLRS Algorithms implementation in C++ templates. - ***************************************************************************/ -//! -//! @problem 2-1 Insertion sort on small arrays in merge sort -//! -#ifndef MERGE_WITH_INSERTION_SORT_HPP -#define MERGE_WITH_INSERTION_SORT_HPP - -#include "insertion_sort.hpp" -#include "merge_sort.hpp" - -namespace clrs {namespace ch2 { - -/** - * @brief merge_with_insertion_sort - * @param first - * @param last - * @param thresh i.e. k - * - * @problem 2-1 - * @complx theta(n*k + n lg(n/k)) - */ -template -inline void -merge_with_insertion_sort(Iter first, Iter last, SizeType thresh) -{ - assert(last - first >= thresh); - - if(last - first > thresh) - clrs::ch2::merge_sort(first, last); - else - clrs::ch2::insertion_sort(first, last); -} - -}}//namespace -#endif // MERGE_WITH_INSERTION_SORT_HPP - -//! @test merge_with_insertion_sort -//! problem 2-1 -//! -//#include -//#include -//#include "alan.hpp" -//#include "merge_with_insertion_sort.hpp" - -//int main() -//{ -// std::vector v{1,6,88,2,0,77}; -// clrs::ch2::merge_with_insertion_sort(v.begin(), v.end(), 2); -// alan::print_container(v); - -// alan::end(); -// return 0; -//} -//! @output -//! -//0 1 2 6 77 88 -//exit normally diff --git a/ch02/selection_sort.hpp b/ch02/selection_sort.hpp deleted file mode 100644 index 954bb0d..0000000 --- a/ch02/selection_sort.hpp +++ /dev/null @@ -1,68 +0,0 @@ -/*************************************************************************** - * @file selection_sort.hpp - * @author Alan.W - * @date 24 Aug 2014 - * @version 2 - * @remark CLRS Algorithms implementation in C++ templates. - ***************************************************************************/ - -//! -//! ex2.2-2 Selection-Sort -//! - -#ifndef SELECTION_SORT_HPP -#define SELECTION_SORT_HPP - -#include - -namespace clrs {namespace ch2 { - -/** - * @brief selection_sort - * @param first - * @param last - * - * @ex2.2-2 - * @complx O(n^2) - */ -template -void selection_sort(Iter first, Iter last) -{ - //! define a lambda to find the minimum element - using Lamda = std::function; - Lamda min = [](Iter first, Iter last)->Iter - { - auto ret = first; - for(auto it = first; it != last; ++it) - if(*ret > *it) ret = it; - return ret; - }; - - //! sort with lambda min() - for(auto it = first; it != last - 1; ++it) - std::swap(*it, *min(it, last)); -} - -}}//namespace -#endif // SELECTION_SORT_HPP - -//! @test selection_sort for ex2.2-2 -//! -//#include -//#include -//#include "alan.hpp" -//#include "selection_sort.hpp" - -//int main() -//{ -// std::vector v{1,6,88,2,0,77}; -// clrs::ch2::selection_sort(v.begin(), v.end()); -// alan::print_container(v); - -// alan::end(); -// return 0; -//} -//! @output -//! -//0 1 2 6 77 88 -//exit normally diff --git a/ch02/src/add_binary_numbers.hpp b/ch02/src/add_binary_numbers.hpp new file mode 100644 index 0000000..dc82307 --- /dev/null +++ b/ch02/src/add_binary_numbers.hpp @@ -0,0 +1,25 @@ +#pragma once + +namespace clrs +{ + namespace ch02 + { + template + Container add_binary_numbers(Container const& lhs, Container const& rhs) + { + Container sum(lhs.size() + 1); + auto l = lhs.crbegin(); + auto r = rhs.crbegin(); + typename Container::value_type carry = 0; + for (auto curr = sum.rbegin(); curr != sum.rend() - 1; ++curr) + { + unsigned bit_sum = *l++ + *r++ + carry; + *curr = bit_sum % 2; + carry = bit_sum / 2; + } + sum[0] = carry; + + return sum; + } + } +} \ No newline at end of file diff --git a/ch02/src/find_inversions.hpp b/ch02/src/find_inversions.hpp new file mode 100644 index 0000000..73123f4 --- /dev/null +++ b/ch02/src/find_inversions.hpp @@ -0,0 +1,44 @@ +#pragma once + + +namespace clrs +{ + namespace ch02 + { + template + Container merge_and_count_invertions(Container lhs, Container rhs, typename Container::size_type & count) + { + Container ret; + auto l = lhs.cbegin(); + auto r = rhs.cbegin(); + + //compare and copy, until either one exausted + while (l != lhs.cend() && r != rhs.cend()) + ret.push_back(*(*r < *l ? (count += lhs.cend() - l, r) : l)++); + + + //copy the rest + if (l == lhs.cend()) + while (r != rhs.cend()) + ret.push_back(*r++); + else + while (l != lhs.cend()) + ret.push_back(*l++); + + return ret; + } + + template + Container find_inversions_by_mergesort(Container const& seq, typename Container::size_type & count) + { + if (seq.size() > 1) + { + auto mid = seq.cbegin() + seq.size() / 2; + auto lhs = find_inversions_by_mergesort(Container(seq.cbegin(), mid), count); + auto rhs = find_inversions_by_mergesort(Container(mid, seq.cend()), count); + return merge_and_count_invertions(lhs, rhs, count); + } + return seq; + } + } +} \ No newline at end of file diff --git a/ch02/src/insertion_sort.hpp b/ch02/src/insertion_sort.hpp new file mode 100644 index 0000000..52e99bd --- /dev/null +++ b/ch02/src/insertion_sort.hpp @@ -0,0 +1,23 @@ +#pragma once +#include + +namespace clrs +{ + namespace ch02 + { + template> + void insertion_sort(Container& seq) + { + if (seq.size() <= 1) return; + + CompareFunc compare; + for (int i = 1; i != seq.size(); ++i) + { + auto key = seq[i]; + auto j = i - 1; + for (; j >= 0 && compare(seq[j], key); --j) seq[j + 1] = seq[j]; + seq[j + 1] = key; + } + } + } +} \ No newline at end of file diff --git a/ch02/src/main.cpp b/ch02/src/main.cpp new file mode 100644 index 0000000..9e8223b --- /dev/null +++ b/ch02/src/main.cpp @@ -0,0 +1,6 @@ +#include + +int main() +{ + return 0; +} \ No newline at end of file diff --git a/ch02/src/merge_sort.hpp b/ch02/src/merge_sort.hpp new file mode 100644 index 0000000..b3e22d1 --- /dev/null +++ b/ch02/src/merge_sort.hpp @@ -0,0 +1,42 @@ +#pragma once + +namespace clrs +{ + namespace ch02 + { + template + Container merge(Container lhs, Container rhs) + { + Container ret; + auto l = lhs.cbegin(); + auto r = rhs.cbegin(); + + //compare and copy, until either one exausted + while (l != lhs.cend() && r != rhs.cend()) + ret.push_back(*(*r < *l ? r : l)++); + + //copy the rest + if (l == lhs.cend()) + while (r != rhs.cend()) + ret.push_back(*r++); + else + while (l != lhs.cend()) + ret.push_back(*l++); + + return ret; + } + + template + Container merge_sort(Container const& seq) + { + if (seq.size() > 1) + { + auto mid = seq.cbegin() + seq.size() / 2; + auto lhs = merge_sort(Container(seq.cbegin(), mid)); + auto rhs = merge_sort(Container(mid, seq.cend())); + return merge(lhs, rhs); + } + return seq; + } + } +} \ No newline at end of file diff --git a/ch02/src/polynomial.hpp b/ch02/src/polynomial.hpp new file mode 100644 index 0000000..f27af09 --- /dev/null +++ b/ch02/src/polynomial.hpp @@ -0,0 +1,35 @@ +#pragma once + +namespace clrs +{ + namespace ch02 + { + template + typename Sequence::value_type naive_evaluate(Sequence const& seq, typename Sequence::value_type x) + { + using Value = typename Sequence::value_type; + + auto y = Value(0); + for (int i = 0; i != seq.size(); ++i) + { + auto x_part = Value(1); + for (auto k = i; k != 0; --k) + x_part *= x; + y += x_part * seq[i]; + } + + return y; + } + + template + typename Sequence::value_type horner_evaluate(Sequence const& seq, typename Sequence::value_type x) + { + using Value = typename Sequence::value_type; + + auto y = Value(0); + for (auto coefficient = seq.crbegin(); coefficient != seq.crend(); ++coefficient) + y = *coefficient + x*y; + return y; + } + } +} \ No newline at end of file diff --git a/ch02/src/selection_sort.hpp b/ch02/src/selection_sort.hpp new file mode 100644 index 0000000..ad89eca --- /dev/null +++ b/ch02/src/selection_sort.hpp @@ -0,0 +1,23 @@ +#pragma once +#include + +namespace clrs +{ + namespace ch02 + { + template + Container selection_sort(Container seq) + { + if (seq.size() < 2) return seq; + + for (int i = 0; i != seq.size() - 1; ++i) + { + int index_for_min = i; + for (int j = i; j != seq.size(); ++j) + if (seq[index_for_min] > seq[j]) index_for_min = j; + std::swap(seq[i], seq[index_for_min]); + } + return seq; + } + } +} \ No newline at end of file diff --git a/ch02/src/src.vcxproj b/ch02/src/src.vcxproj new file mode 100644 index 0000000..fe0a843 --- /dev/null +++ b/ch02/src/src.vcxproj @@ -0,0 +1,80 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {BA9819D5-BA49-490C-AACD-11BC927CBA56} + src + + + + Application + true + v120 + MultiByte + + + Application + false + v120 + true + MultiByte + + + + + + + + + + + + + + + Level3 + Disabled + true + + + true + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + true + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ch02/src/src.vcxproj.filters b/ch02/src/src.vcxproj.filters new file mode 100644 index 0000000..02ecf49 --- /dev/null +++ b/ch02/src/src.vcxproj.filters @@ -0,0 +1,42 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + \ No newline at end of file diff --git a/ch02/test/stdafx.cpp b/ch02/test/stdafx.cpp new file mode 100644 index 0000000..ab6cf71 --- /dev/null +++ b/ch02/test/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// test.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/ch02/test/stdafx.h b/ch02/test/stdafx.h new file mode 100644 index 0000000..43280fc --- /dev/null +++ b/ch02/test/stdafx.h @@ -0,0 +1,13 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +// Headers for CppUnitTest +#include "CppUnitTest.h" + +// TODO: reference additional headers your program requires here diff --git a/ch02/test/targetver.h b/ch02/test/targetver.h new file mode 100644 index 0000000..87c0086 --- /dev/null +++ b/ch02/test/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include diff --git a/ch02/test/test.vcxproj b/ch02/test/test.vcxproj new file mode 100644 index 0000000..ad37165 --- /dev/null +++ b/ch02/test/test.vcxproj @@ -0,0 +1,103 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {3C8BB254-56A9-4953-A3FB-27D273CC1E07} + Win32Proj + test + + + + DynamicLibrary + true + v120 + Unicode + false + + + DynamicLibrary + false + v120 + true + Unicode + false + + + + + + + + + + + + + true + + + true + + + + Use + Level3 + Disabled + $(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;%(PreprocessorDefinitions) + true + + + Windows + true + $(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories) + + + + + Level3 + Use + MaxSpeed + true + true + $(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;%(PreprocessorDefinitions) + true + + + Windows + true + true + true + $(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories) + + + + + + + + + Create + Create + + + + + + + + + + + + \ No newline at end of file diff --git a/ch02/test/test.vcxproj.filters b/ch02/test/test.vcxproj.filters new file mode 100644 index 0000000..e593748 --- /dev/null +++ b/ch02/test/test.vcxproj.filters @@ -0,0 +1,48 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/ch02/test/test_add_binary_numbers.cpp b/ch02/test/test_add_binary_numbers.cpp new file mode 100644 index 0000000..be035b3 --- /dev/null +++ b/ch02/test/test_add_binary_numbers.cpp @@ -0,0 +1,42 @@ +#include "stdafx.h" +#include "CppUnitTest.h" +#include "../src/add_binary_numbers.hpp" + +#include + +using namespace Microsoft::VisualStudio::CppUnitTestFramework; + +namespace test +{ + TEST_CLASS(test_add_binary_numbers) + { + public: + + TEST_METHOD(test_add_binary_numbers_case1) + { + std::vector lhs = { 1, 1 }; + std::vector rhs = { 0, 1 }; + auto actual = clrs::ch02::add_binary_numbers(lhs, rhs); + std::vector expect = { 1, 0, 0 }; + Assert::IsTrue(actual == expect); + } + + TEST_METHOD(test_add_binary_numbers_case2) + { + std::vector lhs = { 0 }; + std::vector rhs = { 0 }; + auto actual = clrs::ch02::add_binary_numbers(lhs, rhs); + std::vector expect = { 0, 0 }; + Assert::IsTrue(actual == expect); + } + + TEST_METHOD(test_add_binary_numbers_case3) + { + std::vector lhs = { 1, 1, 1, 1 }; + std::vector rhs = { 1, 1, 1, 1 }; + auto actual = clrs::ch02::add_binary_numbers(lhs, rhs); + std::vector expect = { 1, 1, 1, 1, 0 }; + Assert::IsTrue(actual == expect); + } + }; +} \ No newline at end of file diff --git a/ch02/test/test_find_inversions.cpp b/ch02/test/test_find_inversions.cpp new file mode 100644 index 0000000..70673ce --- /dev/null +++ b/ch02/test/test_find_inversions.cpp @@ -0,0 +1,66 @@ +#include "stdafx.h" +#include "CppUnitTest.h" +#include "../src/find_inversions.hpp" +#include + +using namespace Microsoft::VisualStudio::CppUnitTestFramework; + +namespace test +{ + TEST_CLASS(test_find_inversions) + { + public: + + TEST_METHOD(merge_and_count_invertions_case1) + { + auto lhs = std::vector < int > {9}; + auto rhs = std::vector < int > {0}; + std::size_t count = 0; + clrs::ch02::merge_and_count_invertions(lhs, rhs, count); + Assert::AreEqual(1u, count); + } + + TEST_METHOD(merge_and_count_invertions_case2) + { + auto lhs = std::vector < int > {8, 9}; + auto rhs = std::vector < int > {0, 1}; + std::size_t count = 0; + clrs::ch02::merge_and_count_invertions(lhs, rhs, count); + Assert::AreEqual(4u, count); + } + + TEST_METHOD(merge_and_count_invertions_case3) + { + auto lhs = std::vector < int > {8, 10}; + auto rhs = std::vector < int > {0, 9}; + std::size_t count = 0; + clrs::ch02::merge_and_count_invertions(lhs, rhs, count); + Assert::AreEqual(3u, count); + } + + TEST_METHOD(find_inversions_by_mergesort_case1) + { + auto sample = std::vector < int > {2, 1}; + std::size_t count = 0; + clrs::ch02::find_inversions_by_mergesort(sample, count); + Assert::AreEqual(1u, count); + } + + TEST_METHOD(find_inversions_by_mergesort_case2) + { + auto sample = std::vector < int > {}; + std::size_t count = 0; + clrs::ch02::find_inversions_by_mergesort(sample, count); + Assert::AreEqual(0u, count); + } + + TEST_METHOD(find_inversions_by_mergesort_case3) + { + auto sample = std::vector < int > {2, 3, 8, 6, 1}; + std::size_t count = 0; + clrs::ch02::find_inversions_by_mergesort(sample, count); + Assert::AreEqual(5u, count); + } + + }; +} \ No newline at end of file diff --git a/ch02/test/test_insertion_sort.cpp b/ch02/test/test_insertion_sort.cpp new file mode 100644 index 0000000..507787e --- /dev/null +++ b/ch02/test/test_insertion_sort.cpp @@ -0,0 +1,64 @@ +#include "stdafx.h" +#include "CppUnitTest.h" +#include "../src/insertion_sort.hpp" +#include +#include + +using namespace Microsoft::VisualStudio::CppUnitTestFramework; + +namespace test +{ + TEST_CLASS(test_insertion_sort) + { + public: + + TEST_METHOD(insertion_sort_case1) + { + std::vector sample = { 1, 5, 2, 1, 6 }; + std::vector expect = { 1, 1, 2, 5, 6 }; + clrs::ch02::insertion_sort(sample); + Assert::IsTrue(sample == expect); + } + + TEST_METHOD(insertion_sort_case2) + { + std::vector sample = { 5 }; + std::vector expect = { 5 }; + clrs::ch02::insertion_sort(sample); + Assert::IsTrue(sample == expect); + } + + TEST_METHOD(insertion_sort_case3) + { + std::vector sample = {}; + std::vector expect = {}; + clrs::ch02::insertion_sort(sample); + Assert::IsTrue(sample == expect); + } + + TEST_METHOD(insertion_sort_case4) + { + std::deque sample = { 1, 5, 2, 1, 6 }; + std::deque expect = { 1, 1, 2, 5, 6 }; + clrs::ch02::insertion_sort(sample); + Assert::IsTrue(sample == expect); + } + + TEST_METHOD(insertion_sort_case5_reverse) + { + std::deque sample = { 1, 5, 2, 1, 6 }; + std::deque expect = { 6, 5, 2, 1, 1 }; + clrs::ch02::insertion_sort, std::less>(sample); + Assert::IsTrue(sample == expect); + } + + TEST_METHOD(insertion_sort_case6_reverse) + { + std::vector sample = {}; + std::vector expect = {}; + clrs::ch02::insertion_sort, std::less>(sample); + Assert::IsTrue(sample == expect); + } + + }; +} \ No newline at end of file diff --git a/ch02/test/test_merge_sort.cpp b/ch02/test/test_merge_sort.cpp new file mode 100644 index 0000000..ba55076 --- /dev/null +++ b/ch02/test/test_merge_sort.cpp @@ -0,0 +1,60 @@ +#include "stdafx.h" +#include "CppUnitTest.h" +#include "../src/merge_sort.hpp" +#include + +using namespace Microsoft::VisualStudio::CppUnitTestFramework; + +namespace test +{ + TEST_CLASS(test_merge_sort) + { + public: + + TEST_METHOD(test_merge_case1) + { + auto ret = clrs::ch02::merge(std::vector(), std::vector()); + Assert::IsTrue(ret == std::vector()); + } + + TEST_METHOD(test_merge_case2) + { + auto ret = clrs::ch02::merge(std::vector < int > {1}, std::vector < int > {1}); + Assert::IsTrue(ret == std::vector < int > {1,1}); + } + + TEST_METHOD(test_merge_case3) + { + auto ret = clrs::ch02::merge(std::vector < int > {2, 3}, std::vector < int > {1, 4}); + Assert::IsTrue(ret == std::vector < int > {1, 2, 3, 4}); + } + + TEST_METHOD(test_merge_case4) + { + auto ret = clrs::ch02::merge(std::vector < int > {1}, std::vector < int > {5, 6, 7, 8}); + Assert::IsTrue(ret == std::vector < int > {1, 5, 6, 7, 8}); + } + + TEST_METHOD(test_merge_sort_case1) + { + auto sample = std::vector < int > {2, 1}; + auto ret = clrs::ch02::merge_sort(sample); + Assert::IsTrue(ret == std::vector < int > {1, 2}); + } + + TEST_METHOD(test_merge_sort_case2) + { + auto sample = std::vector < int > {}; + auto ret = clrs::ch02::merge_sort(sample); + Assert::IsTrue(ret == std::vector < int > {}); + } + + TEST_METHOD(test_merge_sort_case3) + { + auto sample = std::vector < int > { 1, 5, 2, 1, 6 }; + auto ret = clrs::ch02::merge_sort(sample); + Assert::IsTrue(ret == std::vector < int > { 1, 1, 2, 5, 6 }); + } + + }; +} \ No newline at end of file diff --git a/ch02/test/test_polynomial.cpp b/ch02/test/test_polynomial.cpp new file mode 100644 index 0000000..d6746dd --- /dev/null +++ b/ch02/test/test_polynomial.cpp @@ -0,0 +1,75 @@ +#include "stdafx.h" +#include "CppUnitTest.h" +#include "../src/polynomial.hpp" +#include + +using namespace Microsoft::VisualStudio::CppUnitTestFramework; + +namespace test +{ + TEST_CLASS(test_polynomial) + { + public: + + TEST_METHOD(naive_evaluate_case1) + { + auto sample = std::vector < int > { 1 }; //y = 1 + auto x = 2; + auto expect = 1; + auto actual = clrs::ch02::naive_evaluate(sample, x); + + Assert::AreEqual(actual, expect); + } + + TEST_METHOD(naive_evaluate_case2) + { + auto sample = std::vector < int > { 1, 2 }; // y = 1 + 2x + auto x = 2; + auto expect = 5; + auto actual = clrs::ch02::naive_evaluate(sample, x); + + Assert::AreEqual(actual, expect); + } + + TEST_METHOD(naive_evaluate_case3) + { + auto sample = std::vector < int > { 5, 2, 0, 7}; // y = 5 + 2x + 0x^2 + 7x^3 + auto x = 2; // = 5 + 4 + 0 + 56 = 65 + auto expect = 65; + auto actual = clrs::ch02::naive_evaluate(sample, x); + + Assert::AreEqual(expect, actual); + } + + TEST_METHOD(horner_evaluate_case1) + { + auto sample = std::vector < int > { 1 }; //y = 1 + auto x = 2; + auto expect = 1; + auto actual = clrs::ch02::horner_evaluate(sample, x); + + Assert::AreEqual(actual, expect); + } + + TEST_METHOD(horner_evaluate_case2) + { + auto sample = std::vector < int > { 1, 2 }; // y = 1 + 2x + auto x = 2; + auto expect = 5; + auto actual = clrs::ch02::horner_evaluate(sample, x); + + Assert::AreEqual(actual, expect); + } + + TEST_METHOD(horner_evaluate_case3) + { + auto sample = std::vector < int > { 5, 2, 0, 7}; // y = 5 + 2x + 0x^2 + 7x^3 + auto x = 2; // = 5 + 4 + 0 + 56 = 65 + auto expect = 65; + auto actual = clrs::ch02::horner_evaluate(sample, x); + + Assert::AreEqual(expect, actual); + } + + }; +} \ No newline at end of file diff --git a/ch02/test/test_selection_sort.cpp b/ch02/test/test_selection_sort.cpp new file mode 100644 index 0000000..af4d99a --- /dev/null +++ b/ch02/test/test_selection_sort.cpp @@ -0,0 +1,36 @@ +#include "stdafx.h" +#include "CppUnitTest.h" +#include "../src/selection_sort.hpp" +#include +#include + +using namespace Microsoft::VisualStudio::CppUnitTestFramework; + +namespace test +{ + TEST_CLASS(test_selection_sort) + { + public: + + TEST_METHOD(test_selection_sort_case1) + { + std::vector sample = { 1, 5, 2, 1, 6 }; + std::vector expect = { 1, 1, 2, 5, 6 }; + Assert::IsTrue(clrs::ch02::selection_sort(sample) == expect); + } + + TEST_METHOD(test_selection_sort_case2) + { + std::vector sample = { 6 }; + std::vector expect = { 6 }; + Assert::IsTrue(clrs::ch02::selection_sort(sample) == expect); + } + + TEST_METHOD(test_selection_sort_case3_string) + { + std::vector sample = { "a", "2", "z", "bb", "0" }; + std::vector expect = { "0", "2", "a", "bb", "z" }; + Assert::IsTrue(clrs::ch02::selection_sort(sample) == expect); + } + }; +} \ No newline at end of file diff --git a/misc/utility.hpp b/misc/utility.hpp new file mode 100644 index 0000000..17d29cf --- /dev/null +++ b/misc/utility.hpp @@ -0,0 +1,13 @@ +#pragma once +#include + +template +inline std::ostream& print(Container const& seq) +{ + std::cout << "{ "; + for (auto const& elem : seq) + std::cout << elem << " "; + std::cout << "}"; + + return std::cout; +} \ No newline at end of file