1. 红黑树
1.1 概念
红黑树是一种自平衡二叉查找树,是一种非常有用的数据结构,最典型的实现是“关联数组”(包括set, multiset, map, multimap)。
在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其
他路径长出俩倍,因而是接近平衡的。
前面说了,红黑树,是一种二叉查找树,既然是二叉查找树,那么它必满足二叉查找树的一般性质。
下面,在具体介绍红黑树之前,咱们先来了解下 二叉查找树的一般性质:
1. 在一棵二叉查找树上,执行查找、插入、删除等操作,的时间复杂度为O(lgn)。
因为,一棵由n个结点,随机构造的二叉查找树的高度为lgn,所以顺理成章,一般操作的执行时间为O(lgn)。
//至于n个结点的二叉树高度为lgn的证明,可参考算法导论 第12章 二叉查找树 第12.4节。
2. 但若是一棵具有n个结点的线性链,则此些操作最坏情况运行时间为O(n)。
而红黑树,能保证在最坏情况下,基本的动态几何操作的时间均为O(lgn)。
ok,我们知道,红黑树上每个结点内含五个域,color,key,left,right,parent。如果相应的指针域没有,则设为NIL。一般的,红黑树,满足以下性质,即只有满足以下全部性质的树,我们才称之为红黑树:
- 性质1. 节点是红色或黑色。
- 性质2. 根节点是黑色。
- 性质3 每个叶节点(NIL节点,空节点)是黑色的。
- 性质4 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
- 性质5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
1.2 树的旋转
当我们在对红黑树进行插入和删除等操作时,对树做了修改,那么可能会违背红黑树的性质。
为了保持红黑树的性质,我们可以通过对树进行旋转,即修改树种某些结点的颜色及指针结构,以达到对红黑树进行插入、删除结点等操作时,红黑树依然能保持它特有的性质(如上文所述的,五点性质)。
树的旋转,分为左旋和右旋,以下借助图来做形象的解释和介绍:
左旋
2. 图论
判断图的回环问题
3. 链表
3.1 怎么找到单向链表倒数第n个元素
思路:定义两个节点指针,首先让其相隔n个元素,然后一起同步向后走,当第二个指针走到最后节点时,第一个指针则指向了倒数第n个元素!
3.2 怎么找到单向链表的中间位置的元素
思路:定义两个节点指针,并让其指向链表头部,当向后走的时候,第一个指针每次走两步,第二个指针每次走一步,那么当第一个指针为NULL时,返回第一个指针即可!
3.3 判断两个链表是否相交:(假设两个链表都没有环)
- 判断第一个链表的每个节点是否在第二个链表中;
- 把第二个链表连接到第一个后面,判断得到的链表是否有环,有环则相交;
- 先遍历第一个链表,记住最后一个节点,再遍历第二个链表,得到最后一个节点时和第一个链表的最后一个节点做比较,如果相同,则相交;
3.4 如何判断一个单链表是有环的?(注意不能用标志位,最多只能用两个额外指针)
一种O(n)的办法就是(用两个指针,一个每次递增一步,一个每次递增两步,如果有环的话两者必然重合,反之亦然)
bool check(const node* head) { if(head==NULL) return false; node *low=head, *fast=head->next; while(fast!=NULL && fast->next!=NULL) { low=low->next; fast=fast->next->next; if(low==fast) return true; } return false; }