大话数据结构学习记录

本书的代码可以在http://cj723.cnblogs.com
第1章 数据结构绪论
1、数据结构:存在一种或多种特定关系的数据元素的集合。
2、程序设计=数据结构+算法
3、一些定义
数据:是描述客观事物的符号,可以输入到计算机中,也能被计算机程序处理。例如:整型,浮点型数据,MP3文件,图像,视频等等。
数据元素:组成数据的基本单位。在计算机中通常作为整体处理。例如人类的数据元素是人,畜类的数据元素是牛、马、羊等
数据项:一个数据元素可以由若干个数据项组成。例如人的数据项有眼、耳、鼻、嘴等,也可以有姓名、年龄、职业、籍贯等。另外,数据项是数据不可分割的最小单位。
数据对象:是性质相同的数据元素的集合,是数据的子集。性质相同就是指数据元素具有相同数量和类型的数据项。例如人都有姓名、年龄、性别等相同的数据项。在实际应用中,我们将数据对象简称为数据。
数据结构:数据元素之间的特定的关系称为结构。数据结构就是相互存在特定关系的数据元素的集合。
4、上面提到了数据结构就是相互存在一种或多种特定关系的数据元素的集合。那么,特定关系有哪些呢?按照视点的不同,可以将其分为逻辑结构和物理结构。
逻辑结构:数据对象中数据元素之间的相互关系。其分为四种:
1)集合结构:集合结构中的数据元素除了同一个集合外,它们之间没有其他关系。
在这里插入图片描述
2)线性结构:线性结构中的数据元素之间是1对1的关系。
在这里插入图片描述
3)树形结构:树形结构中的数据元素之间存在一种1对多的层次关系。
在这里插入图片描述
4)图形结构:数据元素是多对多的关系。
在这里插入图片描述
物理结构:也称存储结构,是指数据的逻辑结构在计算机中的存储形式。实际上,就是指如何把数据元素存储到存储器中。数据的存储结构应正确反映数据元素之间的逻辑关系,喝才是最为关键的,如何存储数据元素之间的逻辑关系,是实现物理结构的重点。
数据元素的存储形式有两种:顺序存储和链式存储。
1)顺序存储结构:把数据元素存在地址连续的存储单元里,其数据间的逻辑关系和物理关系是一致的。
在这里插入图片描述
2)链式存储结构:把数据放在任意的存储单元里,这组存储单元可以是连续的,也可以是不连续的。数据元素的存储关系并不能反映其逻辑关系,因此需要用一个指针存放数据元素的地址,这样通过地址就可以找到相关数据元素的位置。
在这里插入图片描述
小结:
在这里插入图片描述在这里插入图片描述
5、抽象数据类型
数据类型:指一组性质相同的值的集合及定义在此集合上的一些操作的总称。
数据类型的分类:(1)原子类型,例如整型,浮点型(2)结构类型,由若干个类型组合而成
抽象是指抽取出事物具有的普遍性的本质。对已有的数据类型抽象,就有了抽象数据类型。
在这里插入图片描述
第2章 算法
1、算法:是解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,并且每条指令表示成一个或多个操作。
2、算法的特性
(1)输入和输出
(2)有穷性:算法可在可接受的时间内执行完毕
(3)确定性
(4)可行性
3、算法设计的要求
(1)正确性
(2)可读性
(3)健壮性
(4)高效率,存储量低
在这里插入图片描述
第三章 线性表
1、线性表(list):0个或多个数据元素的有限序列。这里的序列,意思是元素之间有一定顺序的。若有多个元素存在,那么第一个元素没有前驱元素,最后一个没有后继元素。其次,元素的个数是有限的。
在这里插入图片描述
2、线性表的操作

