通过装填因子越大求表长如果是小数怎么办

1:数据的结构直接影响算法的选擇和效率

2:数据->数据元素(元素,结点记录)数据的基本单位->数据项(字段,域)数据不可分割的最小单位

3:数据类型:原子数据类型:值不可分(整型字符型,实型)和结构数据类型:值可分解(数组类型结构类型)用户自己定义的

4:数据结构:逻辑结构,物理結构:存储结构(数据结构在计算机中的表示)运算特征。


逻辑结构:集合线性结构(一对一),树型结构(一对多)图状结构(哆对多)


运算:插入,删除查找,排序


数据结构定义:按某种逻辑关系组织起来的一批数据,应用计算机语言按一定的存储表示方法把它们存储在


计算机的存储器中,并在这些数据上定义了一个运算的集合


数据的4种基本存储方法:


顺序存储方法:逻辑上相邻的节点存储在物理位置相邻的存储单位中,结点之间的逻辑关系由存储单元的邻接关系来体现


该方法主要应用于线性的数据结构。


链接存储方法:不要求逻辑上相邻的结点在物理位置上也相邻结点之间的逻辑关系是由附加的指针来表示的。


索引存储方法:存储结点信息的同时建立附加的索引表。索引表中的每一项称为索引项索引项的一般形式:(关键字,地址)


散列存储方法:根据结点的关键字直接计算絀该结点的存储地址


例子:线性结构+顺序存储方法+栈=顺序栈,线性结构+链接存储方法+队列=链队列

5:算法特性:有穷性,确定性可行性,输入输出。

6:算法好坏的判断依据:正确性健壮性,可读性执行耗费时间,执行耗费空间

8:算法是通过数据结构求解问题的步骤,程序是用数据类型描述的算法



线性结构:线性表,栈队列,串


非线性结构:数组广义表,树二叉树,图


应用数据结构:查找内部排序,外部排序文件。


有且只有一个“第一元素”


有且只有一个“最后元素”


除第一个元素之外其他元素都有唯一的直接前趨


除最后元素之外,其他元素都有唯一的直接后继

2:线性表的基本操作:初始化清除,求表长插入数据,删除数据


获得后继结点,獲得前趋结点获得位置i的节点,定位(按值查找)


在插入数据删除数据,定位中平均移动比较次数是n/2这三个操作的时间复杂度是O(n)。

3:线性表的存储结构用数组来实现

4:顺序表:顺序存储结构的线性表


特点:元素在计算机内部存储的物理位置相邻来表示线性表中数據元素之间的逻辑相邻关系


一段连续的内存空间来保存线性表结点的值。

5:在顺序存储中能够方便的查找指定位置的结点值,但是插入和删除结点比较麻烦。

5:链表:链式存储结构的线性表

6:单链表:一个结点只包含一个指针域一个结点结构=数据域+指针域。指针域保存地址信息


用单链表来表示线性表时,结点之间的逻辑关系是由结点中的指针来指示的

7:为了方便判断空表,插入和删除结点我們在单链表的第一个结点前面加上一个头结点。


单链表的头指针L指向头结点如果L->next=null,表示链表为空表。

8:单链表中任何两个结点的存储位置之间没有固定的联系,要寻找某一个结点必须从头指针出发,

9:线性表的链式存储方式利用不连续的内存空间来保存结点的信息因此,在结点中不仅需要保存结点


本身的数据值,还需要利用指针域保存指向直接后继的指针

10:单链表的操作:清除链表,求表长定位查找,插入数据删除数据时间复杂度为O(n)

11:在链式存储中,插入或者删除结点不需要大量的移动结点;但是在定位时却需要遍历整个链表。

12:单循环链表:如果把单链表的最后一个节点的指针域指向第一个结点(头结点)则构成一个首尾相连的循环链表。

13:循环鏈表中判断一个链表是否为空需要看头结点的next域是否等于自身。

14:循环链表建立和判断的时间复杂度为O(1)插入和删除的时间复杂度為O(n)

15:双向链表:两个指针域,一个指向直接前趋一个指向直接后继。

16:双向链表中结点的特点结点的next的prior是结点本身,结点的prior的next是結点本身

17:判断双向链表为空表:看是否两个指针域都为NULL。

18:双向链表的建立和判断时间复杂度为O(1)插入和删除的时间复杂度为O(n)

19:双向循环链表:双向链表中的头结点和尾结点连接起来。

20:判断双向循环链表为空表:看是否两个指针域都指向自身

21:线性表顺序存储与链式存储的比较


时间角度:当线性表的操作操作主要是进行查找,而很少进行插入和删除时应该采用顺序表进行存储


当对于频繁嘚插入和删除操作的线性表,则应该采用链表作为为存储结构


空间角度:顺序表的存储空间是静态分配的在程序引入前必须规定其存储閨蜜,如果估计过大会造成空间的浪费。估计过小会造成空间的溢出。


动态链表是动态分配的只要内存空间有空闲,就不会产生溢絀


线性表的长度变化比较大时,应该采用动态链表为存储结构

22:顺序表是采用数组实现的,链表是采用指针(动态链表)或者游标(靜态链表)来实现的

1:栈和队列:操作受限的线性表,称为限定性的线性表结构

2:栈:仅允许在一端进行插入和删除运算线性表。后進先出(LIFO)线性表


栈顶:允许进行插入和删除的那一端


栈底:不可以进行插入和删除的那一端(线性表的表头)


进栈,入栈压栈:在┅个栈中插入新元素,成为新的栈顶元素


出站退栈:在一个栈中删除一个元素,删除栈顶元素使下一个成为新的栈顶元素。

3:栈的基夲操作:构造空栈清除所有元素,判断栈是否为空返回栈顶元素,入栈出栈。

4:根据存储结构:顺序栈链栈


顺序栈:利用地址连續的存储单元依次存放从栈底到栈顶的数组元素,数组0位置的元素作为栈底元素


top=-1表示栈空;top=maxsize-1,表示栈满就相当于一维数组


在做入栈操莋前,首先要判定栈是否满(满了叫上溢);入栈指针top先加1然后入栈。


在做出栈操作前先要判定栈是否为空(空的为下溢);出栈指針top先减1,然后出栈(指针+1)


链栈:相当于结点构成的单链表。


栈顶元素为单链表的第一个结点因为栈顶元素操作频繁,所以经常用没囿头结点的单链表


链栈是动态分配结点空间的,所以操作时无需考虑上溢问题


链栈的优点:可使多个栈共享空间;在栈中元素变化的數量较大,且存在多个栈的情况下链栈是栈的首选存储方式。

5:栈的应用:数值进制转换括号匹配问题,子程序的调用递归实现

6:隊列:限定在表的一段进行插入而在另一端进行删除的线性表。先进先出线性表(FIFO)




入队:向队列中插入新元素成为新的队尾元素


出队:从队列中删除元素,其后继元素成为新的队头元素

7:队列的基本操作:构造空队列,判断队列为空求队列长度,返回队头元素插叺队尾元素,删除队头元素清除队列元素。

8:根据存储结构:链队列顺序队列


链队列:限制仅在表头进行删除和在表尾进行插入的单鏈表。拥有两个指针(头指针尾指针)


头指针指向头结点,队尾指针指向真正的队尾元素结点


判断链队列为空:头指针和尾指针全部指向头结点。


入队:先将尾指针指向的元素的指针指向入队元素然后尾指针指向入队元素。


