《大话数据结构》学习笔记

第一章 数据结构绪论

数据:是描述客观事物的符号,是计算机中可以操作的对象,是能被计算机识别,并输入计算机处理的符号集合。

数据元素:是组成数据、有一定意义的基本单位,在计算机中通常作为整体处理。也被称为记录。

数据项:一个数据元素可以有若干个数据项组成。数据项是数据不可分割的最小单位。

数据对象:是性质相同的数据元素的集合,是数据的子集。性质相同是指数据元素具有相同数量和类型的数据项。

不同数据元素之间不是独立的,而是存在特定的关系,我们将这些关系称为结构。

数据结构:是相互之间存在一种或多种特定关系的数据元素的集合。


按照观点的不同,我们把数据结构分为逻辑结构物理结构

逻辑结构:是指数据对象中数据元素之间的相互关系。逻辑结构分为以下四种:

  • 集合结构:集合结构中的数据元素除了同属于一个集合外,它们之间没有其他
    关系。
  • 线性结构:线性结构中的数据元素之间是一对一的关系。
  • 树形结构:树形结构中的数据元素之间存在一种一对多的层次关系。
  • 图形结构:图形结构的数据元素是多对多的关系。

物理结构:是指数据的逻辑结构在计算机中的存储形式。分为以下两种:

  • 顺序存储结构:是把数据元素存放在地址连续的存储单元里,其数据间的逻辑关系和物理关系是一致的。
  • 链式存储结构:是把数据元素存放在任意的存储单元里,这组存储单元可以是连续的,也可以是不连续的。需要用一个指针存放数据元素的地址,这样通过地址就可以找到相关联数据元素的位置。

抽象是指取出事物具有的普遍性的本质。
抽象数据类型(ADT):是指一个数学模型及定义在该模型上的一组操作。
抽象数据类型体现了程序设计中问题分解、抽象和信息隐藏的特性。


第二章 算法

算法:算法是解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,并且每条指令表示一个或多个操作。

算法具有五个基本特性:输入、输出、有穷性、确定性、可行性。

输入输出:算法具有零个或多个输入,至少有一个输出。算法是一定要输出的。
有穷性:指算法在执行有限的步骤之后,自动结束而不会出现无限循环,并且每一个步骤在可接受的时间内完成。
确定性:算法的每一步骤都具有确定的含义,不会出现二义性。相同的输入只能由唯一的输出结果。
可行性:算法的每一步都必须是可行的。也就是说,每一步都能通过执行有限次数完成。可行性意味着算法可以转换为程序上机运行。


函数的渐近增长给定两个函数f(n)和g(n),如果存在一个整数N,使得对于所有的n>N , f(n)总是比g(n)大,那么,我们说f(n)的增长渐近快于g(n)。

判断一个算法的效率时,函数中的常数和其他次要项常常可以忽略,而更应该关注主项(最高阶项)的阶数。


算法的时间复杂度
在进行算法分析时,语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)随n的变化情况并确定T(n)的数量级。
算法的时间复杂度,也就是算法的时间量度,记作T(n)=O(f(n)).
随着n的增大,T(n)增长最慢的算法为最优算法。

推导大O阶的方法:

1、用常数1取代运行时间中的所有加法常数。
2、在修改后的运行次数函数中,只保留最高阶项。
3、如果最高阶项存在且不是1,则去除与这个项相乘的常数。得到的结果就是大O阶。


常数阶——O(1)
不管这个常数是多少,我们都记作O(1)。
线性阶——O(n)
对数阶——O(logn)
平方阶——O(n^2)


常见的时间复杂度所耗费的时间从小到大依次是:
O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(n ^3) < O(2 ^n) < O(n!) < O(n ^n)

对算法的分析,一种方法是计算所有情况的平均值,这种时间复杂度的计算方法称为平均时间复杂度。另一种方法是计算最坏情况下的时间复杂度,这种方法称为最坏时间复杂度。一般在没有特殊说明的情况下,都是指最坏时间复杂度。


第三章 线性表

线性表:零个或多个数据元素的有限序列。

元素之间是有顺序的,若元素存在多个,则第一个元素无前驱,最后一个元素无后继,其他每个元素都有且只有一个前驱和后继。

线性表元素的个数n(n>=0) 定义为线性表的长度,当n=0时,称为空表。

在较复杂的线性表中,一个数据元素可以由若干个数据项组成。


线性表的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表的数据元素。

线性表的每个数据元素的类型都相同,可以用一维数组来实现顺序存储结构。

数组的长度是存放线性表的最大存储空间长度。
线性表的长度是线性表中数据元素的个数。

在任意时刻,线性表的长度应该小于等于数组的长度。


