随笔分类 - 算法/数据结构
算法导论学习
摘要:引言 问题引入 对于一个2×2的表格,从左上角走到右下角,过程只可以向右或向下移动,共有6种方式(如图),那么,对于一个10×10的表格呢? 递归解法 n设坐标以左上角为(0,0),向右记为R,为x轴的增方向;向下记为D,为y轴的增方向。当前坐标为C,表格的宽=高=S。 从(0,0)开始,我们有两种选择,R和D。 如果第一步选择R时,C=(1,0),此时又有两种选择,R和D,也就是说,与第一步是一样的。 同理,如果第一步选择的是D,也与第一步一致。 显然,这是一个递归的过程。边界条件就是当C的坐标到达(S-1,S-1)。 因此: stat...
阅读全文
摘要:1 //[1] 2 //求int32的绝对值。 3 //首先,对x右移32位,需要注意的是,对有符号整型来说,右移操作采用算数移位,也就是说,符号位不变。 4 //如果x为正数,则得到0,否则得到0xFFFFFFFF。 5 //然后异或x,如果x为正数,则x异或0,保持不变;否则,反转x的各位。 6 //最后,如果x为负数,那么最终的减去(x >> 31)就是加1。也就说,求出了负数的补码。正是计算机中表示数值的形式。 7 #define ABS(x) ((x ^ (x >> 31)) - (x >> 31)) 8 9 10 //[2]11 //用来判断一个
阅读全文
摘要:概念:红黑树也是一类二叉查找树,但是在每个结点上增加一个存储位表示颜色,是红色或者黑色。通过对任何一条从根到叶子的路径上的颜色限制,红黑树可以确保没有一条路径会比其它路径长出两倍,因而是接近平衡的。红黑树保证在最坏情况下,基本动态集合操作为O(lg(n))。树的每个结点包含5个域,color,key,left,right,parent。本文为了方便起见,视key和value的值相等,而且都为int。如果一个结点没有一个子结点或者父结点,则相应的指针域包含NULL。将这些NULL视为指向二叉查找树外结点的指针,将带关键字的节点视为树的内结点。从某个节点x出发,不包含这个结点,到达叶结点的任意一条
阅读全文
摘要:概念: 二叉查找树的存储方式总是满足一下的性质,如果y是x的左子树的一个节点,则key[y]<=key[x];如果y是x的右子树的一个节点,则key[x]<=key[y]。 性质: 一棵随机构造的二叉查找树的期望高度是O(lg(n)),从而树上的基本集合操作的平均时间是O(lg(n))。 二叉树的遍历分为先序,中序和后序,本文中的算法都是针对中序遍历,当然另外两种的算法也会给出。 根据一种遍历方法,每个树节点都有前驱和后继,就中序遍历而言,如果一个节点有左右两个子节点,那么它的前驱点一定没有右子树,它的后继一定没有左子树。这是因为,...
阅读全文
摘要:引言 很多应用中需要用到一种动态集合结构,支持insert,search,delete。实现这种结构一种有效的数据结构为散列表。最坏情况下,散列中查找一个元素与在一个链表中的时间相同,都是O(n),然而在一些合理的假设下,在散列中查找一个元素的期望是O(1)。 什么是散列表 散列表可以理解为普通数组的推广,可以对数组进行直接寻址,可以再O(1)时间内查找任意元素,这叫做直接寻址表。 直接寻址表有个明显的不足:如果key的取值范围很大,而实际要存储的关键字集合的大小相对key的取值域来说很小,那么会造成很明显的空间浪费。这时就需要散列技术。 散列表通常采用的数组尺寸与所要存储的关键字数是成比例的
阅读全文
摘要:看了这篇文章才对浮点数的二进制表示有所了解,不过我的目的不是为了软考。C/C++编译器都是按照IEEE的浮点数表示法,即一种科学计数法 ,用符号,指数和尾数来表示,底数为2,也就是把浮点数表示为尾数乘以2的指数次方再添加上符号的形式。因为科学技术法 a×bm的形式,a介于1~10,而浮点数表示法中,a始终为1,所以在最终的表示结果中,这个1被略去。 具体规格是: 符号位阶码尾数总长度 float182332 double1115264 下面通过例子来解释上面的表示规格: 38414.4表示为doubl...
阅读全文
摘要:关于stack,queue和list的简单实现:template <class Type>class Stack{public: Stack(int size) :size_(size) { ptr_ = new Type[size_]; next_ = ptr_; } ~Stack() { delete []ptr_; ptr_ = NULL; } void push(const Type& val); Type pop();private: int size_; Type* ptr_; Type* next_;};template <class Type>v
阅读全文
摘要:template <class value_t>int partition(value_t *arr, int first, int last){ --last; int i = first - 1; int x = arr[last]; for(int j = 0; j < last; ++j) { if(arr[j] <= x) ++i, std::swap(arr[j], arr[i]); } std::swap(arr[i + 1], arr[last]); return i + 1;}template <class value_t>int GetN
阅读全文
摘要:1.获取序列最大和最小值的方法很简洁也很高效:template <template value_t>value_t max_element(int *arr, int ncount){ int max = arr[0]; for(int i = 0; i < ncount; ++i) { if(arr[0] > max) max = arr[0]; } return max;}template <template value_t>value_t min_element(int *arr, int ncount){ int ...
阅读全文
摘要:比较排序是无法突破O(nlg(n))的时间界限的,如若希望实现线性时间的排序,必须放弃比较的方式排序。下面要描述的计数排序,基数排序和桶排序,都不是比较排序,因此,O(nlg(n))对于他们来说不适用。计数排序:计数排序假设输入的序列的值是从0~k的,它不能原地的排序,因此需要另外一个输出区间;而且需要有一个辅助的区间,这个区间的大小与0~k的元素的个数相同。排序开始时,分配一个辅助区间,初始化为0;然后,将设置辅助区间各个位置上的值,使得第i个索引上的值,为数值为i的元素的个数。然后从1下标遍历这个辅助区间,令array[i] += array[i - 1],最终的结果是,对于索引为i的辅助
阅读全文
摘要:快速排序也是分治的,但不同于分治的一点是,它有分隔的概念,把一个序列按照p分为两份,左边的小于等于p,右边的大于等于p,再对两边的序列重复这个过程,直到序列只有一个元素为止。快速排序的最坏运行时间是O(n^2),证明如下:快速排序的平均运行时间能达到O(nlg(n)),比较排序不能突破这个极限,可以把比较排序算法理解为决策树模型,决策树是一种满二叉树,注意这里的二叉树是国际定义的满二叉树,也就是说,所有的节点,要么是叶子节点,要么度为2,不存在度为1的节点:以上就是一棵满二叉树,表示了对3,2,1进行排序的过程。可以看到,对于排列而言,n个元素对应n!个排列,也就对应树的n!个叶子节点,这里的
阅读全文
摘要:合并排序是分治的思想,把大的问题分解成小的问题,再把小的问题组合起来。合并排序通过把一个序列等分为两份,然后再分别把这两份等分,直到不能再分(只有一个元素)为之,接着把分开的序列合并,最后得到整个有序的序列。合并排序合并的过程不是在原地的,需要把数组拷贝出去,再按照顺序拷贝回来,之中设计到内存的动态分配和释放。假设输入序列为A,共有n个元素,那么合并的过程的时间复杂度是O(n),这是显而易见的。合并排序的层数可以很直观的看到,假设层数为X,当X=1时是cn/2,即cn/(2^x),当2^x=n时,分解结束,此时X=lg(n),再加上最顶层,是lg(n)+1,乘以每一层的代价cn,得cn
阅读全文
摘要:堆:堆是完全二叉树。和其他的树一样,用数组表示堆,保留索引为0的位置(这个位置可以用来保存堆中元素的数),对于一个下标为i的节点,它的左子节点的下标为2×i,右子节点是2×i+1。 堆的叶子节点是从(n/2)+1处开始的。这一点可以这样证明:假设一个堆有n个节点, 设下标为m的节点是该堆的第一个子节点,那么一定有2×m>n,且m节点之前的节点,一定不是叶子节点,那么就有(m-1)×2<=n,也就是说: (n/2)+1 >= m > n/2, 由于m是自然数,所以m只可以取值(n/2)+1。根据堆的性质,定义如下两个宏来计算堆的父子
阅读全文
摘要:1.有穷级数的值总是有定义的。 2. 对于无穷级数: 如果极限不存在,则这个级数是发散的,否则是收敛的。 一个收敛级数的项并不是可以任意顺序相加的,除非它是绝对收敛级数: 3. 对任意实数c和任意有限序列,存在: 这个特征可以用来对含有渐进符号的项求和: 4. 等差级数求和: 5. 平方和和立方和: 6. 几何级数定义: 值为: 7. 调和级数: 8. 自反,对称,传递性:关系的性质主要有以下五种: Ref:http://zh.wikipedia.org/wiki/%E4%BA%8C%E5%85%83%E5%85%B3%E7%B3%BB自反性:在集合 X 上的关系 R,如对...
阅读全文
摘要:一般的插入排序(全文按照operator <排序):void insertion_sort(int* arr, int count){ for(int i = 1; i < count; ++i) { int key = arr[i]; //需要插入的元素. //元素插入的序列,注意,pArr[0~j]一定是已经排序的.在这一点上,可以引发一些优化. int j = i - 1; while(j >= 0 && arr[j] > key) //在已经排序的序列中,寻找key的插入位置. { arr[j + 1] = arr[j]; //将大于key的元素
阅读全文
浙公网安备 33010602011771号