第四章 线性序
本章讨论了二元关系的性质比如传递性和对称性,着重介绍了全序和弱线性序,给数据的有序存储打下基础。
Relation(Op)=
HomogeneousPredicate(Op)
^Arity(Op) = 2 // 关系的定义:两元同源谓词
Property(R:Relation) // 传递性的定义
transitive:R
r->(r(a,b)^r(b,c) => r(a,c))
严格的(strict):关系对其自身之间的作用无效。比如大于,对自己和自己比较是没有意义的。
自反的(reflexive): 关系对其自身之间总有这一关系。
对称的(symmetric):如果关系在一个方向成立在另一方向也成立,比如A是B的兄弟,同样B也是A的兄弟。
反对称(asymmetric):在一个方向成立绝对不在另一个方向成立,比如A是B的父亲,那B绝对不是A的父亲。
equivalence:R // 相等的完整定义: 具有传递 自反 对称这三种特性的一种关系
r-> transitive(r) ^ reflexive(r) ^ symmetric (r)
三分律(tri-chotomy law):两个数之间的关系不是大于就是小于或者等于。
排序算法的稳定性:当两个元素相等时,比较的结果不会破坏其原来的顺序,举例来讲如果 a=b,那么排序的结果不会让b跑到a前面。
第五章 有序代数结构
单位元: 它和任意其他元素组合总得到那个元素,比如乘法的1,加法的0
半群(semigroup):带有一个可交换的运算的集合。比如加法可交换那就是加半群,某些乘法就不是半群,比如矩阵相乘。
幺半群(monoid): 带有单位元的半群。 那带有0的加法,那就是加法幺半群。带有1的乘法就是乘法幺半群。
群(group):带有逆运算的幺半群。
半环:当一个类型同时有加法和乘法。
求余
作者写了一个递归形式的算法,还介绍了Floyd and Knuth的算法,我更倾向后面这种,
template<typename T> requires(HalvableMonid(T)) T remainder_nonnegative_iterative(T a, T b) { if(a<b) return a; T c=largest_double(a, b); a =a-c; while(c!=b){ c=half(c); if(c<=a) a=a-c; } return a; } template<typename T> requires(ArchimedeanMonoid(T)) T largest_doubling(T a, T b){ while(b<a-b) b= b+b; return b; }
gcd(a, b) = gcd(a-b, b)
先根据上门的公式实现一种简单的算法
template<typename T> T substarctive_gcd_nozero(T a, T b){ while(true){ if(b<a) a=a-b; else if(a<b) b=b-a; else return a; } }利用上面求余的快速算法,加上对特殊情况0的处理得到下面优化算法
template<typename T> T fast_subtractive_gcd(T a, T b){ while(true){ if(b==T(0)) return a; a = remainder_nonnegative_iterative(a, b); if(a==T(0)) return b; b=remainder_nonnegative_iterative(b,a); } }
template<typename T> pair<QuotientType(T), T> quotient_remainder_nonegative_iterative(T a, T b){ typedef QuotientType(T) N; if(a<b) return pair<N,T>(N(0), a); T c = largest_doubling(a, b); a=a-c; N n(1); while(c!=b){ n=twice(n); c=half(c); if(c<=a){ a=a-c; n=successor(n); // ++n } } return pair<N, T>(n,a); }
迭代器就是stl的灵魂之一,本章从数学的角度对不同的迭代器进行了规范,由于使用stl时候已经感觉到迭代器的好处,所以就不再详细阅读。