在这里插入图片描述
在这里插入图片描述
3、线性表的顺序存储结构
线性表的顺序存储结构,指的是用一段地址连续的存储单元以此存储线性表的数据元素。
在这里插入图片描述
线性表中的元素的类型相同,这意味可以使用数组来实现顺序存储结构,而且数组的长度就是这个线性表的最大容量。这和占座位是一样的,假如定义了一个长度为10的数组,但是只有5个数据需要存放,那剩下的5个没有存储数据依然占据了内存。
所以,描述顺序存储结构需要三个属性:
—存储空间的起始位置:数组data,它的存储位置就是存储空间的存储位置
—线性表的最大存储容量:数组长度MAXSIZE
—线性表的当前长度:length
4、数据长度和线性表的长度区别
数组的长度:存放线性表的存储空间的长度,存储分配后一般不会改变。
线性表的长度:线性表中数据元素的个数,随着线性表的插入和删除操作的进行,这个量是会变化的。
为了保证线性表的所有元素都可以被存储,因此,线性表的长度至少应该小于等于数组的长度(线性表如果要进行插入的操作,那么数组的长度就要根据实际情况>线性表的长度,保证有空闲的位置)。
5、地址计算方法
C/C++的下标都是从0开始的。
在这里插入图片描述
内存中的地址,是有编号的。存储器中的每个存储单元都有自己的编号,这个编号称为地址。而且每一个数据元素因为它各自所占的存储单元的大小是不一样的,所以,假设占用的是c个存储单元,那么线性表中第i+1个数据元素的存储位置和第i个数据元素的存储位置满足以下关系(LOC表示获得存储位置的函数):
在这里插入图片描述
6、顺序存储结构的插入和删除
(1)获得元素操作
在这里插入图片描述
在这里插入图片描述
(2)插入操作
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
(3)删除
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
线性表的顺序存储结构,在存、读数据的时候,时间复杂度是O(1);而插入或者删除的时候,时间复杂度都是O(n)。这说明,线性表的顺序存储结构,适应元素个数不太多,存取数据的操作频繁的应用。它的优缺点如下:
在这里插入图片描述
7、线性表的链式存储结构
线性表的最大缺点就是插入和删除时需要移动大量元素,这显然很耗费时间。因此,线性表的链式存储结构的特点就是用一组任意的存储单元来存储数据元素,这组存储单元可以是连续的,也可以不是连续的。
在这里插入图片描述
对于线性表来说,有头有尾,链表也是这样。链表中的第一个节点的存储位置叫做头指针,那么最后一点的指针指向什么呢?通常它指向空,NULL。
在这里插入图片描述
有时为了方便操作,在单链表的第一个节点的前面设立一个节点,称为头节点。头节点的数据域可以不存储任何信息,也可以存储线性表的长度等信息,头节点的指针域存储指向第一个节点的指针。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
8、单链表的存取

3.6线性表的链式存储结构
头指针–》链表中第一个节点的存储位置叫做头指针
头节点–》单链表第一个节点前设置一个节点,称为头节点。可以存储线性表的特征信息等

typedef struct Node
{
ElemType data;
struct Node *next;
}Node;
typedef struct Node *LinkList;
3.7单链表的读取
获得链表第i个数据的算法思路:
1、声明一个节点p指向链表第一个结点,初始化j从1开始
2、当j<1时,就遍历链表,让p的指针向后移动,即p++;
3、若到链表末尾p为空,则说明第i个元素不存在
4、否则查找成功,返回节点p的数据。
实现代码如下所示:
Status GetElem(LinkList L,int i,ElemType *e)
{
int j;
LinkList p;
p=L->next;
j=1;
while(p && j<1)
{
p=p->next;
++j;
}
if (!p || j>1)
{
return error;
}
*e=p->data;
return ok;
}
3.8、单链表的插入和删除
插入:
s->next=p->next;
p->next=s;

删除:
p->next=q->next;

3.9 单链表的整表创建
顺序存储结构的创建,其实就是一个数组的初始化,即声明一个类型,大小相同的数组并赋值的过程。而单链表与顺序存储结构不同。单链表可以是链式存储结构的形式。它可以很散的分布,所以,对于这种动态的、分散的分布方式,我们需要动态分配内存。有两种实现方式:头插方式,尾插方式

3.10 单链表的整表删除
单链表的销毁:从头到尾逐个释放,假设当前元素的指针是q,free(q);

3.12 静态链表
数组描述的链表叫做静态链表,也叫游标实现法。
静态链表的大小是事先固定的,所以为了存储的数据不溢出,往往会声明较大的空间。

第六章 树

6.1 开场白
树是一种特殊的殊绝结构,就像现实生活中的树一样,有根,有树叉,有树叶。
6.2 树的定义
前面我们谈到的数据结构都是1对1的线性结构,在现实中,还有多对一的情况需要处理,这个时候就需要我们使用树这个结构了。
树是许多个节点(n>=0)的有限集。当节点数=0的时候,称为空树。当n>1的时候,除根节点之外的所有节点可以分为m个互不相交的有限集T1、T2、````Tm,其中,每一个集合本身又是一棵树,并且称为子树(subtree).
当n>0的时候,根节点是唯一的,不可能存在多个根节点。
当m>0的时候,子树的个数没有限制,但它们一定是不相交的。即一个根节点可以对应多个子节点,但是一个子节点不能对应多个根节点。
6.2.1 节点分类
树的节点包含一个数据元素以及若干指向其子树的分支。节点拥有的子树数目成为节点的度(degree)。度为0的节点称为叶节点(Leaf)或终端节点,度不为0的节点称为非终端节点或分支节点。除去根节点之外,分支节点也叫做内部节点。树的度是树内各节点的度的最大值。