存储器中的每个存储单元都有自己的编号,这个编号称为地址。

线性顺序存储结构的优缺点
优点:
1、无须为表示表中元素之间的逻辑关系而增加额外的存储空间。
2、可以快速地存取表中任一位置的元素。
缺点:
1、插入和删除操作需要移动大量元素。
2、当线性表长度变化较大时,难以确定存储空间的容量。
3、造成存储空间的“碎片”。


线性表链式存储结构定义
为了表示每个数据元素a(i)与其直接后继数据元素a(i+1)之间的逻辑关系,对数据元素a(i)来说,除了存储其本身的信息之外,还需存储一个指示其直接后继的信息(即直接后继的存储位置)。
我们把存储数据元素信息的域称为数据域,把存储直接后继位置的域称为指针域。指针域中存储的信息称为指针或链。这两部分信息组成数据元素a(i)的存储映像,称为结点(Node)。

n个结点(a(i) 的存储映像)链结成一个链表,即为线性表(a1,a2,a3,…an)的链式存储结构,因为此链表的每个结点中只包含一个指针域,所以叫做单链表。

头指针和头结点的异同
头指针:
1、头指针是指链表指向第一个结点的指针,若链表有头结点,则是指向头结点的指针。
2、头指针具有标识作用,所以常用头指针冠以链表的名字。
3、无论链表是否为空,头指针均不为空。头指针是链表的必要元素。

头结点:
1、头结点是为了操作的统一和方便而设立的,放在第一元素的结点之前,其数据域一般无意义(也可存放链表的长度)。
2、有了头结点,对在第一元素结点前插入结点和删除第一结点,其操作与其他结点的操作就统一了。
3、头结点不一定是链表的必须要素。


静态链表
用数组描述的链表叫做静态链表,这种描述方法还称为游标实现法。

循环链表
将单链表中终端结点的指针端由空指针改为指向头结点,就使整个单链表形成一个环,这种头尾相接的单链表称为单循环链表,简称循环链表。

双向链表
双向链表是在单链表的每个结点中,再设置一个指向其前驱结点的指针域。所以在双向链表中的结点都有两个指针域,一个指向直接后继,另一个指向直接前驱。


第四章 栈与队列

栈的定义
栈是限定仅在表尾进行插入和删除操作的线性表。

允许插入和删除的一端称为栈顶,另一端称为栈底,不含任何数据元素的栈称为空栈。栈又称为后进先出(last in first out)的线性表,简称LIFO结构。

栈底是固定的,最先进栈的只能在栈底。
栈的插入操作,叫做进栈,也称压栈、入栈。
栈的删除操作,叫做出栈,也称弹栈。

两栈共享空间
数组有两个端点,两个栈有两个栈底,让一个栈的栈底为数组的始端,即下标为0处,另一个栈为数组的末端,即下标为数组长度n-1处。这样,两个栈如果增加元素,就使两端点向中间延伸。

栈的链式存储结构
栈的链式存储结构,简称为链栈。
即把栈顶放在单链表的头部。

对于链栈来说基本不存在栈满的情况,除非内存已经没有可以使用的空间。

对于空栈来说,链表原定义是头指针指向空,那么链栈的空其实就是top=null的时候。

如果栈的使用过程中元素变化不可预料,有时很小,有时很大,那么最好是用链栈,反之,如果它的变化在可控范围内,建议使用顺序栈会更好一些。


栈的应用——四则运算表达式求值
逆波兰表示:一种不需要括号的后缀表示法。
后缀表达式:所有的符号都是在要运算数字的后面出现。

规则:
从左到右遍历表达式,遇到数字就进栈,遇到是符号,就将处于栈顶的两个数字出栈,进行运算,运算结果进栈,一直到最终获得结果。

我们把平时所用的标准四则运算表达式,叫做中缀表达式。

将中缀表达式转化为后缀表达式的规则:

从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分;若是符号,则判断其与栈顶符号的优先级,是右括号或优先级不高于栈顶符号(乘除优先于加减),则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止。


队列的定义:

队列是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。
队列是一种先进先出(First In First Out) 的线性表,简称FIFO。允许插入的一端称为队尾,允许删除的一端称为队头。

队列也存在顺序存储和链式存储。

循环队列:
把队列的头尾相接的顺序存储结构。
队列满的条件:(rear+1)%Queuesize==front
通用的计算队列长度公式:(rear-front+Queuesize)%Queuesize

对于循环队列和链式队列比较,从时间上,其实他们的基本操作都是常数时间,即都为O(1)的,不过循环队列是事先申请好空间,使用期间不释放,而对于链队列,每次申请和释放结点也会存在一些时间开销。