出队:修改头指针中的指针指向后继结点,但是当删除的元素是最后一个元素时尾指针需要指向回头结点。


顺序队列:用一组地址连续的存储单元依次存放从队列头到队列尾的え素


这里除了定义一维数组还需要两个指针指向队头和队尾。



入队:元素插入到rear所指向的空单元内rear+1;


出队:删除数组头结点,front+1


在非空隊列中头指针始终指向队头元素,而尾指针始终指向队尾元素的下一个位置


假溢出:当发生了若干次出队入队操作后,尾指针到了最後无法插入了,但是队列元素<队列的单元数


避免假溢出现象:使用循环队列。


循环队列:数组大小maxsize数组所表示的循环队列最多允许囿maxsize-1个结点,rear所指的单元始终为空



9:队列的应用:打印杨辉三角,迷宫问题

10:递归:如果一个函数直接调用自己或者通过一系列调用间接地调用自己。


直接递归:在函数体内直接调用自身


间接调用:一个函数通过调用其他函数并由其他函数反过来又调用该函数

11:用到递归方法的情况:


第一种情况:定义是递归的比如阶乘,Fibonacci数列


第二种情况:数据结构时递归的比如链表就是一种递归的数据结构


第三种情况:有些问题自身没有明显的递归结构,但用递归方法求解更简单

12:递归消除:由于递归程序运行时要花费较多的时间和空间,效率较低有时需要消去一个程序中最经常执行部分的递归调用。


常用的是用迭代和栈进行递归消除


1:串(字符串):是一种特殊的线性表,它嘚每个节点仅由一个字符组成通常用双引号把串中字符括起来。

2:空串:长度为0的串

3:空格串:串中都是空格字符它有长度。

4:子串:串中任意个连续字符组成的子序列

5:串:串变量(值可以改变),串常量(只能被引用不能改变其值)

6:顺序串:串的顺序存储结构用一组地址连续的存储单元来依次存放串中的字符序列。字符数组表示


串结束标志:一般使用“\0”来确定串是否结束。也可以把串长喥放在ch[0]中


基本操作:求串长,串复制串连接,求子串串删除。


缺点:事先定义了串长这在程序运行前是很难估计的


定义了串的最夶长度,串值空间被确定是静态的,插入连接操作被限制。

7:串的堆存储结构:依然是一组空间足够大的地址连续的存储单元存放串值字符序列,不同的是


存储空间的大小不是预先定义的而是在程序执行过程中动态分配的。


指向字符串存储空间的是字符指针而非数組若为空串,则指针为null

8:链串:串的链式存储结构:每个结点仅存储一个字符。便于插入和删除

9:块链:由于链串每个结点的指针域所占空间比字符域大,存储空间利用率低


所以在链串的每个结点存放多个字符,这样的结点叫做块块的大小就是结点所容纳字符的個数。


当结点大小大于1时串的长度不一定正好是结点大小的整数倍,因此用特殊字符“#”填充

10:串的模式匹配:子串定位操作。


两种方法:n是主串长度m是模式串长度


第一种:时间复杂度O(mn)


KMP算法:时间复杂度O(m+n)


1:多维数组和广义表:非线性结构。


逻辑结构:每个数據元素可能有多个直接前趋和多个直接后继

2:数组只有两种基本运算————读和写


读:给定一组下标,读出相应的元素


写:给定一组丅标修改相应的元素

3:数组的存储结构:一般取数组的开始地址作为基准,然后考察其他元素相对此基准的偏移量因此基准加上该数組元素的偏移量就是该元素的绝对地址。


由于内存是一段连续的一维存储空间并不是一个多维的存储空间,因此多维数组中的数据要存儲在内存汇总需要按照一定


的顺序存储在一维空间中。

4:矩阵的压缩存储:矩阵中有很多值相同的元素或者零值元素为了节省存储空間,需要对他们进行压缩存储


对称矩阵,三角矩阵(上三角或者下三角是常数)对角矩阵(除了主对角线和主对角线相邻两侧的若干條对角线的元素之外,其余元素皆为0)


三元组表:根据原矩阵上非零元素的行号列号以及值来作为三元组中的一个值。

6:广义表:又称為列表它是线性表的推广。就是放宽了线性表元素是原子项这个限制允许他们具有自身独立的类型结构。


广义表可以表示为:LS=(a1...ai...an)LS是广義表的名字,n是广义表的长度若ai本身就是广义表,则称为它是LS的子表


空表:不包含任何元素的广义表。


用大写字母表示广义表小写芓母表示原子。


若广义表非空则a1称为LS的表头,其余元素组成的表(a2...ai...an)称为LS的表尾显然,表尾一定是子表表头可以是原子也可以是子表。


廣义表结构:广义表是递归定义的


不考虑广义表内部的结构,广义表就是一个线性表反之,线性表就是一个不含子表的广义表


广义表的深度:该表展开后所含括号的层数。


():长度为0的空表对其不能求表头和表尾的运算。


(()):长度为1的非空表对其进行分解,得到的表头和表尾均是空表

8:纯表:广义表可以与树对应,没有共享和递归的成分

9:再入表:广义表中的元素存在共享

10:递归表:广义表中有自己。有递归

11:广义表特有的运算:取表头和表尾。


在广义表中取某个元素需要将该元素所在的子表逐步分离出来,直箌所求的元素成为某个子表的表头再用取表头运算取出。


总的来说最后一步肯定是取表头


1:树是n个结点的有限集T,当n=0时称为空树,當n>0时满足以下条件


有且只有一个称为树根的结点


当n>1时,除树根结点以外的其余n-1个结点可以划分为m个互不相交的有限集每一个集合本身叒是一个数。


树中有且只有一个结点为树根的结点


树中各子树是互不相交的集合

3:相关概念:结点的度(结点拥有子树的数目)

4:树的基本操作:初始化,求树根创建一颗树,求双亲结点求孩子结点,

插入子树删除子树,树的遍历清除树,判断树空

5:二叉树:甴n个结点的有限集构成,此集合可能为空集也可能由一个根结点及两颗互不相交的左,右子树组成并且左,右子树都是二叉树


二叉樹有且仅有一个结点被称为树根的结点


当n>1时,每个结点至多有两颗子树(即二叉树不存在度大于2的结点)


二叉树的子树有左右之分,且其次序不能任意颠倒它是有序树。

7:二叉树的基本操作:基本和树一样但是在求孩子结点的时候,有左孩子和右孩子之分

8:满二叉樹:一颗深度为k且有2^k-1个结点的二叉树。

9:完全二叉树:深度为k有n个结点的二叉树当且仅当其每一个结点都与深度为k的满二叉树一一对应。



叶子结点只可能在层次最大的两层上出现


对任一结点若其右分支下子孙最大层次为p,则左分支下子孙的最大层次为p或者p+1

10:满二叉树必為完全二叉树完全二叉树不一定是满二叉树。


在二叉树的第i层至多有2^(i-1)个结点


深度为k的二叉树至多有2^k-1个结点。


对任意一颗二叉树BT如果其叶子结点树为n0,度为2的结点数为n2则n0=n2+1



对于n个结点的完全二叉树的深度为logN+1,logN取下限表示不大于logN的最大整数


对于具有n个结点的完全二叉树,如果对其结点按层次编号则对任一结点i,有


如果i=1则结点i是二叉树的树根,无双亲;如果i>1,则其双亲是i/2取下限


如果2i>n则结点i无左孩子;洳果2i<=n,则其左孩子是2i;


12:二叉树的顺序存储:用一组连续的存储单元来存储二叉树的数据元素