6.2.2 节点之间的关系
节点的子树的根称为该节点的孩子(child),相应的,该节点称为孩子的双亲(parent)。同一个双亲的孩子之间互称为兄弟(sibling)。节点的祖先是从根到该节点所经分支上的所有节点。反之,以某节点为根的子树中的任一节点都称为该节点的子孙。

6.2.3 树的其他相关概念
节点的层次:从根开始定义,根为第一层,根的孩子为第二层。若某节点在第I层,其子树的根就在I+1层,其双亲在同一层的节点互为堂兄弟。树中节点的最大层次称为树的深度(Depth)或高度。

如果将树中节点的各子树看成从左到右是有次序的,不能互换的,则称该树为有序树,否则为无序树。

森林是m棵互不相交的树的集合。对于树中的每个节点而言,其子树的集合就是森林。

6.3 树的抽象数据类型
ADT tree
DATA
树是由一个根节点和若干棵子树构成。树中的节点具有相同数据类型及层次关系。
operation
InitTree(×T) 构造空树
DestroyTree(×T) 销毁树
CreateTree(*T,definition)按照definition中给出的树的定义来构造树
ClearTree(*T) 若树存在,则将树晴空为空树
TreeEmpty(T) 若T为空树,返回true,若不是,返回false
TreeDepth(T):返回树的深度
Root(T):返回树的根节点
Value(T,cur_e):cur_e是一个节点,返回此点的值
Assign(T,cur_e,value):给树的节点cur_e赋值value
Parent(T,cur_e):若cur_e是树的非根节点,则返回他的双亲,否则返回空
Leftchild(T,cur_e):若cur_e是树的非叶节点,则返回它的最左的子孩子,否则返回空
RightSibling(T,cur_e):若cur_e有右兄弟,返回他的右兄弟,否则返回空
InsertChild(*T,*p,i,c):其中p指向的树T的某个节点,i为所指节点p的度加1,非空树c与T不相交,操作结果为插入c为树T中p指节点的第i棵树
DeleteChild(*T,*p,i):其中p指向树T的某个节点,i为所指节点p的度,操作结果为删除T中的p所指节点的第i’棵子树
endADT

6.4 树的存储结构
前面我们介绍了顺序存储结构和链式存储结构,充分利用这两种的结构的特点,完全可以实现对树的存储结构的表示。我们这里要介绍三种不同的表示方法:双亲表示法,孩子表示法,孩子兄弟表示法。

6.4.1双亲表示法
我们假设以一组连续的空间来存储树的节点,同时在每个节点中,附设一个指示器指示其双亲节点到链表的位置。对于这样一个结构体,我们可以知道它由两部分组成:data和parent。data是数据域,存储节点的数据信息,parent是指针域,存储该节点的双亲在数组中的下标。
在这里插入图片描述
在这里插入图片描述
对于这样的表示方法的缺点是:要知道节点的孩子是什么需要遍历整个结构才行。
改进方法就是,增加一个长子域,用来记录最左边的子节点。
在这里插入图片描述
另外一个问题就是,我们很关注兄弟之间的关系,双亲表示法无法体现这样的关系,那我们怎么办?可以增加一个右兄弟域来体现兄弟关系,也就是说,每一个节点如果它存在右兄弟,则记录下右兄弟的下标。同样的,如果右兄弟不存在,则赋值为-1.如下表所示
在这里插入图片描述
但如果节点的孩子很多,超过了两个。我们又关注节点的双亲,又关注节点的孩子、还关注节点的兄弟,而且对时间遍历要求还比较高,那么我们还可以把此结构扩展为有双亲域、长子域、再有右兄弟域。存储结构的设计是一个非常灵活的过程。一个存储结构设计的是否合理,取决于基于该存储结构的运算是否适合,是否方便,时间复杂度好不好等。

