/* .. 离开了邓公的视频讲解,只能自己看课件瞎捉摸了,仅以此立下flag,摸摸前行的垫脚石。 ..*/
【第八章 高级搜索树】
1-Dimensional Range Query:Counting & Reporting
对于一位向量,大量随机查询,Brute-force 是O(n),考虑排序+二分查找?
1d-tree (Lowest Common Ancestor):排序时间O(nlogn),空间O(n)
plannar Range Query:2d-tree kd-tree (查阅相关博客)
quadtree 四分树
Multi-Level Search Tree: x-Query + y-Query –》 x-Query * y-Query (BBST<BBST<T>> -- BBST<Vector<T>>)
range tree : an MLST with fractional cascading
interval tree : 存储interval元素,查询点在的interval
segment tree 线段树:用于区间求和(最值),建树,修改,查询。
参考 https://www.cnblogs.com/wuyudong/p/segment-tree.html
https://www.cnblogs.com/xiaoyao24256/p/6590885.html
#define N 1000
struct node {
int l, r, value;
int add;
} tree[N*4];
void build(int l, int r, int v) {
tree[v].l = l; tree[v].r = r;
if (l == r) { tree[v].value = v; return; }
int mid = (l + r) >> 1;
build(v * 2, l, mid);
build(v * 2 + 1, mid + 1, r);
tree[v].value = tree[v * 2].value + tree[v * 2 + 1].value; // 区间求和
}
void update(int v, int r, int l, int m) { // 区间[l, r), 增量m
if (tree[v].l == l && tree[v].r == r) {
tree[v].value += m * (r - l + 1);
tree[v].add = m;
return;
}
if (tree[v].add) {
tree[v * 2].add += tree[v].add;
tree[v * 2 + 1].add += tree[v].add;
tree[v].add = 0;
}
int mid = (tree[v].l + tree[v].r) >> 1;
if (r <= mid) {
update(v * 2, l, r, m);
}
else {
if (l > mid) {
update(v * 2 + 1, l, r, m);
}
else {
update(v * 2, l, mid, m);
update(v * 2 + 1, mid + 1, r, m);
}
}
}
【第九章 词典】
跳表 skip lists :[William Pugh, 1989] a probabilistic alternative to balanced trees
性能和平衡树差不多。生长概率逐层减半,空间期望值O(n),横向和纵向查找期望值均为O(logn)
通过多层有序链表实现:主要三个函数,查找;插入(用随机函数确定是否生长);删除。(以下代码仅代表思路)
1 template <typename T> class Quadlist { 2 private: int _size; QuadlistNodePosi(T) header, trailer; 3 protected: void init(); int clear(); // 初始化、清除所有节点 4 public: QuadlistNodePosi(T) first() const { return header->succ; } 5 QuadlistNodePosi(T) last() const { return trailer->pred; } 6 T remove(QuadlistNodePosi(T) p); // 删除 7 QuadlistNodePosi(T) insertAfterAbove( // 插入e,成为p后继和b上邻 8 T const & e, 9 QuadlistNodePosi(T) p, 10 QuadlistNodePosi(T) b = NULL); 11 }; 12 13 template <typename K, typename V> class Skiplist : 14 public Dictionary<K, V>, public List<Quadlist<Entry<K, V>> * > { 15 protected: 16 bool skipSearch(ListNode< Quadlist<Entry<K, V>>*>* &qlist, 17 QuadlistNode<Entry<K, V>>* &p, K &k); 18 public: 19 int size() { return empty() ? 0 : last()->data->size(); } 20 int level() { return List::size(); } 21 bool put(K, V); 22 V* get(K); 23 bool remove(K); 24 }; 25 26 bool skipSearch(&qlist, &p, &k) { 27 /* 从指定层qlist的首节点p出发,向右succ 向下below 查找k, 28 在每一层向后查找,直到出现key,或者溢出至trailer。 29 命中,则成功返回 30 否则进入下一层qlist,若已穿透底层,则意味着失败 31 p进入当前塔的下一节点 32 确认:无论成功或失败,返回的p均为其中不大于e的最大者?体会哨兵的作用*/ 33 while (true) { 34 while (p->succ && (p->entry.key <= k)) p = p->succ; p = p->pred; 35 if (p->pred && (k == p->entry.key)) return true; 36 qlist = qlist->succ; 37 if (!qlist->succ) return false; 38 p = p->pred ? p->below : qlist->data->first(); 39 } 40 } 41 42 bool put(k, v) { 43 Entry<K, V> e = Entry<K, V>(k, v); 44 if (empty()) insertAsFirst(new Quadlist<Entry<K, V>>); 45 ListNode<Quadlist<Entry<K, V>>*>* qlist = first(); 46 QuadlistNode<Entry<K, V>>* p = qlist->data->first(); 47 if (skipSerach(qlist, p, k)) 48 while (p->below) p = p->below; // 强制转到塔底 49 /* 以下,紧邻与p的右侧,以新节点b为基座,自底而上逐层长出一座新塔 */ 50 qlist = last(); 51 QuadlistNode<Entry<K, V>>* b = qlist->data->insertAfterAbove(e, p); 52 while (rand() & 1) { 53 /* 随机确定塔是否长高, 54 先定位不低于此高度的最近前驱p, 55 若已经最高,则创建新层;若是header,则转移p至上一层header;否则,直接提升p 56 qlist提升一层 57 插入节点至 p之后,b之上 */ 58 while (qlist->data->valid(p) && !p->above) p = p->pred; 59 if (!qlist->data->valid(p)) { 60 if (qlist == first()) 61 insertAsFirst(new Quadlist<Entry<K, V>>); 62 p = qlist->pred->data->first()->pred; 63 } 64 else p = p->above; 65 qlist = qlist->pred; 66 b = qlist->data->insertAsAbove(e, p, b); 67 } 68 } 69 70 bool remove(k) { 71 /* 表为空或者不存在,则返回 72 先记住下一层节点,然后删除当前节点,转到下一层继续删除。 73 需要清除已可能不含词条的顶层。 */ 74 if (empty()) return false; 75 ListNode<>* qlist = first(); 76 QuadlistNode<>* p = qlist->data->first(); 77 if (!skipSearch(qlist, p, k)) return false; 78 do { 79 QuadlistNode<>* lower = p->below; 80 qlist->data->remove(p); 81 p = lower; qlist = qlist->succ; 82 } while (qlist->succ); 83 while (!empty() && first()->data->empty()) 84 List::remove(first()); 85 return true; 86 }
位图 bitmap
依散列思想,所有离散集或显示或隐式可表达为整数集。
使用物理地址连续的一段空间,各元素依次对应于一个bit位
应用:小集合+大数据,内存要求高,否则将导致整体I/O效率低下;素数筛法;
1 class Bitmap { 2 private: 3 char* M; // 以char(8 bit)为单位的bitmap 4 int N; // 位图长度 以sizeof(char)为单位 5 public: 6 Bitmap(int n = 8) { M = new char[N = (n + 7) / 8]; memset(M, 0, N); } 7 ~Bitmap() { delete[] M; M = NULL; } 8 void set(int k); void clear(int k); bool test(int k); 9 }; 10 void set(int k) { 11 expand(k); 12 M[k >> 3] |= (0x80 >> (k & 0x07)); // '1000 0000' 右移 k%8 的位数 13 } 14 void clear(int k) { // 体会一下位操作,移位后取非再并;因为要覆盖,就必须用并 15 expand(k); 16 M[k >> 3] &= ~(0x80 >> (k & 0x07)); 17 } 18 void test(int k) { 19 expand(k); 20 return M[k >> 3] & (0x80 >> (k & 0x07)); 21 } 22 void expand(int k) { 23 if (k < 8 * N) return; 24 int oldN = N; char* oldM = M; 25 M = new char[N = (2 * k + 7) / 8]; // 加倍扩容策略 26 memcpy_s(M, N, oldM, oldN); 27 delete[] oldM; 28 }
初始化操作对算法整体的影响——很深远:用校验环进行初始化 O(1),[J.Hopcroft, 1974]
新增两个向量 和一个标识
1 int F[m]; // From 2 int T[m]; int top = 0; // To 及其栈顶标识 3 bool Bitmap::test(int k) { // O(1) 4 return (0 <= F[k]) && (F[k] < top) 5 && (k == T[F[k]]); // 校验环 6 } 7 bool Bitmap::reset() { top = 0; } // 复位,切断所有校验环, O(1)!!! 8 bool Bitmap::set(int k) { 9 if (!test(k)) { 10 T[top] = k; F[k] = top++; // 创建校验环 11 } 12 } 13 bool Bitmap::clear(int k) { 14 if (test(k)) 15 if (--top) { 16 F[T[top]] = F[k]; T[F[k]] = T[top]; // 用top位置的环覆盖 17 } 18 }
MD5算法
【第十一章 串】
键树、 Trie树(retrieve)、字典树:多模式匹配,(KMP算法是单模式匹配)
算法思想:空间换时间,利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。
一种哈希树的变种。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。【下图感受一下】
网上参考:https://blog.csdn.net/hackbuteer1/article/details/7964147