在存储的时候,对于普通二叉树必须修补荿完全二叉树进行存储这也造成了存储空间的浪费。这是顺序存储的最大缺点

13:二叉树的链式存储:二叉树的结点应由一个数据元素囷分别指向其左,右子树的各个分支构成


因此二叉树的链表中的结点包含三个域:数据域和指向左,右子树的指针域称为二叉链表。

14:使用链式存储结构来存储二叉树比使用顺序结构存储二叉树更加方便也更容易反应结点之间的逻辑关系。


先根遍历二叉树:根节点-左孓树-右子树


中根遍历二叉树:左子树-根结点-右子树


后根遍历二叉树:左子树-右子树-根结点

16:线索二叉树:加上了指针“线索”的二叉链表組成的二叉树:目的是为了加速遍历过程和充分利用存储空间


线索:在有n个结点的二叉链表中有2n个指针域但只要n-1个指针域用来存放左右指針,其余n+1个指针域均为空


因此用这n+1个空指针域来存放遍历过程中的前趋和后继的指针。



若结点有左子树则lchild指向左孩子,否则ltag=1lchild指向直接前趋结点。


若结点有右子树则rchild指向右孩子,否则rtag=1rchild指向直接后继结点。

17:线索化:实质是在二叉链表的空链域中填写相应结点在一定遍历次序下的前趋和后继的地址而这个地址只能在动态的遍历过程中才能得到。


在线索树中查找前趋结点:当ltag=1lchild就是其前趋结点;当ltag=0时,lchild就是其左子树右链下最后一个结点


在线索数中查找后继结点:当rtag=1,rchild就是其后继结点;当rtag=0时rchild就是其右子树左链下最后一个结点。


双亲表示法:用一组连续的存储空间(数组)来存储树中的结点每个数组元素不但包含结点本身的信息,


还保存双亲结点的下标号


好处:查找某个结点的双亲容易


坏处:查找某个结点的孩子结点很困难。


孩子链表表示法:把每个结点的孩子结点排列起来构成一个单链表(駭子链表)。


然后将这样的将n个这样的数据元素放在一组连续的存储空间中


好处:容易求得一个结点的孩子结点。


坏处:求得一个结点嘚双亲结点就很困难


孩子兄弟链表表示法:链表中的结点有两个链域,分别指向第一个孩子结点和下一个(右)兄弟结点


好处:容易實现数的任何操作,在结点上加上双亲域可以方便双亲的查找。

20:树森林和二叉树之间的转换


由于树的孩子兄弟链表示法和二叉树的②叉链表表示法完全一样,所以之间很容易实现相互转换



-加线:在树中所有相邻的兄弟之间加一条线


-抹线:对树中每个结点,除了其左駭子外抹去该结点与其余孩子之间的连线


-整理:以树的根结点为轴心,将整树按顺时针旋转45度


可以证明,树转换所构成的二叉树是唯┅的


转换成的二叉树中,左分支上的各结点在原来的树中是父子关系右分枝上的各结点在原来的树中是兄弟关系。



-将森林中的每棵树轉换成相应的二叉树


-第一课树不动从第二课树开始,依次把后一颗二叉树的根结点作为前一颗二叉树根的右子树


树转换成二叉树根结點没有右子树,森林转换成二叉树根结点有右子树。



-加线:若某结点是其双亲的左孩子则把该结点右链上所有的结点都与该结点的双親结点用线连接起来。


-抹线:抹掉原二叉树中所以双亲结点与其左孩子右链上所有结点的连线



能够转换成树的二叉树一定没有右子树



-将②叉树中根结点与其右孩子连接,及沿右分支搜索到的所以右孩子间连线全部抹掉使之成为孤立的二叉树。


-将孤立的二叉树还原成树




從左到右,依次先根遍历根结点的每一颗树



从左到右,依次后根遍历根结点的每一颗树




若树非空则遍历方法是先访问第一层上的结点,然后依次遍历第二层到第n层的结点



访问森林中第一颗树的根结点


先根遍历第一棵树的根结点的子树森林


先根遍历除去第一颗树之后剩餘的树构成的森林。



中根遍历森林中第一颗树的根结点的子树森林



中根遍历除去第一颗树之后剩余的树构成的森林



后根遍历森林中第一颗樹的根结点的子树森林


后根遍历除去第一课树之后剩余的树构成的森林


23:森林的先根遍历中根遍历和后根遍历相对于转换成的二叉树的先根遍历,中根遍历和后根遍历相对应

24:树的先根遍历后根遍历分别于森林的先根遍历和中根遍历。

25:哈夫曼树(最佳判定树):由n个帶权叶子结点构成的所有二叉树中带权路径长度WPL最小的二叉树


WPL:树的带权路径长度:结点的权值*结点的路径长度,然后所以结点的带权蕗径长度相加


树带权路径长度越小越好。

26:前缀编码:任意一个编码不能成为其他任意编码的前缀利用哈夫曼算法,可以设计出前缀編码


好处:可以减少定长编码的总位数

27:哈夫曼树中没有长度为1的结点,一颗n个叶子结点的哈夫曼树共有2n-1个结点


可以用一个一维数组來表示各个结点,数组中每个元素包括四个数据项:结点的权值结点的双亲下标和结点左右孩子。

28:二叉树的一些结论


一颗二叉树的前根序列和中根遍历可确定一颗二叉树


一颗二叉树的后根序列和中根遍历可确定一颗二叉树



含有n个结点的二叉树共有1/(n+1)*C(n|2n);和出栈次数一样


任何一顆二叉树的叶子结点在先根中根和后根遍历序列中的相对次序不发生改变。


1:线性表:数据元素之间仅存在线性关系每个数据元素只囿一个直接前趋和一个直接后继;


树:数据元素之间有着明显的层次关系,且每层上的数据元素可能和下一层中多个元素(孩子)相关联但只能和上一层



图形结构:结点之间的关系可以是任意的,图中任意两个数据之间都可能相关每个结点都可以有多个直接前趋和多个矗接后继。

2:树是图的特殊情况

4:无向完全图:n个顶点的无向图,如果任意两个顶点间都有一条直接边相连


5:有向完全图:n个顶点的囿向图,如果任意两个顶点间都有方向互为相反的两条边相连


6:路径长度:这条路径上边的数目

8:简单路径:除了第一个顶点和最后一個顶点之外,其余顶点都不同的路径

9:简单回路:第一个顶点和最后一个顶点相同的简单路径

10:相关概念:连通图,连通分量(极大连通子图)强连通图,强连通分量弱连通图(有向图中,至少有单向通路)弱连通分量。

11:度:顶点所具有的边的数目

    入度:以某顶點为终点的边的数目

12:生成树:连通图的G的一个子图如果是一颗包含G的所以顶点的树


n个顶点的生成树具有n-1条边。

13:图的存储结构:邻接矩阵邻接表,邻接多重表十字链表

14:若图为权图:若<v1,v2>不是E(G)中的边,则这条边的权值a12为0或者无穷大


若图为非权图:如果顶点v1,v2之间无邊则a12=0;


如果顶点v1,v2之间有边则a12=1。

15:无向图的邻接矩阵是对称的而有向图的邻接矩阵不一定对称。


 用邻接矩阵表示具有n个顶点的有向圖时要用n^2个单元存储邻接矩阵


 用邻接矩阵表示具有n个顶点的无向图时,只需要存入三角矩阵只需n(n+1)/2个存储单元。

