数据结构 ——c++实现(知识点集合)
某不知名学狗的复习记录,包含数据结构基本概念,线性表,栈、队列、递归,串、数组、广义表和树和森林内容整理。主要整理了知识点,代码较少。
第一章 绪论
1.1(算法+数据结构) = 程序
这个括号是体现面向对象的观点
1.2 数据结构的基本概念
数据结构的定义
数据,是信息的载体,是描述客观事物的数、字符、图形、图像、声音以及所有能输入计算机中并被计算机程序是别的和处理的符号的集合。
数据在特定的情况下可以是数字,或者是字符,数据对象就是数据的子集。例如一个特定的,解方程组的程序,它处理的是数据对象是整数和实数。无理数,复数也是数据对象,也就是数据的子集,但是在这个问题中,数据对象并不是他们。
数据的基本单位是数据元素,数据元素由若干数据项组成,数据项是最小单位。例如线性表由数组储存,每一个数组元素就可以称作一个数据元素。如果说我这个数组是int型,那么数据项就是一个integer。若是一个结构体数组,那么数据项就有多个。
数据结构不仅要描述数据,还要描述数据元素与数据元素之间的相互关系。 可分为2大类,也可分为4大类。
1. 线性结构,非线性结构
2. 集合,线性,树,图 数据逻辑结构指数据元素之间的逻辑关系。(以上所说的就是面向用户的逻辑结构) 数据结构(数据元素的表示和元素之间的关系)在计算机中的物理储存方式称为存储结构/物理结构。 算法设计基于逻辑结构,算法实现基于物理结构。
数据结构是数据元素的组织形式。
1.3算法性能与复杂度
1.3.1算法的定义 算法:一个用于实现某个特定任务的有穷指令集,这些指令规定里一个运算序列。具有以下特征
1. 输入性
2. 输出型
3. 确定性
4. 有穷性
5. 有效性
1.3.2 算法的性能标准
正确性
可用性
可读性
效率
健壮性
1.3.3算法复杂度
时间复杂度 循环嵌套 相乘 循环并列 相加
空间复杂度 空间复杂度,是算法所需的存储空间的量度。记作S(n) = O(f(n))。这里不是指程序本身所需要的存储空间,而是指解题过程中所需要的辅助空间。
算法效率的度量一般采用事前估计和后期测试两种方法。常采用事前估计。
第三章 线性表
顺序表 顺序表中任意两个逻辑相邻的数据元素在物理存储上也必然相邻。
顺序表的插入与删除的时间复杂度是On,删除也可以是O(1),就是把最后一个元素放到被删除的位置。
双向链表的删除就是把要删的节点的前驱节点的后指针指向要删的节点的后节点。 插入的时候,先把新节点挂上去,然后再进行前后处理。 静态链表
静态链表利用结构体数组作为链表的模拟,用下标作为指针。
head->next指向已经申请的空间头结点,avil指向第一个可利用的空间(没有存东西的节点)的指针。
第四章 栈、队列与递归
栈
允许插入删除的地方叫栈顶,另外一端叫栈底。 top初值=-1。 注意pop和top函数的区别
一个是要pop要后退,一个是单单取元素。 入栈先++top,再入元素,出栈先出元素再–。
可以共享栈。那么栈满条件为两指针相遇。此时,top1= =top2-1。定义No表示栈号,No= =1为栈1,No= =2为栈2。入栈1操作elem[++top1]=e;入栈2elem[–top2]=e;出栈相反。
表达式求值
关于栈的应用,一个是后缀表达式求值,还有一个是中缀转后缀。 后缀表达式不改变数字顺序。
后缀表达式计算:数字入栈,符号不入,每进栈两个元素,将两个元素出栈计算,计算结果入栈。
中缀转后缀:左向右扫面中缀表达式,运算符入栈,数字不入,运算符按优先级运算,高进低出同级出,遇“(”一定入栈,遇“)”全部出栈。
出栈顺序题 字符按照顺序进栈 如果字符串靠后的字符先出栈了,这个字符的之前的字符按照倒序的相对顺序出栈。
出栈序列种类:(2n)!/(n!n!(n+1)) 后缀表达式的代码
队列
书中约定,front指向的是表头元素,rear是指向队尾元素的后一位置。 初始是front == rear =0
入队的时候先入队,再把rear++ 出队的时候先出队,再front++ 假溢出就是rear指针触底,但front指针不顶头。
循环队列
循环队列满条件:(rear+1)%maxsize= =front; 空条件:rear= =front
求循环队列长度:(rear-front+MaxSize)%MaxSize;+maxsize保证是个正数
循环队列运用取余maxsize达到循环的目的。
但是队满和对空的条件会重合,所以采用少一个空间的办法,即当(rear+1)%maxsize = =front时,队满。
也可以采用增加数据成员length表示当前队列长度,或者增加tag,当rear==front时利用tag来区分。
i,front,rear指下一个:(i/front/rear+1)%maxsize 递归
第五章 串、数组、广义表
5.1字符串
串中任意多个连续的字符组成的子序列称为子串。字串首字符位置即子串在串中位置。 String相关函数 int strlen(char*)求长度 char* strcpy(char* str1, charstr2)把s2里的值复制到s1
char strcat (char* st1, char* str2)字符串连接 char* strcmp(str1, str2)
按asci码进行比较 ,< -1 ,= 0, >1 char* strchr(char *str,char
ch)串中字符定位,若有,则返回第一次出现的位置 substr(str,指定位置int,指定长度int)
从指定位置开始复制字符串,有指定长度 ascii码 大写字母在前,ascii码大,小写字母在后ascii码小
5.1.4模式匹配
模式匹配,就是类似于百度搜关键字。你有一个模式串,去在主串里找模式串的匹配位置。主串叫ob,模式串叫pat,找到了返回主串里的具体序号,没找到返回-1。
有两种算法,一个是Brute-Force算法,一个是KMP算法。
暴力算法
BF算法就是暴力算法。把模式串第一个字符和主串第一个字符对齐,一个个看。一样就结束,不一样就还是拿模式串第一个去怼主串第二个,以此类推暴力找。非常朴素,非常暴力。
KMP算法就是聪明算法,不用每次都倒回去重新开始。想要快速入手KMP请看这个视频,真的很不错:
kmp就是照样那么对着去比,但是在模式串的任何一位出错的时候,会有一个对应的失效函数,告诉你下一步该拿模式串的第几个去和主串的这一位比。打个比方,你的模式串有5位,那就有5个失效函数。设模式串为t,主串为s,在si和tk比较的时候,这俩不匹配了,不要担心,失效函数会告诉你接下来拿t的第几位去和si继续比。循环,直到匹配成功或者模式串比到头了。
所谓的失效函数就是下面说的next[],也就是我这里要说的f[j]。f[j]代表断点j前面的真子串的长度,也是下一个要和si比较的点。
说一下f[j]等于-1和等于0的情况,另外一种情况就是j前有真子串,呢么f[j] = 最大真子串的长度。
若j=0,fj = -1。意思就是第一次比较就崩了,那就和暴力算法一样呗,俩串都移下一位。这里等于-1是方便代码里的移动,也是一个标记,告诉我们下一步是拿s_(i+1)和t_0比较。
若fj =
0,则相当于j前面没有真子串,那么就拿s_i和t_0开始比较。至于为什么能跳这么远,中间难道没有合适的吗,我也不太清楚,这个实在是有点难。
根据f[j]求f[j+1],分两种情况。
当发现正好真子串没有断,比如j的真子串是n位,j+1是n+1,那就f[j+1] = f[j]+1 = n+1
若是发现真子串断了,那就要在前面的下标为0~j的字符里寻找一对新的真子串,使得后缀等于前缀,然后再移动。寻找这个新的真子串的过程可以等效于一个模式匹配:
直到找到一个tm ~ tj = t0~ tj-m。 在这个找的过程中,若是最后一个不等,然后把模式串向右移动的
过程就是在缩小搜查范围。这是算法层面的,做题还是眼睛好使。 复杂度O((m-n+1)*n) KMP
KMP数组从0开始,不能用网上的方法从1开始。 复杂度O(m+n) KMP的具体方法
1. 发现数组第X位不匹配
2. 寻找最长公共部分(小于X-1)
3. 移动 Next(失效函数)怎么算
优化的KMP 优化的next-1 0 -1 0 -1 3 1 0 -1 0 -1 3
不等为本身的kmp值,相等一直向前比比到不能比,值为最后一个比成功的kmp值。
5.2 数组
行优先&列优先的寻址方式 对于a[m][n] 首地址为p 数据类型存储所需要的空间为s
行优先:loc(i,j)=p+(i*n+j)s
列优先:loc(i,j)=p+(i+jm)s
对于以上的公式,愣记是很容易忘记的。
数组在内存中的存储方式是线性的,顺序的。就是一个个排下来的。这种二维数组在内存里面还是按照顺序表的方式存的。 假设数组a[m-1][n-1](等同于mn的矩阵,以下类似表达同一意思)行主序就是先储存第0行的n个元素,列主序就是先储存第0列的m个元素。
一般这种题给你个二维数组或者一个三维数组,然后告诉你首地址,让你去求一个特定的地址。思路就是把二维数组看成一张纸,把三维数组看成一本书。
二维数组假设以行主序存储,那么a[0][0n-1]就是一行有n个字,也就是有n列。a[0m-1][0]就是有m行。
三维数组就不是单单的行或列主序了,是规定下标从左到右还是从右到左储存。也就是规定哪个下标是字数,行数,页数。一般变的最快的是字数,然后是行,再是页。
那么看成a[m-1][n-1][k-1]就是1本有着m页的,每页有n行,每行里有k个字的书。
做题就感觉像查字典 理解了稍微画一下大概位置一算就有了,就是注意一些细节上面可能会出问题,比如序号啥的,还有一行到底有几个,一页到底有几行。
对于二维数组或多维数组,分为行优先和列优先两种存储方式。
5.3 稀松矩阵
三元组 稀松矩阵中的非零元素可以用<row,col value>表示,组成一张线性表。
三元组的矩阵转置就是把row col互换,再排序。 实质上就是排原来的col,循环cols遍找就完事,然后存到新的矩阵的第一行。
十字链表
是用数条行链表与列链表来表示一个矩阵。若是该行或该列有非零元素,则存到十字链表的行指针或列指针数组。若是某行或列元素全为0,则存个空指针。
结点有5个数据项:行,列,值,right指针,down指针 十字链表数据项也有5个: 行指针数组,列指针数组,行数,列数,非零元个数。
广义表 广义表,是由n个表元素,组成的有限序列,其中表元素a可以是一个数据元素(称作单元素或原子),或是一个表(子表),记作LS。
第一个元素称为表头,剩下的元素组成的表称为表尾。 表的长度:表中的元素个数 表的深度:有以下三种情况
1.表中元素的最大深度+1
2.空表为1
3.若表中元素是原子元素,则这个元素的深度为0 链式存储:广义表一般用链式存储表示。结点由三个数据域组成:
1. tag0/1/2 0代表专用表头结点,1代表原子结点,2代表字表结点。
2. ref/data/hlink 与上面0-2一一对应,分别为引用次数,关键字,指向子表表头的指针
3. tlink 指向下一个结点的指针。 广义表表示树
广义表表示多项式 var变量 num 值 第一个系数 第二个指数 ptr 指针 不多说,直接例子
第六章 树&二叉树 二叉树
二叉树性质:
1. 二叉树有n个结点,则分支数为n-1
2. 若二叉树高度为h,则二叉树最少有h个结点,最多有2^h -1个结点(满二叉树)*完全二叉树
3. 有n个结点的二叉树高度最大值为n,最小值为log2(n+1)
树的术语:
结点:数据元素+指向子树根的分支称为一个结点。 结点的度:一个结点的的子树数目。 终端结点:也叫叶子结点,最远的,没子树的。 非终端结点:分支结点。 树的度:最大的度称为树的度 树的深度 = 树的高度
度为2的结点个数=度为0个数-1 二叉树的存储方式
顺序存储
- 利用数组
- 完全二叉树适用
- 任意结点在i位置,则左孩子在2i+1;右孩子在2i+2 链表存储
1.1个结点包含2个指针域+1个数据
2.若有n个结点与n-1个分支,则有n+1个空指针(共2n个指针) 遍历二叉树 先序遍历(前缀) 1) 先访问根结点 2) 再先序遍历左子树 3) 再先序遍历右子树 中序遍历(中缀) 1) 先中序遍历左子树 2) 再访问根结点 3) 再中序遍历右子树
后序遍历(后缀) 1) 先后序遍历左子树 2) 再后序遍历右子树 3) 再访问根结点 层序遍历
每一层从左到右依次遍历,利用队列来进行遍历 1) 初始化队列,并让根结点入队 2)
当队列非空时,取出队头结点p,转步骤3,如果队列为空,则结束遍历。 3)
访问p结点,如果他有左孩子,则入队,如果他有右孩子,则入队(先左后右) 4) 重复23,直到队列为空
线索二叉树写出遍历序列有孩子即Tag=0,指针指孩子,Tag=1指遍历序列的前(后)元素线索化后最多两个空指针
先序(后序)加中序可得唯一树,先序加后序不行。先序(后序)确定根,中序确定子树
堆
- 数组存储;完全二叉树;
- 最大堆:最大的元素在根结点,且每个非终端结点都大于孩子。
- 最小堆:最小的元素在根结点,且每个非终端结点都小于孩子。
堆的构造:由非堆序列转成堆序列 排序的核心代码是 while(i>=0) { filterdown(i); i--; }
filterdown具体就是拿分支结点和子结点进行比较,不符合就交换,但是要交换到底,所以后面的向下沉就是进一步符合标准地往下沉。
堆的插入: filterup 因为堆一定是完全二叉树,所以插入的元素一定是在最后。
那么就是比较该值与其双亲结点,符合就oki,不符合就交换一路向上,那就是j = i i= (j-1)/2。
删除元素: 一般是把数组的最后一个元素补到删除的地方,然后就很大概率变成了一个非堆序列,呢么接着调用filterdown就行。
哈夫曼树
带权路径长度最小的树,称为哈夫曼树。 构造方法,把每个带权结点组成一个集合,然后在集合里合成大西瓜
也就是找俩最小的,合成一个二叉新树,再放回到集合里,循环,直到里面只有一棵树,那就是哈夫曼树。
哈夫曼树的数据成员有4个:叶结点字符信息,叶结点字符编码信息,叶结点个数,储存结点信息。
其中储存结点信息用静态链表实现,结点包含4个数据项:权值,双亲,左孩子,右孩子。-1表示无。
- n为叶子节点数目,则哈弗曼树共有2n-1个结点
- 哈夫曼树结点个数必为奇数。
- 哈夫曼树只有结点为0和2的。
- 哈夫曼树根节点值为所有权值求和 哈夫曼编码左分支0,右1
…继续学习!
4695



被折叠的 条评论
为什么被折叠?