在可以确定队列长度最大值的情况下,建议用循环队列,如果无法估计队列的长度,则用链式队列。

第六章 树

树是n个结点的有限集。

结点拥有的子树数称为结点的度。
度为0的结点称为叶节点或终端结点;
度不为0的结点称为非2终端结点或分支结点。

树的度是树内各节点的度的最大值。

结点的子树的根称为该结点的孩子,相应的,该结点称为孩子的双亲。

同一个双亲的孩子之间互称为兄弟。

结点的祖先是从根到该结点所经分支上的所有结点。


结点的层次从根开始定义,根为第一层,根的孩子为第二层。
双亲在同一层的结点互为堂兄弟。

树中结点的最大层次称为树的深度或高度。

双亲表示法
在每个结点中,附设一个指示器指示其双亲结点在数组中的位置。

多重链表表示法
每个结点有多个指针域,其中每个指针指向一棵子树的根节点。

孩子表示法
把每个结点的孩子结点排列起来,以单链表做存储结构,则n个结点有n个孩子链表,如果是叶子结点则此单链表为空。然后n个头指针又组成一个线性表,采用顺序存储结构,存放进一个一维数组中。

孩子兄弟表示法
任意一棵树,它的结点的第一个孩子如果存在就是唯一的,它的右兄弟如果存在也是唯一的。因此,我们可以设置两个指针,分别指向该结点的第一个孩子和此结点的右兄弟。


特殊二叉树
斜树
所有的结点都只有左子树的二叉树叫左斜树。所有结点都是只有右子树的二叉树叫做右斜树。

满二叉树
在一颗二叉树中,如果所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上,这样二叉树称为满二叉树。

完全二叉树
对一棵具有n个结点的二叉树按层序编号,如果编号为i的结点与同样深度的满二叉树中编号为i的结点在二叉树中位置相同,则这棵二叉树称为完全二叉树。

完全二叉树特点:
1、叶子结点只能出现在最下两层。
2、最下层的叶子颐堤港集中在左部连续位置。
3、倒数二层,若有叶子结点,一定都在右部连续位置。
4、如果结点度为1,则该节点只有左孩子,即不存在只有右孩子的情况。
5、同样结点数的二叉树,完全二叉树的深度最小。

——————————————————————

遍历二叉树

前序遍历,中序遍历,后序遍历

层序遍历:
规则是若树为空,则空操作返回,否则从树的第一层,也就是根结点开始访问,从上而下逐层遍历,在同一层中,按从左到右的顺序对结点逐个访问。

线索二叉树:
指向前驱和后继的指针称为线索,加上线索的二叉链表称为线索链表,相应的二叉树就称为线索二叉树。
对二叉树以某种次序遍历使其变为线索二叉树的过程称作是线索化。
线索化的实质是将二叉链表中的空指针改为指向前驱或后继的线索。
线索化的过程就是在遍历的过程中修改空指针的过程。

————————————————————————————————————

树转化为二叉树
1、加线。在所有兄弟结点之间加一条线。
2、去线。对树中每个结点,只保留它与第一个孩子结点的连线,删除它与其他孩子结点之间的连线。
3、层次调整。以树的根结点为轴心,将整棵树顺时针旋转一定的角度,使之结构层次分明。主义第一个孩子是二叉树结点的左孩子,兄弟转换过来的孩子是结点的右孩子。

森林转换为二叉树
1、把每个树转换为二叉树。
2、第一棵二叉树不动,从第二棵二叉树开始,依次把后一棵二叉树的根结点作为前一棵二叉树的根结点的右孩子,用线连接起来。当所有的二叉树连接起来后就得到了右森林转换来的二叉树。

二叉树转换为树
1、加线。若某节点的左孩子结点存在,则将左孩子结点的所有右孩子结点都作为此结点的孩子。将该结点与这些右孩子结点用线连接起来。
2、去线。删除原二叉树中所有结点与其右孩子结点的连线。
3、层次调整。使之结构层次分明。

二叉树转换为森林
1、从根节点开始,若右孩子存在,则把与右孩子结点的连线删除,再查看分离后的二叉树,若右孩子存在,则连线删除,直到所有右孩子连线都删除为止,得到分离的二叉树。
2、再将每棵分离后的二叉树转换为树即可。

树与森林的遍历
树的遍历:
先根遍历:即线访问树的根结点,然后依次先根遍历根的每棵子树。
后根遍历:即先依次后根遍历每棵子树,然后再访问根结点。

森林的遍历:
前序遍历:先访问森林中第一棵树的根节点,然后再依次先根遍历根的每棵子树,再依次用同样的方式遍历除去第一棵树的剩余树构成的森林。
后序遍历:先访问森林中第一棵树,后根遍历的方式遍历每棵子树,然后再访问根结点,再依次同样的方式遍历除去第一棵树的剩余树构成的森林。

