
数据结构、算法与应用
Zacky_ran
keep learning.
展开
-
多维数组的访问顺序不同导致程序性能不同的原因--高速缓存(cache命中)
我们知道,计算机内存的结构是由逻辑运算单元(ALU)、寄存器(R)、一级缓存cache(L1)、二级缓存cache(L2)、主存(也就是普通内存)构成的。离ALU越近的存储单元速度越快,出于这个原因,计算机采用了一些策略,比如把最近需要处理的数据预载到缓存中,当出现一个缓存未命中时,再把需要的该数据和它相邻若干字节的数据重新装入缓存中。因此,对于多维数组的访问顺序不同也将导致程序的性能不同。考虑...原创 2019-05-17 13:00:42 · 1192 阅读 · 0 评论 -
基于二叉树的前序、中序、后序以及层次遍历迭代器
本文基于二叉树的实现中类似的二叉树结构,其要求节点结构只有左右孩子而无父节点的二叉树。因此,只能靠队列/栈来存储遍历的路径信息,模拟递归调用的过程。同时,本文中迭代器的判断operator==/!=只能通过判断队列/栈中的路径信息来实现。严格地讲,本文的迭代器不如叫作伴随类。因为它不够轻量,一般的迭代器只保存指针信息,而本文的迭代器使用了队列/栈。其中,前序、中序、后序迭代器的栈最大为O(...原创 2019-08-04 12:12:13 · 662 阅读 · 0 评论 -
基于跳表的字典实现
为有序链表增加额外的向前指针的链表叫作跳表(skip list)。它采用随机技术来决定链表的哪些节点应增加向前指针以及增加多少个指针。基于这种随机技术,跳表的查找、插入、删除的平均时间复杂度为O(logN)。然而在最坏情况下,时间复杂度却渐近等于N。关于跳表级数的确定在规则的跳表结构中,第i级链表的数对个数与第i-1级链表的数对个数之比是一个分数p,因此属于i-1级链表的数对同时属于第i级链表...原创 2019-07-26 21:34:28 · 322 阅读 · 0 评论 -
基于散列表(线性探查的哈希表和链式散列)的字典实现
字典的另一种表示是散列。它用一个散列函数(也称哈希函数)把字典的数对映射到一个散列表(也称哈希表)的具体位置。与跳表相比,它把操作的时间提高到渐近等于1,但最坏情况下依然是渐近等于N。但是如果经常输出所有元素或按照顺序查找元素(如查找第10个最小元素之类),跳表的执行效率将优于散列。基于跳表的字典实现散列函数和散列表1.桶和起始桶当关键字范围太大,不能用理想方法表示时,可以采用并不理想的散...原创 2019-07-26 22:26:33 · 1642 阅读 · 10 评论 -
基于哈希表的应用--LZW压缩和解压算法
关于哈希表的实现。本文实现的LZW解压算法主要应用了链式哈希表。关于Lempel-Ziv-Welch开发的LZW压缩/解压算法,具体可以参考这位博主的文章:LZW压缩算法的原理解析,本文就不多赘述了,算法具体实现的想法和思考可以看看代码的注释,这次的代码我注释的还是挺多的了。LZW压缩算法的C++实现//=========================================LZW...原创 2019-07-26 23:03:55 · 1238 阅读 · 1 评论 -
快速排序C++
单趟排序两种交换方法,一种是找到一个元素移动一个元素到对面,另外一种是找到左元素和找到右元素后交换。为什么快排每次必须从右边开始的原因见注释。找一个元素换一个元素#include <iostream>//单趟排序int partition(int a[],int low,int high) { int key = a[low];//通常将左边第一个元素作为基准元素key ...原创 2019-08-05 23:01:28 · 433 阅读 · 0 评论 -
优先级队列--大根堆和小根堆
概述与FIFO的普通队列不同,在优先级队列中,元素出队顺序是由元素的优先级决定。比如大根堆是最大的元素先出队,小根堆是最小的元素先出队。堆是实现优先级队列效率很高的数据结构(当然我们也可以使用无序的线性表或者有序链表来实现,但是它们的删除、插入的时间复杂度至少有一个是O(n))。堆是一棵完全二叉树,这样就保证了底层存储的数组拥有很高的空间利用率。无论是大根堆还是小根堆,它们的插入和删除的复杂性...原创 2019-08-10 16:43:41 · 3507 阅读 · 0 评论 -
基于优先队列的应用--堆排序和霍夫曼树
堆排序堆排序就是将数组堆化,大根堆小根堆的根元素永远是最大或者最小的,于是我们取根元素然后调整堆,继续一下次的堆化,不断重复直到取完(或者只剩下根元素)。此处采用大根堆,将根元素也就是数组的[0]元素不断放到数组的末尾。大根堆的实现可见大小根堆的实现。#pragma once//=============================基于根堆的应用--堆排序===============...原创 2019-08-10 17:01:36 · 291 阅读 · 0 评论 -
平衡搜索树--AVL树的实现
平衡搜索树在原来的二叉搜索树我们提到,如果对普通的二叉搜索树连续有序地插入会导致二叉搜索树退化成链表,操作复杂的从O(log N)退化到O(N)。而AVL树和红黑树这些平衡二叉树就是避免这种最坏情况的出现,对左右孩子子树高度差大于2时进行重新调整,让搜索树始终保持一个健康的状态,保证相关操作都在O(log N)。同时关于STL,哈希表<unordered_map>(原为<has...原创 2019-08-23 23:09:11 · 301 阅读 · 0 评论 -
二叉树的实现C++实现
树的基本性质定义:1.一棵树t是一个非空的有限元素的集合,其中一个元素为根(root),其余的元素(如果有的话)组成t的子树(subtree)。2.一棵树的高度(height)或深度(depth)是树中级的个数。3.一个元素的度(degree of an element)是指其孩子的个数,叶节点的度为0。一棵树的度(degree of a tree)是指其元素的度的最大值。二叉树定义...原创 2019-08-04 12:05:16 · 783 阅读 · 0 评论 -
基于队列的应用--列车重排问题、电路布线问题、图元识别问题以及工厂仿真
本文使用到的队列的实现。列车重排问题、电路布线问题、图元识别问题,在以前都用过栈的数据结构来实现过(基于栈的应用–列车重拍问题、迷宫老鼠问题)。本文采用队列的实现,改变一些问题要求,但吸收、采用了上次同类型问题中的算法思想。列车车厢重排问题相较于使用栈来实现车厢重拍列的算法,主要区别有:缓冲轨道的改变,在栈实现中,我们要求缓冲轨道先进后出(FILO),而在本文中,我们要求其先进先出(FIF...原创 2019-07-22 13:09:45 · 588 阅读 · 0 评论 -
线性表--队列的数组实现
定义和应用队列(queue)是一个线性表,其插入和删除分别在表的不同端进行。它是一种先进先出(FIFO)的线性表,插入元素的一端称为队尾(bakc或者rear),删除元素的一段叫作队首(front)。以数组来实现,需要考虑空间的利用率。如果采用类似数组和栈一般的映射公式location(i)=i,那么每次删除数组前端(队首)元素需要将数组整体左移一位,显然效率低下。考虑新的映射公式locati...原创 2019-07-22 12:16:28 · 323 阅读 · 0 评论 -
线性表--数组/vector描述
一个线性表(linearList)可以用一个抽象数据类型(ADT)来说明。抽象数据类型linearList{实例 有限个元素的有序集合操作 empty():若表空,返回true size():返回表中元素的个数 get(index):返回线性表中索引为index的元素 indexOf(x):返回线性表中第一次出现的x的索引。若x不存在,则返回-1 er...原创 2019-05-27 23:36:01 · 432 阅读 · 0 评论 -
以一维数组存储的矩阵C++语言描述(包括稀疏矩阵三元组的表达),实现矩阵的基本运算(加减乘)及矩阵类的拷贝控制
行主映射:将矩阵依此从每一行的索引从左至右连续编号,将二维矩阵的索引映射为一维数组。列主映射:将矩阵依此从每一列的索引从上至下连续编号,将二维矩阵的索引映射为一维数组。本文的多种矩阵均采用行主映射,使用一维数组来表达多种矩阵。例如按照常规对二维矩阵进行描述的C++二维数组中,矩阵元素M(3,5)对应二维数组Array[2][4]。而采用一维映射后,该元素对应一维数组的Array[3*矩阵的列+...原创 2019-06-06 17:16:59 · 1833 阅读 · 0 评论 -
线性表--单向链表的C++语言描述,实现链表的基本操作以及拷贝控制
线性表可以用数组和链表来表示。数组表示见线性表的数组/vector描述。在链式描述中,线性表的元素在内存中的存储位置是随机的。每个元素都有一个明确的指针或链(指针和链是一个意思)指向线性表的下一个元素的位置(即地址)。对比元素连续存储的数组描述:内存比较:我们希望,当数组满时,数组长度加倍,当数组空间占有率不足25%时长度减半(STL的vector则是按照乘数因子1.5来倍增,并且和我们定义...原创 2019-06-02 00:22:34 · 539 阅读 · 0 评论 -
线性表--带有头节点的双向循环链表C++语言描述,实现链表的基本操作以及拷贝控制
链表描述的基本知识和单向链表的描述见线性表–单向链表。使用头节点的循环链表可以使得链表的一些操作程序更加简洁,运行速度更快。例如我们的index_of操作,就可以将要查找的元素放入头节点的数据域,在循环条件中仅仅需要判断while(currentNode->element!=_given_element)一个表达式,不需要像前面我们实现的未带有头节点的单向链表一样进行while(curre...原创 2019-06-02 10:15:43 · 545 阅读 · 0 评论 -
线性表的应用--箱子排序(桶排序)和基数排序
箱子排序箱子排序的思想简单而言就是分配range(基数,比如[0,9]就是基数为10,range=10)个箱子,然后把每个相同的元素放入一个箱子,最后把箱子连接起来得到新的有序的线性表。箱子排序是一种稳定排序,它不会改变排序前线性表中相同元素的相对次序。虽然可以用数组来表示箱子,但是涉及到箱子的合并(链表的合并操作为Θ(1)),我们使用单向链表来实现使其更高效。单向链表的定义实现见线性表–单向...原创 2019-06-02 11:28:14 · 1270 阅读 · 0 评论 -
深入浅出重新理解递归思想,并重新思考经典递归算法(全排列以及汉诺塔)问题。
1.理解递归通过数学的分段函数f(n)={1n≤1 n∗f(n−1)n>1f(n) = \begin{cases} 1 & n \leq1 \\\ n*f(n-1) & n \gt 1\end{cases}f(n)={1 n∗f(n−1)n≤1n>1或者数学归纳法,都能很好理解到递归的思想。因此,所有的递归函...原创 2019-06-20 12:59:46 · 443 阅读 · 0 评论 -
线性表--栈的数组实现和链表实现
把线性表的插入和删除操作限制在同一端进行就得到栈数据结构,因此栈是一个后进先出(LIFO)的数据结构。抽象数据类型ADT#pragma oncetemplate <typename T>class stackADT{public: virtual ~stackADT(){ }//虚析构函数 virtual bool empty() const = 0;//栈空返回true...原创 2019-07-15 23:32:26 · 420 阅读 · 0 评论 -
基于栈的应用--列车车厢重排问题、开关盒布线问题、离线等价类问题、迷宫老鼠(深度优先、回溯)问题的算法实现
文章所用的栈stackArray见栈的数组实现。列车车厢重排问题一列货运列车有n节车厢,将原来的乱序列车车厢如[581742963]通过输入轨道后,在中转站中经过中转调度,将其有序地驶出输出轨道,如[987654321]。中转站有一个输入轨道,一个输出轨道和k个缓冲轨道。对缓冲轨道的要求为:缓冲轨道上面的车厢序号小于下面的车厢序号,即序号顶部往下为递增的;编号为u的车厢应该进入的缓冲轨道,其顶...原创 2019-07-16 00:01:36 · 954 阅读 · 0 评论 -
二叉搜索树
二叉搜索树二叉搜索树是一颗二叉树,可能为空。一棵非空的二叉搜索树满足以下特征:1).每个元素有一个关键字,并且任意两个元素的关键字都不同;因此,所有的关键字都是唯一的(如果有重复的话,这样的二叉树称为有重复的二叉搜索树)。2).在根节点的左子树中,元素的关键字(如果有的话)都小于根节点的关键字。3).在根节点的右子树中,元素的关键字(如果有的话)都大于根节点的关键字。4).根节点的左右子...原创 2019-08-13 12:03:48 · 465 阅读 · 0 评论