6.4.2 孩子表示法
由于树中的每个节点可能有多棵子树,可以考虑用多重链表,即每个节点有多个指针域,亲戚中每个指针指向一棵子树 的根节点,我们把这种方法叫做多重链表表示方法。
不过,树的每个节点的度,也就是它的孩子个数是不同的,所以可以设计两种方案来解决。
(1)指针域的个数=树的度,树的度就是树的各个节点度的最大值
在这里插入图片描述在这里插入图片描述
这种方法对于树中的各节点的度相差很大时,显然是很浪费空间的。因为有很多的节点,它的指针域是空的。既然这样,那就按需分配空间。
(2)每个节点的指针域的个数=该节点的度在这里插入图片描述
这种方法克服了空间浪费的情况,但是由于各个节点的链表是不相同的结构,加上要维护节点的度的数值,在运算上可能会带来较大的损耗。
那么我们应该如何去做才能既可以减少空指针的浪费又能使节点结构相同呢?我们在遍历一整棵树的时候,把每个节点放到一个顺醋存储结构的数组中是合理的,但每个节点的孩子有多少是不确定的,所以我们再对每个节点的孩子建立一个单链表体现它们的关系。
这就是我们要表达的孩子表示法。具体办法是,把每个节点的孩子节点排列起来,以单链表作为存储结构。
在这里插入图片描述
在这里插入图片描述
这样的结构对于进行查找某个节点的某个孩子,或者找某个节点的兄弟,只需要查找这个节点的孩子单链表即可。对于遍历整棵树也是很方便的,对头节点的数组循环即可。
但是存在一个问题,需要遍历一整棵树才可以直到某个节点的双亲是谁。因此,将双亲法和孩子表示法综合一下,便有如下所示的结构:
双亲孩子表示法,算是孩子表示法的改进
上述的结构叫做双亲孩子表示法,算是孩子表示法的改进。
6.4.3 孩子兄弟表示法
对于任意一棵树,它的节点的第一个孩子如果存在就是唯一的,它的右兄弟如果存在也是唯一的。因此,我们设置两个指针,分别指向该节点的第一个孩子和此节点的右兄弟。
节点结构吐下所示:
在这里插入图片描述
在这里插入图片描述
这种表示法,给查找某个节点的某个孩子带来了方便,只需要通过firstchild找到该节点的长子,然后再通过长子节点的rightsib找到它的二弟,接着一直找下去。当然,如果想要找到某个节点的双亲,这个方法就需要改进了,改进的方法就是添加一个双亲的指针域来解决款速查找双亲的问题。
在这里插入图片描述

6.5 二叉树
二叉树就是每个节点的子树个数<=2的有序树。
6.5.1 二叉树的特点
(1)每个节点最多有两棵树,所以二叉树中不存在度>2的节点。
(2)左子树和右子树是有顺序的,次序不能颠倒。
(3)即使树中某节点只有一颗子树,也要区分它是左子树还是右子树。
二叉树的五种形态:
(1)空二叉树
(2)只有一个根节点
(3)根节点只有左子树
(4)根节点只有右子树
(5)根节点既有左子树又有右子树
6.5.2 特殊二叉树
(1)斜树:分为左斜树和右斜树。所有的节点都只有左子树的二叉树叫左斜树,反之,右斜树。
斜树其实也算一种特殊的线性表。
(2)满二叉树
所有的分支节点都存在左子树和右子树,并且所有叶子都在同一层----》满二叉树
在这里插入图片描述
(3)完全二叉树
对一棵具有n个节点的二叉树按层序编号,如果编号为i的节点与同样深度的满二叉树中编号为i的节点在二叉树中的位置完全相同,则这棵二叉树称为完全二叉树。
在这里插入图片描述
这两者之间的关系如下所示:
在这里插入图片描述
下面的这三种树也是完全二叉树:
在这里插入图片描述
6.6 二叉树的性质
性质1:在二叉树的第i层上至多有2的i-1次方个节点
性质2:深度为k的二叉树至多有2的k次方-1个节点
性质3:终端节点数为n0,度为2的节点数为n2,则n0=n2+1;
度为1的节点数为n1;则节点的总数=n2+n1+n0;
性质4:具有n个节点的完全二叉树的深度为【log2n】+1
在这里插入图片描述
6.7 二叉树的存储结构
6.7.1 二叉树的顺序存储结构
在这里插入图片描述
假如中间的一些节点并无2个孩子或者没有孩子,那么,没有孩子的地方用空表示。
在这里插入图片描述
但是,如果是斜树的话,顺序存储会造成很大的空间浪费,所以顺序存储结构一般只适用于完全二叉树。
6.7.2 二叉链表
上面也讲了,顺序结构一般只适用于完全二叉树,所说义我们用的最多的还是链式存储结构。二叉树的每个节点最多有两个孩子,所以为它设计一个数据域和两个指针域,这样的链表称为二叉链表。
在这里插入图片描述
在这里插入图片描述
6.8 遍历二叉树
二叉树遍历方法:
1、前序遍历
在这里插入图片描述

在这里插入图片描述
2、中序遍历
在这里插入图片描述
在这里插入图片描述
3、后序遍历
在这里插入图片描述

在这里插入图片描述
4 层序遍历
在这里插入图片描述

6.9 二叉树的建立
在这里插入图片描述在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值