16:邻接矩阵来表示图噫判定图中任意两个顶点之间是否有边相连,也易求得各个顶点的度数


对于无向图,邻接矩阵第i行元素之和就是图中第i个顶点的度数


對于有向图,第i行元素之和是顶点i的出度第i列元素之和是顶点i的入度。

17:邻接矩阵并非图的顺序存储结构只是借助了数组这一数据类型来表示图中元素间的相关关系。

18:邻接矩阵的事件复杂度为O(n^2)

19:邻接表表示法:图的链式存储结构,包含两部分:链表和向量


邻接表:在邻接链表中对图中每个顶点vi都建立一个单链表,第i个单链表中的结点表示依附于顶点i的边


邻接表中的每个结点由两个域组成:頂点域和链域。


表头结点:数据域和链域所有表头结点存放在一个顶点表中。


将无向图的邻接表称为边表将有向图的邻接表称为出边表。

20:若无向图中有n个顶点e条边,则邻接链表需n个表头结点和2e个表结点每个结点有两个域


对于边很少的图,用邻接链表比用邻接矩阵哽节省存储单元

21:逆邻接表:为了计算有向图的入度;邻接表可以计算有向图的出度。

22:邻接表的时间复杂度:O(n+e)

23:当边数较少时鄰接表比较好;当边数较多时,邻接矩阵比较好

24:邻接矩阵是唯一的,邻接表不是唯一的

25:图的遍历:深度优先搜索法和广度优先搜索法。

26:深度优先搜索法:类似于树的前序遍历当访问了一个顶点之后,尽量向纵深方向去访问下一个未被访问的顶点


遍历的时间复雜度取决于存储结构



邻接矩阵:O(n^2)

27:广度优先搜索遍历:类似于树的层次遍历


遍历的时间复杂度取决于存储结构



邻接矩阵:O(n^2)


遍历的涳间复杂度为O(n),辅助空间是队列和标志数组

28:非连通图的遍历:进行多次DFS或者BFS算法从某个顶点出发进行遍历,执行一次不能保证访問到所以顶点


为此需要再选择未被访问的顶点作为起点,再次执行DFS或者BFS

29:生成树是连通图的极小连通子图:由于n个顶点的连通图至少囿n-1条边,而所以包含n-1条边及n个顶点的连通图都是无回路的树

30:生成树:连通图G的一个子图如果是一颗包含G的所有顶点的树。

31:构造最小苼成树:


尽可能选择权值小的边但不能构成回路


选取n-1条恰当的边以连接网的n个顶点

32:构造最小生成树的普里姆(prim)算法,从顶点出发寻找最短边


算法的时间复杂度为O(n^2),比较适合构造稠密图的最小生成树,与边数无关

33:构造最小生成树的克鲁斯卡尔(kruskal)算法,选取n-1条朂小的边


算法的时间复杂度为O(eloge)与网中数目e相关,适合稀疏图的最小生成树


迪杰斯特拉(dijkstra):提出一个按路径长度递增的次数产生朂短路径的算法。


算法的时间复杂度O(n^2)


弗洛伊德(floyd):求每一对顶点之间你的最短路径


算法的时间复杂度O(n^3)比较适合稠密图,需要求A^n和path^n;

35:AOV网:以顶点表示活动有向边表示活动之间的先后关系的网

36:拓扑排序:构造AOV网的拓扑有序序列的操作。是定义在有向图上的一种操作AOV网不应该出现回路。


算法时间复杂度O(n+e)

37:对AOV网进行拓扑排序的步骤是:


在AOV中选取一个入度为0的顶点并输出它


从网中删去该顶点並且删去从该顶点发出的全部有向边


重复上面两个步骤,直到网中全部顶点均已输出或者当前图中不存在入度为0的顶点位置,后一种情況说明有向图有回路

38:AOV网的拓扑有序序列不唯一。

39:AOE网:顶点表示子工程(事件)边表示活动,边上的权表示活动所需的时间

40:关鍵路径:从开始顶点到结束顶点的最长路径长度。一个AOE网可能有多条关键路径他们的长度是一样的。

41:最早开始时间:一个时间vk能够发苼的最早时间取决于从始点v1到顶点vk的最长路径长度

42:最迟开始时间:一个时间vk允许的最迟发生时间,应该等于结束顶点事件vn的最早发生時间减去vk到vn的最长路径长度

43:最迟开始时间-最早开始时间


若为0,则活动为关键活动否则为非关键活动。

44:关键路径的识别:为了使AOE网所代表的工程尽快完成要先识别关键路径,只有缩短关键路径上的关键活动所需时间才能缩短整个工期


对AOE网进行拓扑排序,按拓扑排序的次序求出各顶点事件的最早发生时间ve若有向图中有回路,则算法结束否则执行下一步


按拓扑序列的逆序求出各顶点事件的最迟发苼时间vl


根据求得的各顶点的ve,vl求出各活动ai的最早开始时间e(i)和最迟开始时间l(i),若e(i)=l(i)则ai为关键活动。

46:不论出度还是入度顶点的度之和等於图边数的两倍。

47:用邻接表表示图进行广度优先遍历通常采用队列来实现算法。

48:用邻接表表示图进行深度优先遍历通常采用栈来實现算法。

1:查找表:同一类型的数据元素(或者记录结点)构成的集合。

2:关键字:数据元素中某个数据项的值用它可以标识或识別一个数据元素。

3:查找:给定一个关键字K在含有n个结点的查找表中找出关键字等于给定值K的结点。


若查找成功返回结点的信息或该結点在表中的信息。


若查找失败返回相关的指示信息。

4:动态查找表:若在查找的同时需要对表进行修改操作(如插入删除等)。

5:靜态查找表:若对表只进行查找操作(查询检索等)。

6:内查找:如果查询过程都在内存中进行

7:外查找:如果查询过程需要访问外存。

8:平均查找长度(ASL):查找过程中对关键字需要执行的平均比较次数


衡量一个查找算法效率高低的标准。


顺序查找:从表的一端开始顺序扫描线性表,依次将扫描到的结点关键字和给定值K相比较


R[0]作哨兵,从后往前判断


顺序查找的存储结构:适用于线性表的顺序存儲结构也使用也链式存储结构(使用单链表,扫描从表头开始)


顺序查找的平均查找长度:(n+1)/2


顺序查找改进:每当查找成功时就将找到的结点和后继结点交换,减少查找概率大的结点的比较次数


顺序查找的优点:算法简单,对表结构无任何要求不关注关键字是否囿序。


顺序查找的缺点:查找效率低当n特别大时,不宜用顺序查找


二分查找(折半查找):效率较高的查找算法,要求线性表是有序表并且要用向量作为表的存储结构。



首先确定该区间内的中点位置


然后将待查的K值与中点位置进行比较:若相等查找成功返回位置;否则确定新的区间差找


如果中间位置大于k,则新的区间则是左子表


如果中间位置小与K则新的区间则是右子表


重复上面这个过程,直至找箌关键字为K的结点


二分查找判定树:把当前查找区间的中间位置上的结点作为根,左子表和右子表中的结点分别作为根的左子树和右子樹


二分查找成功时的平均查找长度:log(n+1)-1


二分查找失败时的平均查找长度:log(n+1)取上限


二分查找的平均查找长度:logn


二分查找的优点:查找效率高,但是要排序关键字最高效的排序需要花费O(nlogn)


二分查找的缺点:只适合顺序存储结构,适合一经建立就很少改动而又经常需偠查找的线性表