——————————————————
森林的前序遍历和二叉树的前序遍历结果相同,森林的后序遍历和二叉树的中序遍历结果相同。
当以二叉链表作树的存储结构时,树的先根遍历和后根遍历完全可以借用二叉树的前序遍历和中序遍历的算法来实现。


**

赫夫曼树

**
路径长度:从树中一个结点到另一个结点之间的分支构成两个结点之间的路径,路径上的分支数目称作路径长度。

树的路径长度就是从树根到每一结点的路径长度。

结点的带权的路径长度为从该结点到树根之间的路径长度与结点上权的乘积。

树的带权路径长度为树中所有叶子结点的带权路径长度之和。

带权路径长度WPL最小的二叉树称作赫夫曼树(最优二叉树)。

——————————————————————————————

构造赫夫曼树的赫夫曼算法:
1、根据给定的n个权值{w1,w2,w3,…,wn}构成n棵二叉树的集合F={T1,T2,…,Tn},其中每棵二叉树T1中只有一个带权为Wi根结点,其左右子树均为空。
2、在F中选取两棵根结点的权值最小的树作为左右子树构造一棵新的二叉树,且置新的二叉树的根结点的权值为其左右子树上根结点的权值之和。
3、在F中删除这两棵树,同时将新得到的二叉树加入F中。
4、重复2和3步骤,直到F只含一棵树位置。这棵树便是赫夫曼树。

———————————————————————————————

第七章 图

图是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图G中顶点的集合,E是图G中边的集合。

在图中数据元素,称之为顶点。

在图结构中,不允许没有顶点。在定义中,若V是顶点的集合,则强调了顶点集合V有穷非空。

而图中,任意两个顶点之间都可能有关系,顶点之间的逻辑关系用边来表示,边集可以是空的。

——————————————————————————————

无向边:若顶点Vi到Vj之间的边没有方向,则称这条边为无向边,用无序偶对(Vi,Vj)来表示。
如果图中任意两个顶点之间的边都是无向边,则称该图为无向图。

有向边:若从顶点Vi到Vj的边有方向,则称这条边为有向边,也称为弧。
用有序偶对< Vi,Vj >来表示,Vi称为弧尾,Vj称为弧头。
如果图中任意两个顶点之间的边都是有向边,则称该图为有向图。

——————————————————————————————

在图中,若不存在顶点到其自身的边,且同一条边不重复出现,则称这样的图为简单图。

在无向图中,如果任意两个顶点之间都存在边,则称该图为无向完全图。
含有n个顶点的无向完全图有 n*(n-1)/2 条边。

在有向图中,如果任意两个顶点之间都存在方向互为相反的两条弧,则称该图为有向完全图。含有n个顶点的有向完全图有n*(n-1)条边。

——————————————————————————————

有很少条边或弧的图称为稀疏图,反之称为稠密图。

与图的边或弧相关的数叫做权。
这种带权的图通常称为网。

顶点V的度是和V相关联的边的数目。

以顶点V为头的弧的数目称为V的入度。
以顶点V为尾的弧的数目称为V的出度。

——————————————————————————————

路径的长度是路径上的边或弧的数目。

第一个顶点到最后一个顶点相同的路径称为回路或环。

序列中顶点不重复出现的路径称为简单路径。

除了第一个顶点和最后一个顶点之外,其余顶点不重复出现的回路,称为简单回路或简单环。

——————————————————————————————

在无向图G中,如果从顶点V到顶点V’有路径,则称V和V’是连通的。
如果对于图中任意两个顶点Vi、Vj属于V,Vi和Vj都是连通的,则称G是连通图。

无向图中的极大连通子图称为连通分量。条件:
1、要是子图
2、子图要是连通的
3、连通子图含有极大顶点数
4、具有极大顶点数的连通子图包含依附于这些顶点的所有边。

在有向图G中,如果对于Vi,Vj属于V、vi不等于vj,从vi到vj和从vj到vi都存在路径,则称为G是强连通图。有向图中的极大强连通子图称为有向图的强连通分量。

连通图的生成树是一个极小的连通子图,它含有图中全部的n个顶点,但只有足以构成一棵树的n-1条边。

如果一个图有n个顶点和小于n-1条边,则是非连通图,如果它多于n-1条边,必定构成一个环。

有n-1条边并不一定是生成树。

如果一个有向图恰有一个顶点的入度为0,其余顶点的入度均为1,则是一棵有向树。
一个有向图的生成森林由若干棵有向树组成,含有图中全部顶点,但只有足以构成若干棵不相交的有向树的弧。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值