由于图片看不了,大家可以看这个百度云笔记,我看完大话数据结构整理的,里面有些内容我还不太明白,等过段时间还需要仔细回顾回顾。点击打开链接
一.数据及数据结构的基本概念
- 数据结构是一门研究非数值计算的程序设计问题中的操作对象,以及他们之间的关系和操作等相关问题的学科。
- 数据:符号集合
- 数据元素:组成数据有一定意义的基本单位,也被称作记录。
- 数据项:一个数据元素可以由多个数据项组成,是数据不可分割的最小单位。
- 数据对象:是性质相同的数据元素的集合,是数据的子集。
2.数据结构:数据元素的特定关系。
- 逻辑结构:数据元素之间的相关关系
线性结构:数据元素之间是一对一的关系
2.物理结构:数据的逻辑结构在计算机中的
存储形式
3.数据类型:是指一组性质相同的值的集合,以及此集合上的一些操作。
原子类型:不可以分割的基本类型:整形。。。
结构类型:若干个类型组合,可以分割,比如:数组
二、算法
指令的有限序列,每条指令表示一个或多个操作。
1.算法的基本特性:
输入、输出、有穷性、确定性、可行性
2.算法的设计要求:
正确性、可读性、健壮性、高效率和低存储量
事后统计方法(不科学,不精确)
3.事前估算方法:时间复杂度,用O()表示——大O记法
空间复杂度(用空间来换取时间,一般不怎么用)
O(1):常数阶;O(n):线性阶;O(n2):平方阶
三、线性表
线性表(List):零个或多个数据元素的有限序列。
1.顺序存储结构:一段地址连续存储空间
数组的长度和线性表的长度区别:数组长度是存放线性表的存储空间的长度,固定的;线性表的长度是线性表中数据元素的个数,随插入删除,长度改变。
存取是O(1):知道地址马上可以取到
插入、删除:O(n):一个个比较
注:写代码时要注意:程序的健壮性,插入地址适不适合,
2.链式存储结构
一个节点:
数据域
指针域
链表的第一个节点的存储位置叫头指针;链表的最后一个节点指针为"NULL";
注:在单链表的
第一个节点前附设一个节点,——头结点;
- 读取:不知道第i个节点在哪,需要从头开始遍历
- 插入和删除:
都是由两部分组成:1.遍历查找第i个节点;2.插入和删除节点
3.静态链表
用数组描述的链表(为了不使用指针)
数组中每个元素都有两个值,一个代表数据,一个代表游标(相当于指针)——不一定用,但是思想比较巧、
注意游标
4.循环链表
将单链表中的终端节点的只诊断由空指针改为指向头结点
- 注:循环链表和单链表的区别:在于循环的判断条件上,原来是判断p->next是否为空,现在是p->next是否等于投节点(头结点是那个没有数据的节点)
- 将两个循环链表合并,需要删掉一个头结点
5.双向链表——用空间来换时间
一个节点包括:
数据部分;
指向前驱节点的指针;
指向后继节点的指针。
注:在插入和删除的时候需要改变两个指针变量
顺序:先搞定s的前驱和后继,再搞定后节点的前驱,最后前节点的后继
顺序:顺时针
free(p);
四、栈与队列
1.栈——后进先出(Last In First Out)的线性表(LIFO结构)
存一个元素的时候,top为0,所以空栈的时候top为-1,用-1来判断栈是否为空。
- 两个栈可以共享空间:数据类型要一样
栈1为空时,top=-1;栈2为空时,top=n;
栈1为满时,top=n-1;栈2为满时,top=0;
当在中间栈1和栈2相遇时,top1+1=top2;
栈的链式结构,不需要有节点,应用在递归上(处理器内部自身会进行的):四则运算表达式P105
2.迭代和递归的区别:
迭代:循环结构,不需要反复调用函数和占用额外的内存;
递归:选择结构,使程序结构清晰简洁,但是大量的递归调用会建立函数的副本,会消耗 大量的时间和内存。
3.队列
- 队列:数据块、头指针、尾指针
- 循环队列(顺序队列):
当front=rear时就不能判断是空队列还是满队列,所以需要外加1.一个标示flag,flag=0,队列为空;flag=1,队列为满。方法二:队列满时,仍然保留一个空位。
对第二种情况:对满的条件是:(rear+1)%QueueSize==front——会从尾部出来,再从头部进去。
计算队列长度:(rear-front+QueueSizde)%QueueSize
注:在进行入队或出对的情况下也要考虑%QueueSize
Q->rear=(Q->rear+1)%MAXSIZE;
- 链式存储的队列,需要有头结点
但是若链表除头结点外只剩一个元素,则需要将rear指向头节点
从a1里面正式放数据元素。
- 循环队列是事先申请好空间的,使用期间不释放;而链队列可以申请和释放空间,但需要消耗一点时间。建议:在可以确定队列长队最大值的情况下,使用循环;无法确定,使用链队列。
五、串(????匹配算法不明白)
串的存储结构也有顺序存储和链式存储,在链式存储中一个节点对应一个字符,会造成很大的浪费,所以会考虑放多个字符,未被占满时,用非串值字符补全。但串的链式存储除了在连接串与串操作时有一定的方便之外,总的来说不如顺序存储灵活,性能也不好。
1.KMP模式匹配算法
避免重复遍历的情况,需要计算一个
子串next数组:
其中MAX的计算,从头开始,尾部对应相应的几个,但是不包括第j位
注:字符不相等是将j=next[j];回溯
KMP算法仅当模式与主串之间存在许多“部分匹配”的情况下才体现出优势,否则和不同的区别不大。
2.改进的KMP模式匹配算法
六、树
- 节点拥有的子树称为节点的度。度=0,是叶节点或终端节点。
2.节点的层次是从根开始定义的,根为第一层。
树的深度或高度:树中节点的最大层次
3.森林是m课互不相交的树的集合。
- 双亲表示法
或
兄弟域
根据自己的需求可以灵活变动,看需要那么地址。
2.孩子表示法:多重链表
每个节点有多个指针域,每个指针域指向一棵子树的根节点
->
专门取一个位置来存储节点指针域的个数,但是这时间上额损耗大。
将双亲表示法和孩子表示法综合的:
3.孩子兄弟表示法:把一棵复杂的树变成了一棵二叉树
4.二叉树:
- 二叉树的特点:树中某个节点只有一棵子树,需要区分是左子树还是右子树(树是不用区分的)
- 二叉树的性质
性质3:对任何一棵二叉树,如果其终端节点数为n0,度为2的节点数为n2,则n0=n2+1。
性质5:I.如果i=1,则节点i是二叉树的根,无双亲;如果i>1,则其双亲是节点[i/2];
II.如果2i=n,节点i有左子树,如果2i>n,则节点没有左子树;
III.如果2i+1=n,节点i有右子树,如果2i+1=n,则没有。
- 二叉树的存储结构
链表:数据域,指针域,
- 二叉树的遍历方式:都是根据根节点来判断的。
为什么需要这么多形式的遍历:因为计算机只有循环、判断等方式,所以需要通过遍历方式把树中的节点变成有意义的线性序列。
- 算法
只改变打印数据的位置。
得到唯一的二叉树:都需要中序遍历序列,前序和后序需要一个即可。
- 线索二叉树
节点有左子树或右子树,那么lchild,rchild里面存放孩子的地址;如果没有孩子,则lchild,rchild存放的是要跳转的地址(即前驱或后继的地址,这两个地址称为线索);通过ltag,rtag来区分是什么地址(0,1标志的内存空间比地址空间小,所以用他们来做标识符)
线索二叉树就是把一个二叉树变成了一个双向链表。线索化的实质:将二叉链表中的空指针改为指向前驱或后继的线索。
这个程序不太懂??????
5.树、森林、二叉树的转换
- 树——>二叉树:将兄弟连起来,断开除长子外的孩子连线,兄弟的变成右子树。
- 森林——>二叉树:先每个树变二叉树;第一个二叉树不动,后面的依次作为前一个二叉树的根节点的右子树插入。
6.赫夫曼树及应用
节点到节点的路径,经过的连线。如果有权值,就用权值*路径。权值路径最小的就是赫夫曼树。
描述:把每个点的权值从小到大排列,2个最小的放下面,和成一个值再重新选两个最小的,重复。
N1=15;N2=30;N3=60;
- 赫夫曼编码:把权值变成0,1