分块查找(索引查找):性能介于顺序查找和二分查找之间


分块查找表的索引结构:


分块有序的线性表:前一块的最大關键字小于后一块的最小关键字


索引表:抽取各块中最大关键字及其起始位置构成一个索引表,索引表是递增有序表



首先查找索引表,鈳采用二分查找或者顺序查找看看结点在哪一块


然后在已确认的块中进行顺序查找。


分块查找的平均查找长度





分块查找的优点:在表中插入或者删除一个记录时只要找到该记录所属的块,就可在该块内进行插入和删除运算


因为块中的记录的存放是任意的,所以插入或鍺删除的时候不需要移动大量的结点


分块查找的缺点:增加一个辅助数组的存储空间和将初始表分块排序的运算。


在这三种查找方式中二分查找效率最高,但是只适用于静态查找表


二叉排序树(二叉查找树):


若它的左子树非空,则左子树上所有的结点的值小于根结點的值


若它的右子树非空则右子树上所有的结点的值大于根结点的值


左右子树本身又个数一颗二叉排序树


树排序:二叉排序树的中序遍曆是一个有序遍历,平均执行时间O(nlogn)


对于相同的实力树排序是堆排序的2-3倍,因此在一般情况下构造二叉排序树是为了查找并不是为叻排序。



若二叉排序树为空则为待插入的关键字申请一个新结点,并令其为根;


若二叉树不为空则将key和根的关键字比较:


若二者相等,说明树中已有此关键字无须插入


若key小于根关键字,则插入左子树


若key大于根关键字则插入右子树



p为叶子结点,只需将p的双亲parent中指向p的指针域置为空;


p只有一个孩子只需将child和p的双亲直接连接就可以,然后删除p;


p有两个孩子替换p为p右子树下最左边的点,删除该点


二叉排序树上的查找:二叉排序树构建不唯一,二分查找树是唯一的


二叉排序树的查找的平均查找长度与二叉树的形态有关


最坏情况查找长度:构成一颗单树(n+1)/2


最好情况查找长度,构成一颗形态与二分查找树相似的排序树logn


插入,删除和查找算法的时间复杂度均为O(logn)


二叉排序树和二分查找的比较:



如果有序表是静态查找表用二分查找


如果有序表是动态查找表,用二叉排序树


平衡二叉树:指树中任一结点嘚左右子树的高度大致相同为了保证二叉排序树的高度为logn


满二叉树是完全平衡的,只要二叉树的高度O(logn)可以看成是平衡的。


AVL树中任┅结点的左右子树的高度之差的绝对值不超过1


最坏情况下n个结点的AVL树高度为1.44logn


完全平衡的二叉树高度为log2n,AVL树是接近最优的


B-树:查询的文件较大,且文件存放在磁盘等直接存取设备中为了减少查询过程中对磁盘的读写次数。



每个结点至少包含以下数据域(n,p0,k1,p1,k2,...,ki,pi)k表示关键字(关键芓序列递增有序)p表示指针


所有叶子结点都在同一层,叶子的层数为树的高度h



由于内部结点的度数正好是关键字总数+1所以每个非根结點至少有m/2颗子树,至多有m颗子树


高度为n的三阶B-树的结点至少是2^n-1


一颗高度为h的B-树任一叶子结点所处的层数为h,当向B-树插入一个新关键字时为检索插入位置所需读取h个结点。

11:散列表的查询:不同于顺序查找二分查找,二叉排序树不以关键字的比较为基本操作,而是采鼡直接寻址技术

12:散列的基本思想:以结点的关键字K为自变量,通过一个确定的函数关系h计算出对于的函数值,然后把这个值解释为結点


的存储地址将结点存入函数值所指的存储位置上。在查找时根据要查找的关键字用同一函数计算出地址


再到相应的单元里去取出偠找的结点。

13:散列表冲突问题:两个不同的关键字由于散列函数值相同,因而被映射到同一表位置上




关键字的个数小于或者等于散列表的长度


14:装填因子越大:a=填入的结点n/表长m。a越大表越满,冲突的机会也越大通常去a<=1。

15:散列函数的选择:


平方取中法:先通过求關键字的平方值扩大相近数之间的差别然后根据表长度取中间的几位数作为散列函数值。


除留余数法:最简单常用的一种方法就是用表长m去除关键字,取其余数作为散列地址m最好取素数。



首先用关键字key乘上某个常数A(0<A<1)并抽取出key*A的小数部分,A最好选黄金分割点;


然后鼡m乘以该小数后取整


随机函数法:保证随机函数值在0-(m-1)之间。通常当关键字长度不等时采用此方法来构造散列函数。


开放地址法:沖突发生时使用某种探查技术在散列表中形成一个探查序列,沿此序列逐个单元查找直到找到给定的关键字








缺陷:可以减少堆积现象,但是不易探查到整个散列空间




m为素数,则h1(key)取1-(m-1)之间的任何数均与m互素


m为2的方幂,则h1(key)取1-(m-1)之间的任何奇数


拉链法:将所有关键字为同义词的结点链接到同一个单链表中。



拉链法处理冲突简单没有堆积现象


拉链法结点空间动态申请,适合造表前无法确认表长的情况



删除结点比较容易直接在链表上删除;而对开放地址表来说,只能在被删结点上做标记不能真正的删除结点



指针需要额外嘚空间,当结点规模小与拉链法相比,开放地址发更省空间


查找:散列表的平均查找长度比顺序查找,二分查找等完全依赖与关键字仳较的查找要小得多


查找成功ASL:查找次数之和/关键字个数


查找失败ASL:查找不成功时对关键字需要执行的平均比较次数。


直接找关键字到苐一个地址上关键字为空的距离即可初始位置只能是MODn的0-n-1;


由同一个散列函数,不同的解决冲突方法构造的散列表其平均查找长度是不哃的


散列表的平均查找长度不是结点个数n的函数,而是装填因子越大a的函数


顺序查找O(n),其他查找O(logn)散列法查找O(1)


1:排序方法嘚稳定性:在待排序的文件中,若存在多个关键字相同的记录经过排序后这些相同的关键字的记录之间的相对次序


保持不变。反之则昰排序方法是不稳定的。

2:内部排序:排序过程中整个文件都在存放在内存中进行处理的


一般适用于记录个数不多的小文件


插入排序,選择排序交换排序,归并排序基数排序

3:外部排序:排序过程中需要进行数据的内,外存之间的交换


一般使用于记录个数太多,不能一次性将全部记录放入内存的大文件

4:排序算法的性能评价:



执行算法所需的辅助空间:O(1)是就地排序非就地排序一般是O(n)


5:不同存储方式的排序过程:顺序表,链表索引表。

6:插入排序:每次将一个待排序的记录按其关键字大小插入已经排序好的文件中的适当位置,矗到全部记录插入完位置


(就像打牌一样边抓边整理)。


直接插入排序:在排序中引入哨兵这个概念,作用是:


在进入循环之前保存了r[i]的副本,使得不致于因为记录后移而丢失r[i]中内容


在while循环中监视下标j是否越界一旦越界,直接退出


引入哨兵后使得测试查找循环条件嘚时间大约减少了一半




关键词递增有序(正序):O(n)


关键词递减有序(反序):O(n^2)


关键词无序(平均):O(n^2)



辅助空间一个监视哨O(1),就地排序


直接插入排序是一个稳定的排序


希尔排序:直接插入排序的改进先取一个小与n的整数d作为第一个增量,把文件分成d组嘫后排序,然后减少增量


的值进行排序最后增量变成1进行排序。



希尔排序的执行时间依赖于增量序列:



应该避免序列中的值为倍数


当n较夶时希尔排序比较和移动的次数约为n^1.3


希尔排序时间性能上明显优于直接插入排序


7:交换排序:两两比较待排序记录的关键字,发现两个記录的次序相反时即进行交换直到没有反序的记录出现


冒泡排序:从下往上扫描数组,一旦违反轻气泡不能再重气泡之下的原则就让其调换,直到最后任何两个气泡都是轻者在上重者在下。




关键词递增有序(正序):O(n)


关键词递减有序(反序):O(n^2)


关键词无序(岼均):O(n^2)



辅助空间一个监视哨O(1),就地排序


冒泡排序是一个稳定的排序


快速排序(霍尔排序):采用分治法的思想将原问题分解成若干个规模更小但结构与原问题相似的子问题,递归解决子问题


然后将这些子问题的解组合为原问题的解



分解:在数组中任选一个基准,依次划分左右两个较小的子区间最后使得左区间的值<基准值<右区间值


求解;递归对左右区间进行快速排序


组合:求解后已经有序了,排序好了其实是个空操作。



快速排序的时间主要耗费在划分操作上对长度为k的区间进行划分,共需进行k-1次关键字的比较


在无序数组Φ选择划分的基准关键字是决定算法性能的关键。



最坏:划分后基准是在最左边或者最右边O(n^2)


最好:划分基准是中值O(nlogn)



空间复杂度:赽速排序需要一个栈来实现




8:选择排序:每一趟从待排序的记录中选出关键字最小的记录顺序存放在已排序好的子文件的后面,直到全蔀记录排序完毕


直接选择排序:n个记录经过n-1此直接选择排序得到有序结果


第一趟,在无序区中选择最小的值和第一个元素交换


第二趟,在2-n中选择最小的值和第二个元素交换。



时间复杂度:O(n^2)



辅助空间一个监视哨,O(1)就地排序


直接选择排序是不稳定排序。


堆排序:是一树型选择排序其特点是:在排序过程中,将序列看成是一颗完全二叉树的顺序存储结构利用完全二叉树


中双亲结点和孩子结點之间的内在关系,在当前无序区中选择关键字最大(或最小)的记录




堆的实质:是满足一下性质的完全二叉树:树中任一非叶结点的關键字均不大于(或不小于)其左右孩子结点的关键字。


大根堆:根结点的关键字是堆里所有结点关键字中最大者


小根堆:根结点的关键芓是堆里所有结点关键字中最小者


注意:堆中任意子树也是堆


堆排序与直接选择排序的区别:在直接选择排序中,会出现重复的比较次數由于堆排序可以通过树型结构保存


部分比较结果,因此能够减少比较次数



先将初始文件R建成一个大根堆,此堆为初始的无序区


然后將最大的记录R[1](堆顶)和无序区最后一个记录R[n]交换由此得到新的无序区R[1,,,N-1]和有序区[N]


然后调整新的无序区为大根堆,继续交换元素直到无序区呮有一个元素为止。


算法分析:堆排序适合待排序的记录个数较多的情况因其运行时间主要消耗在建立初始堆和调整堆时进行





平均:O(nlogn)接近最坏性能,


由于堆排序建立初始堆所需的比较次数较多所以堆排序不适宜记录小的文件



辅助空间一个监视哨,O(1)就地排序


9:歸并排序:将这些有序的子序列进行归并,从而得到有序的序列


插入排序,选择排序交换排序对待待排序的初始状态不做任何要求,泹是归并排序要求待排序序列已经部分有序


部分有序:待排序列由若干个有序的子序列组成。


两个有序子序列归并:R[LOW,M],R[M+1HIGH],R1。三个指针分别指向三个集合比较R[I]和R[J]的值,直到一个集合已经


全部复制完毕此时将另一非空的子文件中的剩余记录依次复制到R1中。



自底向上:第一趟歸并待排序的文件n个长度为1的子文件,然后两两归并第二趟,长度为2直到归并完成。


效率虽然高但是可读性较差



分解:当前区间┅分为二,分裂点是中间点


求解:递归对两个子区间进行归并排序


组合:把两个子区间合成一个有序的区间


递归的终止条件是子区间的長度为1。



存储结构要求:顺序和链表都可以



对于长度n的文件,需要进行logn趟二路归并取下限每趟归并时间为O(n)


所以最好还是最坏都是O(nlogn)



需要一个辅助向量来暂存两个有序子文件归并的结果。O(n)


归并排序是稳定的排序

10:基数排序:前面的各种排序方法是根据关键字值夶小排序的。基数排序是借助多关键字排序的思想对单个逻辑关键字进行排序


最高位优先:排序是先对最高位关键字K0进行排序,然后在對K1进行排序最后对最次位关键字Kd-1进行排序。


最低位优先:排序先对最次位关键字Kd-1进行排序然后对关键字Kd-2进行排序,直到对最高位关键芓K0进行排序


用到分配和收集来实现。


比如扑克牌按花色和牌面大小两个关键字排序



时间复杂度:排序所需的计算时间不仅和文件大小n囿关,而且还与关键字的位数d关键字的基r有关。


(十进制的基为10二进制的基为2)



空间复杂度:O(n+r)



当n很大,记录的关键字位数较小且鈳以分解(整型或者字符串)时采用基数排序。



O(n^2):简单拍排序:直接插入冒泡,直接选择


O(n^logn):快速堆,归并



O((n+r)):基数


各种排序方法比较:简单排序中直接插入最好;快速排序最快;当文件为正序时直接插入和冒泡均为最佳。


不同条件下排序方法的选择:


若n较尛(n<=50)采用直接插入或者直接选择。


若n较大选择时间复杂度(n^logn)的排序方法:快排,堆归并


若文件初始状态为有序:直接插入,冒泡或者随机快排



链表:插入排序,归并排序基数排序,使之减少记录的移动次数

12:外部排序:磁盘文件排序和磁带文件排序


区别:初始归并段在外存储介质中的分布方式磁盘时直接存取设备,磁带是顺序存取设备


方法:按照内存大小,在外存中分成若干个h的子文件然后读入内存进行内部排序,然后输出外存


最后把这些归并段整合到一起。


归并方法:二路归并多路归并。


      散列表,又叫哈希表它是基于快速存取的角度设计的,也是一种典型的“空间换时间”的做法顾名思义,该数据结构可以理解为一个线性表但是其中的元素不是紧密排列的,而是可能存在空隙

value)而直接进行访问的数据结构。也就是说它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度这个映射函数叫做散列函数,存放记录的数组叫做散列表比如我们存储70个元素,但我们可能为这70个元素申请了100个元素的空间70/100=blogs.com/xiohao/p/4389672.html

Hash哈希知识点导航

??2.1 直接寻址法
??2.2 数字分析法
??2.3 平方取中法
??2.6 除留余数法
??3.1 哈希查找的操作步骤
??3.2 哈希表查找效率
4. 解决哈希冲突的方法
??4.1 开放地址法
??4.4 建竝公共溢出区
??4.5 线性探测法
??5.1 原理与应用
??5.2 哈希算法特点
8. 三元组稀疏矩阵存储

??Hash,也叫哈希或散列就是把任意长度的输入(也叫預映射),通过散列算法变换成固定长度的输出,该输出就是散列值
??若结构中存在和关键字key相等的记录,则必定在H(key)的存储位置上称该H(key)为哈希函数

??根据设定的哈希函数H(key)和处理冲突方法将一组关键字映射到一个有限的地址区间上并以关键字在地址区间中的象莋为记录在表中的存储位置,这种表称为哈希表或散列表这一映像称为散列,所得存储位置称为哈希地址或散列地址

??对不同的关鍵字可能得到同一散列地址,即key1≠key2而f(key1)=f(key2),这种现象称碰撞

??哈希函数能使数据序列的访问过程更加迅速有效,通过哈希函数数据元素将被更快地定位。

??散列法存储的思想是由关键字和散列函数(即哈希函数)共同决定数据的存储地址的

??取关键字或关键字的某个线性函数值为散列地址。即H(key)=key或H(key) = a*key + b其中a,b为常数,这种哈希函数为自身函数
例:有一个从1到100岁的人口数字统计表中,其中年龄作为关鍵字,哈希函数取关键字自身

??有学生的生日数据如下:
??年?? 月?? 日
??经分析,第1,2,3位数重复的可能性大取这三位造成的沖突的机会增加,所以尽量不取前3位较好

??取关键字平方后的中间几位为哈希地址。

??将关键字分隔成位数相同的几部分(最后一蔀分的位数可以不同)然后把这几部分的叠加和(舍去进位)作为哈希地址。
??例:每一种图文图书都有一个国际标准图书编号它昰一个10位的十进制数字,若要以它作关键字建立一个哈希表当馆藏种类不到10000时,可采用折叠法构造一个四位数的哈希函数

??选择一個随机函数,取关键字的随机函数值作为它的哈希地址即H(key)=random(key),其中random为随机函数通常用于关键字长度不等时的场合。

??取关键字被某个鈈大于哈希表表长m的数p除后所得余数为哈希地址即H(key)=key MOD p(p<=m)
??在哈希函数进行模除取余时最好取素数进行模除。其原因和计算机的输入有關因为计算机输入不是所有数都是随机的,而是有某种规律因为存在大量的while和for循环,而素数对于这样的数处理起立比合数要好而且素数一般为3。
??哈希函数的构造不是越复杂越好因为哈希函数越复杂,取得关键字地址所消耗的时间越长可能对哈希算法性能造成┅定的影响。因此选择哈希函数的时候应该多方面权衡,选择合适的哈希函数

??哈希查找是通过计算数据元素的存储地址进行查找嘚一种方法。

3.1 哈希查找的操作步骤

① 给定的哈希函数构造哈希表

② 根据选择的冲突处理方法解决地址冲突。③ 在哈希表的基础上执行哈唏查找

??step1先取数据元素的关键字key,计算哈希函数值若该地址对应的存储空间没有被占用,则将元素存入;否则执行step2解决冲突step2根据選择的冲突处理方法,计算关键字key的下一个存储地址若下一个存储地址仍被占用,则继续执行step2直到找到能用的存储地址为止。

??因為有些数据本身是无法排序的(如图像)有些数据是很难比较的(如图像),如果数据本身是无法排序的就不能对它们进行比较查询。如果数据时很难比较的即使采用折半查找,要比较的次数也是非常多的因此哈希查找并不查找数据本身,而是先将数据映射为一个整数(它的哈希值)并将哈希值相同的数据存放在同一个位置,即以哈希值为索引构造的一个数组

??在哈希查找的过程中,只需先將要查找的数据映射为它的哈希值然后查找具有这个哈希值,这就大大减少了查找次数
哈希查找可以在外存中查找,可以用哈希表映射到文件分级查找。

??虽然哈希查找就是尽量避免比较直接找到位置但因为一旦有hash冲突的存在,就会有比较操作所以在哈希查找Φ,“比较”操作一般是不可避免的

3.2 哈希表查找效率

??哈希表的查找效率主要取决于哈希函数、处理冲突的方法和装填因子越大。
??为了提高哈希表的查找效率可以采取的正确措施有:
① 减小装填(载)因子
② 设计冲突(碰撞)少的散列函数
③ 处理冲突(碰撞)时避免产生聚集(堆积)现象
??不同结构获得任意指针值:
??二叉树排序树中,查找的平均时间复杂度是O(logn);
??对于栈和队列来说查找昰把元素挨个出栈或队列,故平均时间复杂度O(n);
??哈希表直接通过关键码查找元素,平均为O(1)

??装填因子越大的计算公式=关键字个数/表长喥。即装填因子越大是衡量哈希的好坏标准之一还和hash表的平均查找长度有关。如果要提高效率可以减小装填因子越大,即可以减少关鍵字个数或提高表长度

装填因子越大反应的是空间利用率。 ??例:你要对5个对象进行hash,而内存中准备了20个位置,那么还有15个空位最後装填因子越大就是5/20 = 0.25,所以装填因子越大越小产生冲突的可能越小。

??ASL(Average Search Length)即平均查找长度,在查找运算中由于所费时间在关键字的仳较上,所以把平均需要和待查找值比较的关键字次数称为平均查找长度
??其中n为查找表中元素个数,pi为查找第i个元素的概率通常假设查找每个元素的概率相同,即pi=1/nci是找到第i个元素的比较次数。
??一个算法的ASL越大性能越差,ASL越小性能越好。
??例:设哈希表長为8哈希函数为Hash (key)=key%7。初始记录关键字序列为(3224,1527,2013),用链地址法作为解决冲突方法的平均查找长度是( )
??链地址法作为解决冲突方法:冲突以后变成链表,查询次数增加
??32%7=4?4位置为空存入(查一次)
??24%7=3?3位置为空,存入(查一次)
??15%7=1?1位置为空存入(查一次)
??27%7=6?6位置为空,存入(查一次)
??20%7=6?6位置不为空向下查找,7位置为空存入(查两次)
??13%7=6?6位置不为空,向下查找7位置不为空,继续查找5位置为空(就近原则),存入(查三次)

??当两个不同的数据元素的哈希值相同时,就会发生冲突为减少发苼冲突的可能性,哈希函数应该将数据尽可能地分散地映射到哈希表的每一个选项中解决冲突的方法有以下4种:

??基本原理是:当关键芓key的哈希地址出现冲突时,计算key的下一个存储地址w1假如w1被占用;则计算key的下一个存储地址w2,如果w2仍被占用,继续计算key的存储地址w3,w4……直至找到能用的存储地址将相应元素放入其中。

??在开放地址法构造的散列表删除结点不能简单地将被删的结点的空间置为空,否则将截断在它之后填入散列表的同义词结点的查找路径因为开放地址法中,空地址单元(即开放地址)都是查找失败的条件因此用开放地址法处理冲突的散列表上执行删除操作,只能在被删结点上做删除标记而不是真正的删除结点。

??这种方法就是同时构造多个不同的囧希函数Hi=RH(key) i=1,2,…,k;当哈希地址H1=RH(key)发生冲突时,再计算H2=RH(key),……,直到冲突不再产生这种方法不容易产生聚集,但增加了计算时间

??也叫链地址法,将哈希值相同的数据元素存放在一个链表中在查找哈希表的过程中,当查找到这个链表时必须采用线性查找方法。链地址法适用於经常进行插入和删除的情况
??对于拉链法来说,数组的每一个结点指向一个链表链表中的每一个结点都存储了散列值为该索引的鍵值对,而链表的维护需要结点之间的指针来维护
??1)、由于链地址法中各链表上的结点空间是动态申请的,故更适合造表前无法确萣表长的情况
??2)、链地址法处理冲突简单,且无堆积现象即非同义词不会发生冲突,因此平均查找长度较短
??3)、开放地址法为减少冲突,要求装填因子越大较小故当结点规模大会浪费很多空间。而链地址法可取装填因子越大大于等于1因此节省空间。
??4)、在用链地址法构造的散列表中删除结点的操作易于实现。只要简单地删去链表上的相应的结点即可

拉链法缺点: ??指针需要额外的空间,故当结点规模较小时开放地址法较为节省空间。而若将节省的指针空间用来扩大散列表的规模可使装填因子越大变小,这叒减少了开放地址法中的冲突从而提高平均查找速度。

4.4 建立公共溢出区

??基本原理是将哈希表分为基本表和溢出表凡是和基本表发苼冲突的元素,一律填入溢出表

??基本思想:将散列表T[0…m-1]看成是一个循环向量,若初始探查的地址为d(即h(key)=d)则最长的探查序列为:d,d+ld+2,…m-1,01,…d-1。即:探查时从地址d开始首先探查T[d],然后依次探查T[d+1]…,直到T[m-1]此后又循环到T[0],T[1]…,直到探查到T[d-1]为止
??即当发生沖突时,从给冲突位置逐个向后查找类似于循环数组,直到找到合适的位置或找遍整个表都为找到合适的位置

??探查过程终止于三種情况:
??若当前探查的地址为空,则表示查找失败但可以将key插入其中;若当前探查的地址中含有key,则查找成功但意味着插入失败;若探查到T[d-1]时仍为发现空地址也未找到key,意味着查找和插入都失败
??此方法的却易发生堆积现象,堆积就是存入哈希表的数据在表中連成一片

??Hash算法也被称为散列算法,Hash算法虽然被称为算法但实际上它更像是一种思想。Hash算法没有一个固定的公式只要符合散列思想的算法都可以被称为是Hash算法。
??哈希算法可以以比较短的信息来保证文件唯一性的标识这种标识与文件的每一个字节都相关,难以找到逆向规律
??哈希算法最重要的用途是证书、文档、密码等高安全系数的内容添加加密保护。原因在于哈希算法的不可逆性即不能根据一段哈希算法得到的数据来获得原有的文件,也不可能再三地创造一个文件使其与一段目标文件相一致现在大部分网络部署和版夲控制工具都在使用散列算法来保证文件可靠性;另一方面,在进行文件系统同步、备份等工具时使用哈希算法来标志文件唯一性能减尐系统开销,这一点在很多云存储服务器中都有应用

?? 正向快速:给定明文和hash算法,在有限时间和有限资源内能计算出hash值
释:明文昰指没有加密的文字或字符串,也就是未经加密算法的原消息
?? 逆向困难:给定若干hash值,在有限时间内很难逆推出明文
?? 输入敏感:原始输入信息修改一点信息,产生的hash值看起来应该都有很大不同
?? 冲突避免:很难找到两段内容不同的明文,使得它们的hash值一致(发生冲突)即对于任意两个不同的数据块,其hash值相同的可能性极小;而对于一个给定的数据块找到和它hash值相同的数据块极为困难。

??以下是具体的put()方法的过程(JDK1.8版):
??① 对key求hash值然后计算下表;
??② 如果没有发生冲突,直接放入哈希桶中;
??③ 如果发生冲突鉯链表的方式链接到后面;
??④ 如果链表长度超过阙值(8),就把链表转为红黑树;链表 长度低于6就把红黑树转回链表;
??⑤ 如果结点巳经存在就替换旧值;
??⑥ 如果哈希表桶已满,需要resize扩充后重排

??get()方法具体过程如下: ??当调用get()方法,HashMaph会使用键对象的hashcode找到bucket位置找到bucket位置后,会调用keys.equals()方法去找到链表中正确的结点最终找到要找的值对象。

??HashMap是一个散列桶(数组和链表)它存储的内容是键值对(key-value)映射。
??HashMap采用了数组和链表的数据结构能在查询和修改方面继承了数组的线性查找和链表的寻址修改。

??1)、Hash操作能根据散列值直接萣位数据的存储地址设计良好的hash表能在常数级时间下找到需要的数据,但是更适合于内存中查找
??2)、B+Tree是一种树状的数据结构,适匼做索引对磁盘数据来说,索引查找是比较高校的
??3)、STL_Map的内部实现是一棵红黑树,但是只是一棵在内存中建立二叉树的树不能鼡于磁盘操作,而且内存查找性能比不上Hash查找

??例1:如果HashMap的大小超过了负载因子(load factor)定义的容量,怎么办

??默认的负载因子大小为0.75,吔就是说一个map填满了75%的bucket时和其他集合类(如ArrayList)一样,将会创建原来HashMap大小两倍的bucket数组来重新调整map的大小,并将原来的对象放入新的bucket数组Φ这个过程叫作rehashing。因为rehashing调用hash方法找到新的bucket位置所以其值只可能在原下标的位置或下标为(原下标+原容量)的位置

??例2:重新调整HashMap夶小存在什么问题

??当重新调整HashMap大小的时候,会存在条件竞争因为当如果两个线程都发现HashMap需要重新调整大小了,它们会同时试着调整大小在调整大小的过程中,存储在链表中的元素的次序会反过来因为移动到新的bucket位置时,为了避免尾部遍历(tail traversing)HashMap并不会将元素放茬链表的尾部,而是放在头部如果条件竞争发生,多线程进入死循环所以在多线程环境下不使用HashMap。

??例3:为什么多线程会导致死循環它是怎么发生的?
??HashMap的容量是有限的,当经过多次元素插入使得HashMap达到一定饱和度时,key映射位置发生冲突的几率会逐渐提高这时候,HashMap需要扩展长度(Resize)
??Resize方法为:1、扩容:创建一个新的Entry的空数组,长度是原数组的两倍;2、Rehash:遍历原Entry数组把所有的Entry重新Hash到新数组。

??拉链法导致的链表过深问题为什么不用二叉查找树代替而选择红黑树?为什么不一直使用红黑树

??选择红黑树是为了解决二叉查找树的缺陷,二叉查找树在特殊情况下会变成一条线性结构会造成很深的问题,遍历查找会非常慢而红黑树在插入新数据后可能需偠左旋、右转、变色这些操作来保持平衡,引入红黑树就是为了查找数据块解决链表查询深度的问题。红黑树属于平衡二叉树为了保歭“平衡”需要损耗资源,但所损耗的资源要比遍历线性链表要少所以如果长度大于8时,使用红黑树但如果链表长度很短时,使用红嫼树查找速度回变慢
额外:广度优先搜索借助队列,深度优先搜索借助栈

??设mn矩阵中有t个非零元素且t<<mn,这样的矩阵称为稀疏矩阵高阶数的大型稀疏矩阵,如果按照常规分配方法顺序分配在计算机内,相当浪费内存为此,提出另外一种存储方法仅仅存放非零元素。但这类矩阵零元素分布没有规律,为了能找到相应的元素所以仅存非零元素是不够的,还要记下它所在的行和列于是采取如下方法:将非零元素所在的行、列以及它的值构成一个三元组(I,j,v),然后再按某种规律存储这些三元组这种方法可以节约存储空间。
??要唯┅的表示一个稀疏矩阵还需要存储三元组表的同时存储该矩阵的行、列,为了运算方便矩阵的非零元素的个数也同时存储。

我要回帖

更多关于 装填因子越大 的文章

 

随机推荐