2025王道《数据结构》笔记

---------------------------------------------------------------------------------------------------------------------------------

声明 ①极简

        ②可能有误

        ③持续更新中

---------------------------------------------------------------------------------------------------------------------------------

五、树

一、基础

1,树

树:n个点的有限集合(递归定义的数据结构)

分支结点:有儿

叶子结点:没儿

路径长度:几条边(just从上往下数)

点的层次/深度:从上往下数

点的高度:从下往上数

点的度:有几个儿

树的高/深度:总共多少层

树的度:max(点的度)

同构:两棵树,名字不一样,其他都一样

斜树:糖葫芦串,just,全左或全右

2,树的种类

森林:m(m>=0)棵互不相交的的树的集合

满二叉树:堆满了

完全二叉树:《满》从右下角,按序号删点得到

二叉排序树:序号往左下依次-,往右下依次+

平衡二叉树:任一点的左子树和右子树的深度之差1

哈夫曼树——补充知识

点的权,表示重要性

点的带权路径长度=(根到该点经过的边数)*权值

树的带权路径长度WPL=all(叶的带权路径长度)之和

哈夫曼树(最优二叉树)

在有n个带权叶子的二叉树中,WPL最小的树

哈夫曼树——性质

1,每个初始点都成为叶子,权值越小,路径越长

2,点=2n-1

3,无(度=1)的点

4,形状不唯一,但WPL都一样,且最优

哈夫曼树——构造

哈夫曼编码——补充知识

①固定长度编码,每个字符,用等长的二进制位表示

②可变长度编码,允许对不同字符用不等长的二进制位表示

③前缀编码,无一个编码是另一个编码的前缀,无歧义

哈夫曼编码——构造

①字符集的每个字符,作为一个叶子

②字符出现频度=权值

③按哈夫曼树构造

哈夫曼编码——性质

①不唯一

②用于数据压缩

3,遍历

树的遍历

1,先根遍历(约=根左右)《深度优先遍历》

2,后根遍历(约=左右根)《深度优先遍历》

3,层次遍历《广度优先遍历》

①根入队

②队头出队,访问这个点,把它孩子入队

③重复

二叉树的遍历

①先=根左右

②中=左根右

③后=左右根

遍历⇒完整树(必须有中)

①前+中

②后+中

③层+中

线索化,对叶

①左子+前驱

②右子+后继

4,树的存储结构

①双亲表示法

定义,data+parent(指向父)

优,找父方便

缺,找儿,要遍历整个数组

适用,找父多,找子少——并查集

②孩子表示法

定义,data+*firstkid(指向儿的一条链)

优,找儿方便

缺,找父,要遍历整个数组

适用,找父少,找子多——服务流程树

③孩子兄弟表示法

定义,二叉链表,*firstkid(指向第一儿),*nextbro(指向右第一兄)

存森时,每棵树的根,视为平级的兄弟

存储结构,类似于二叉树

5,树的转换

树——>二叉树

①根放一边

②根的子,往右下,串成糖葫芦

③再依次找子的子,串成糖葫芦

④重复

                           

森林——>二叉树

同上,区别=无根,直接把第一层串起来就行

                     

二叉树——>树

一个糖葫芦,就是上面一个点的儿

                         

二叉树——>森林

第一个糖葫芦,就是森林的第一层

                     

森林的遍历
(1)先序遍历
①分别对每个子树,先序遍历
②森林——>二叉树,先序遍历

   
(2)中序遍历
①分别对每个子树,后根遍历
②森林——>二叉树,中序遍历

6,并查集

查,一路向北,查到根

并,一棵树成为另一棵树的子树

并查集——时间复杂度

1,未优化

最坏

find=最坏树高O(n)

将n个独立元素,多次并为一个集合,O(n*n)

2,优化union

最坏

find=最坏树高=O(log2n)

将n个独立元素,多次并为一个集合,O(nlog2n)

3,优化find

最坏

find=最坏树高=(α(n))

将n个独立元素,多次并为一个集合,O(nα(n))

((α(n))增长很慢,一般<=4)

二、公式

1,度=m

2,m叉树

3,二叉树

4,满二叉树

5,完全二叉树

三、tip

(1)《线树》——目的

①加速遍历

②方便找前驱后继

   

(2)删点

①删左右儿

②删该点

⇒后遍删✔

  

(3)《后线树》——缺

①难找后继

②栈

   

(4)树的《顺存》

①just,完+满

②存all点

   

(5)《二》遍历结果=唯一

    
(6)《森》——《二》(根的左子树的点)=m1-1

       
(7)《森》叶=《二》(左子=null)

     
(8)遍历关系

①森先=二先

②森后=二中

六、图

一、基础

1,图

图——定义

①点,必非空,可∞

②边

简单图

① 无重复边

② 无指向自身的边

多重图

两点之间边数>1,又有指向自身的边

路径:点序列abcd

回路/环:第一个点=最后一个点

简单路径:点不重复出现的路径

简单回路:除第一个点和最后一个点,其余点不重复出现的回路

路径长度:几条边

点到点的距离:a到b的最短路径(无,就=∞)

子图,部分点+部分边

生成子图,all点+部分边

边的权(权值):边,标上(有含义的值)

带权图/网:边,有权值

带权路径长度:带权图中,一条路上,(all边的权值)之和

稀疏图:边少

稠密图:边多

2,无向图

①边,无向,有限

②点

度,一个点,有几条边

连通:两点之间有边

无连图:无孤立点

无连图的可能形态

①树

②环

③无完图

极大连通子图/连通分量:尽可能,多点+多边

(其中,极大=该连通分量中,all点+all点依附的边)

极小连通子图:刚好连,少一边就不连

连通图的生成树:含all点的极小连通图,all点+少边

非连通图的生成森林:由连通分量的生成树构成

极大连通子图的特例

若图

①不连通
②每个子部分,含all点和边

它自己,就是极大连通子图

无完图:无中,任两点之间有边

①无回路

②无连图

3,有向图

①边,有向,有限

②点

①弧头:箭头指的(b)

②弧尾:箭尾指的(a)

①入度

②出度

③点的度=出度+入度

强连通:两点之间,有双向弧

强连通图:一点到另一点,有相反的两条路

极大强连通子图/强连通分量,多边+多点

强连通分量的特例

一点只有出边,或只有入边,该点单独构成一个强连通分量

有完图:有中,任两点之间,有双向弧

有向树

①just一(点的入度)=0

②其余(点的入度)=1

③有向图

4,邻接矩阵

邻接矩阵,用数组实现的顺序存储

邻接矩阵——特点
①求度/出度/入度,时=O(n)
②空=O(n²),稀✔,稠X
③若点的编号写好,则表示方式唯一

邻接矩阵——代码
①点的信息
②二维数组
③点数,边数

邻接矩阵——带权图代码
①点max
②∞(环=0)
③点的类型
④权值的类型
⑤点的信息
⑥权值二维数组
⑦点数,弧数

 

邻接矩阵——存无

(是对称矩阵,可压缩存储,只存上三角区/下三角区)

​A[i][j]=1有边

A[i][j]=0无边

第i个点的度=(第i行/第j列=1)的sum

邻接矩阵——存有

​A[i][j]=1,有(i——>j的弧)

A[i][j]=0,无​(i——>j的弧)

第i个点的出度 = 第i行,1的sum
第i个点的入度 = 第i列,1的sum
第i个点的度 = 第i行、第i列的1的sum之和

邻接矩阵A

A^{n}的元素,A^{n}[i][j]=由i到j,有几条路长为n

——> 

5,邻接表

邻接表——特点

①顺+链
②表示方式不唯一,边可换顺序
③稀✔,稠也✔

邻接表——存无

①边=2*实际边
②空=O(n+2e)

邻接表——存有

空=O(n+e)

邻接表——代码

①点信息
②指向点的第一条边

点数组

①点数
②边树

①指的点
②指向下一条边的指针

6,图的基操

7,广搜BFS

树的广搜=层遍

广——步骤

(1)找一点相邻的all点,用基操

    ①找第一邻点
    ②找第一邻点的下一邻点(无,返-1)

(2)标记,已访过的点

(3)辅助队列

广——完整代码

①访点
②标记
③点V=✔,入队
④if(队非空)
    ①V出队
    ②找V的邻点V1
        if(V1=X)
            ①访V1
            ②标记V1=✔
            ③V1入队

广——优化代码

①设标记数组=bool
②优()
    ①数组全=X
    ②初始化队列Q
    ③for(标记数组)
        if(X){BFS}

广——时空,不看代码,看矩和表

①空,最坏=O(n)
②时

广度优先生成树

(高度min的树)

表示方式广树形态
唯一唯一
不唯一不唯一

8,深搜DFS

树的深搜=先根

深——未优化代码

①标记数组设为bool
②DFS(图,点)
    ①访点
    ②点,标=✔
    ③for(第一邻点,第二邻点)
        if(第一邻点=X){DFS}

深——优化代码

①for(图)
    标记数组,全=X
②for(图)
    if(点=X){DFS}

深——时空

①空

最坏=O(n)

最好=O(1)


②时

9,广深对比

广深——共性

(1)广、深序列

(2)

无,调次=连通分量数

有,调次

        ①if起始点,到每个点都有路,1次

        ②有强连,从哪开始,都是1次

广深——步骤区别

(1)广
头(all邻点)

(2)深
头(头的第一邻点A——>A的下一邻点)——>头的第二邻点

十字链表
解决表——存有时,入边和出边重复
  
邻接多重表
解决表——存无时,边冗余

10,最小生成树MST

带权无连图G——>all生成树R——>最小生成树T

                                                     (R中边的权值之和min)

MST——性质

①形态可多样,但边权值之和all一样,且min
②if一无连,本身就是树,其MST就是自己
③just连,有生成树

④非连,just有生成森林

边=点-1

边+1⇒一个环

边-1⇒不连

求MST的算法

(1)Prim算法(普里姆)

①从一点,开始建树
②每次把,代价min的新点,加入树
③重复,直到all点加入

                  
(2)Kruskal算法(克鲁斯卡尔)

①每次选,一条权值min的边
②使该边的两头连(已连的不选)
③重复,直到all点连

算法——时

(1)Prim=O(n²)

for(n-1)

  ①for(n),找LowCast中min的点
  ②for(n),更新(X的LowCast值)
准确来说,O(n-1)*O(2n)

               

(2)Kruskal=O(e*log2(e))

①边,按权值排序
②看,第1条边的两头,连不连(用并查集判断)
               2

               3

               4

              ***

               n

BFS——求无权图的单源最短路径

(all权值一样的带权图,也能求)

d[]——各点到源点,的min路长

path[]——各点的直接前驱

        

BFS_找最短路(图,源点)

(1)for(图)
    ①d[i]=∞
    ②path[i]=-1
(2)d[源点]=0
(3)标记数组[源点]=✔
(4)入队(Q。源点)
(5)while(队非空)
    ①出队(Q,源点)
    ②for(W=第一邻点(图,源点);W=all邻点(图,源点,W);W++)
        if(标记数组[W]=X)
            d[W]=d[源点]+1
            path[W]=源点
            标记数组[W]=✔
            入队(Q,W)

11,Dijkstra

Dijkstra——步骤

(1)初始化

①若从V0开始,设final[0]=✔

                             dist[0]=0

                             path[0]=-1
②其余点,设final[i]=X

                     dist[i]=arcs[0][i]

                     path[i]=(arcs[0][i]=∞)? -1:0

          

(2)n-1轮处理
①遍历all点,找到点a,有final[a]=X,令final[a]=✔

                                         dist[a]最小

  
②看a的all邻点b,若final[b]=X                        ,令dist[b]=dist[a]+arcs[a][b]

                                 dist[a]+arcs[a][b]<dist[b]        path[b]=a
 

(准确来说,时=O(n-1)*O(2n))

Dijkstra,重复n次——>可求带权图中,all点间的最短路径,时=O(n³)

12,Floyd

①动态规划
②求每一对点之间的最短路径

Floyd——步骤

(1)初始化,无中转点和中转路径

    
(2)n次循环


①允许在V0中转⇒
②允许在V1中转⇒
             V2        ⇒
             ***
             Vn-1      ⇒

Floyd——例子

(1)初始化

                   

(2)n次循环

①允许在V0中转

②允许在V1中转

               ***

允许在Vn-1中转

Floyd——代码

for (int k = 0; k < n; k++) {//以Vk为中转点
		for (int i = 0; i < n; i++) {//遍历矩阵
			for (int j = 0; j < n; j++) {
				if (A[i][j] > A[i][k] + A[k][j]) {//以Vk为中转点的路径更短
					A[i][j] = A[i][k] + A[k][j];//更改最短路长
					path[i][j] = k;//中转点
				}
			}
		}
	}

Floyd——时空

时=O(n³)
空=O(n²)

BFSDijkstraFloyd
X
负权图XX
负权回路XXX
O(n²)或O(n+e)O(n²)O(n²)
适用无权图的单源最短路带权图的单源最短路带权图中各点间的最短路

13,拓扑排序

有向无环图DAG——描述表达式

(多形态)
①把点,不重复的排成一排
②标,运算符顺序
③按序,加入运算符,分层
④自底向上,看同层可否合体

有向无环图DAG——例子

                       

AOV网,用点表示活动的网
(是DAG,必无环)

拓扑排序——定义
(找做事的先后顺序)

    
当一个由有向无环图的点组成的序列,满足
①每个点,just出现一次
②若A在B前面,必无A<——B的路

拓扑排序——步骤
在AOV网中
①找一无前驱的点,并输出
②删该点
       all该点指向的边
③重复①②,直到网空
              网中,无(无前驱的点)⇒有环

拓扑排序——时

O(n²)
O(n+e)

拓扑排序——代码

逆拓扑排序——步骤
在AOV网中
①找一无后继的点,并输出
②删该点
      all指向它的边

逆拓扑排序_DFS——代码

(在点退栈前输出)

14,关键路径

AOE网(用边表示活动的网络)

有带无环图中

①点——事件
②边——活动
③边权——完成该活动的开销

AOE网——性质

①just点发生后,点所指的边,才能开始
②just点的入度边,all结束时,该点才能发生
③点可并行

源点

①just一个
②入度=0
③表示整个工程的开始

汇点

①just一个
②出度=0
③表示整个工程的结束

关键路径

从源点到汇点,的all路中,路长max

关键活动

关路上的活动(边)

结论

①完成整个工程的min时=关路的长
②关活,耗时↗,工期↗

③关活,时↘,可能变成非关活
④关路,可能有多条
⑤加快all关路上的关活,工期才↘

关键路径——步骤

二、公式

1,无向图

2,有向图

三、tip

(1)图的遍历,每个点,just被访1次

      
(2)对无连图深搜,可访问到all点

        
(3)不是图

       

(4)图的点,可∞个

       
(5)连通分量中,可能有回路

      
(6)有向图的矩,若对角线以下,全=0——>无环

           
(7)矩,若主对角线,全=0——>每个点,无指向自己的边

          
(8)无完/有完,矩

①主=0
②其余=1

             

(9)判,有向图,有无环

①拓
②深

③关路

            

(10)不是环

①简单路径
②最短路径

           

(11)Floyd,求每对点间的最短路

①边权,可=负
②不可有,含负边的环

      

(12)修改深

输出后,马上退出栈⇒序列=逆拓扑

    

(13)无连,权all=1

广,可求从某点,到其余点的最短路

   

(14)若有的拓,序列唯一

①X,每个点,入度≤1,出度≤1
②✔,入度=0的点仅一个,出度=0的点仅一个

七、查找

一、基础

1,查找

查找

在数据集合中,找数据元素

查找表(查找结构)

①⽤于查找的数据集合
②由同类型的数据元素(或记录)组成

关键字

①数据元素中,唯⼀标识该元素的某个数据项的值
②基于关键字的查找,查找结果唯⼀

(1)静态查找表

just查

                        

(2)动态查找表

①查

②插入、删

查找⻓度

对⽐关键字的次数

平均查找⻓度(ASL, Average Search Length)

所有查找过程中,进⾏关键字的⽐较次数,的平均值

ASL=∑PiCi (i=1,2,3,…,n)

2,顺序查找

顺查——视频代码

//顺序表
typedef struct{
    int *p;//动态数组基址
    int len;
};sb

//顺查
int f(sb a,int key){
    for(int i=0;i<len&&a.p[i]!=key;i++)
    {return i==a.len ? -1:i;}
}
//✔,返坐标
//X,返-1

顺查——课本代码

//顺序表
typedef struct{
    int *p;//动态数组基址
    int len;
};sb

//顺查
int f(sb a,int key){
    a.p[0]=key;//哨兵
    
    for(int i=a.len;a.p[i]!=key;i--) return i;
}
//✔,返坐标
//X,返0

变化

①0号位置空出来,放哨兵
②从1号开始,存数据
 

不用判越界

顺查优化——有序表

用查找判定树,分析ASL

一个成功点的查长=自身所在层

       失败                 父

3,折半查找(二分查找)

just适用于有序的顺序表

折——代码

//顺序表
typedef struct{
    int *p;
    int len;
}sb;

//折
int f(sb a,int key){
    int low=0;
    int high=a.len-1;
    int mid;

    while(low<=high){
        mid=(low+high)/2;
        if(a.p[mid]==key) reutrn mid;//✔
        if(a.p[mid]>key)  high=mid-1;//往左走
        if(a.p[mid]<key)  low=mid+1;//往右走
    }

    return -1;//X
}
//代码不能正常运行,just为了美观简洁

折树

①平二树,just最后一层不满
②二排树,左<中<右
③失败点=n+1=空链表
④若mid=(low+high)/2,对任一点,右子树的点-左=0/1

⑤点=n——>h=log2(n+1)——>查✔,ASL≤h
                                                 查X,ASL≤h

⑥时=O(log2n)

4,分块查找

分——特点
①块内无序
②块间有序

分——代码

//索引表
typedef struct{
    int maxv;
    int low,high;    
}index;

//顺序表存的元素
int list[100];

分——步骤
(1)在索引表中,找对应分块
①顺

②折
(若索引表中无目标,此时折索表,停在low>high,要在low所指分块中找)
(2)在块内顺查

分——时

5,二叉排序树(二叉查找树)

二排——定义
①可空
②左<根<右
③左、右子树,all是二排
(中遍——>递增序列)
④点不能重复

二排——时
=查长=O(log2n     +1)

查最坏情况,糖葫芦=O(n)

二排——代码

//二排树
typedef struct{
    int k;
    struct node *l,*r;    
}node,*tree;

//查——非递归(空复=O(1))
node *f_find(tree a,int k){
    while(a非空&&k!=a->k){
        if(k<a->k) a=a->l;       
        if(k>a->k) a=a->l;       
    }
    return a;
}

//查——递归(空复=O(h))
node *f_find(tree a,int k){
    if(a空) return null;                 //树空,X
    if(k=a->k) return a;                 //=根,✔
    if(k<a->k) return f_find(a->l,k);    //<根,查左儿
    if(k>a->k) return f_find(a->r,k);    //>根,查右儿
}

//插——递归
int f_insert(tree a,int k){
    if(a空){
        a=(tree)malloc(sizeof(node));
        a->k=k;
        a->l=a->r=空;
        return 1;
    }                                   //树空,X
    if(k=a->k) return 0;                //=根,✔
    if(k<a->k) return f_insert(a->l,k); //<根,查左儿
    if(k>a->k) return f_insert(a->r,k); //>根,查右儿
}
//新插入的点,包是叶——>空=O(h)

//构
void f_create(tree &a,int str[],int n){
    a=空;
    int i=0;
    while(i<n){
        f_insert(a,str[i]);
        i++;        
    }    
}
//不同的关键字序列,可能得到,相同的树

删——步骤
(1)叶,直接删,无影响

  
(2)just左儿,或,just右儿

让k的儿,替代k

      
(3)左右儿,all有
①让k的直接前驱,替代k
            直接后继
②删该直接前驱
          直接后继

         


①直前,左儿中最右下的点,包无右儿
②直后,右儿中最左下的点,包无左儿

6,平衡二叉树AVL

定义

任一点的左、右子树的高度差≤1

点的平衡因子=左子树的高-右子树的高

(平二树,每个点的平衡因子,just=-1/0/1)

平二树——代码

//平二树——点
typedef struct node{
    int k;       //数据域
    int balance; //平衡因子
    struct node *l,*r;
}node,*tree;

二排树,插之后,how保持平衡

①从插入点,往上找,第一个不平衡点A
②调整以A为根的树(最小不平衡树)

调整最小不平衡树——目标

①恢复平衡
②保持二排特性(左<根<右)

调整最小不平衡树——原因

插入时,只要调整最小不平衡树,让它平衡,其他祖先点都会平衡

最小不平衡树——情况

①LL,对A的L,右旋
②RR,对A的R,左旋
③LR,对A的LR,左旋,再右旋
④RL,对A的RL,右旋,再左旋

平二树——时

平二树——删步骤

①按二排删,删点
②往上找,最小不平衡树A,无就end
③找A下面,最高的儿和孙
④根据孙,调整A
⑤if不平衡向上传导,继续②

(平二删——时=O(log2n))

7,红黑树RBT

定义

①点=红/黑
②根=黑
③叶(外部点、NULL点、失败点)all=黑
④父子不能同时=红
⑤每个点,从该点,到其他点的路上,黑相同(黑高bh)

定义——简记

①左根右
②根叶黑
③不红红
④黑路同

红黑树——代码

struct node{
    int k;
    node* dad;
    node* l;
    node* r;
    int color;
}

红黑树——性质

红黑树——插
(1)按左<根<右,插
  
(2)新点=根,染黑
    新点≠根,染红
①if插新点,红黑树✔,end
②if插新点,红黑树X,看叔色
  黑叔
  LL,右旋,父爷换色
  RR,左旋,父爷换色
  LR,先左旋,再右旋,儿爷换色
  RL,先右旋,再左旋,儿爷换色

  

  红叔
  叔父爷换色,爷变新点

红黑树——删
①时=O(log2n))
②=二排删
③删后,会破坏红黑特性,需调整

8,B树(多路平衡查找树)

5叉查找树——代码
 

struct node{
    int k[4];           //关键字
    struct node* kid[5];//儿
    int num;            //点中,有几个关键字
}

5叉查找树——↑ 查效率
①除了根,all点,分叉≥⌈m/2⌉,关键字≥⌈m/2⌉-1(向上取整)
②all点,其所有子树的高相同

B树的阶,max(儿个数),⽤m表示

B树——定义
空树,或满⾜如下性质的m叉树
①all点,⼦树≤m,关键字≤m-1
②if根≠终端结点,⼦树≥2
③除了根,all点,分叉≥⌈m/2⌉,关键字≥⌈m/2⌉-1
④非叶点,结构如下

ki,关键字,k1<k2<...<kn
      
pi,指针
pi-1所指子树<ki
pi所指子树>ki
       
n,关键字个数(⌈m/2⌉-1≤n≤m-1)
⑤all叶在同一层,无信息(=失败结点)

B树——核心性质
①根,       ⼦树∈[2, m],        关键字∈[1,m−1]
   其他点,⼦树∈[⌈m/2⌉,m],关键字∈[⌈m/2⌉−1,m−1]
②all点,其所有子树的高相同
③⼦树0<关键字1<⼦树1…. (≈左<中<右)

B树——高

B树——插
①插后,if点,关键字>上限,则从中间位置⌈m/2⌉二分,左放在原点,右放到新点,《中》插⼊原点的⽗
(若⽗的关键字也>上限,重复①,直⾄传到根为⽌,导致B树h+1)
②新元素,包是,插到最底层的终端点

B树——点

①叶——失败点
②终端点——失败点上面一层

B树——删
若被删关键字
(1)在终端点
直接删
     
(2)在⾮终端点
⽤直前/直后,替代被删的关键字
①直接前驱:当前关键字,左⼦树中,最右下元素
②直接后继:当前关键字,右⼦树中,最左下元素
            
(3)所在点
①删之后的关键字<下限
②兄富
左兄富,⽤当前点的前驱、前驱的前驱,填空
右兄富,⽤当前点的后继、后继的后继,填空
            
(4)所在点
①删之后的关键字<下限
②兄穷
③左右兄的关键字=⌈m/2⌉ − 1
删后,则合并(左/右兄+父)的关键字

合并——注
合并时,父的关键字会-1

①父=根
②父的关键字=0
则删根,让合并后的新点成为新根
          

①父不等于根
②父的关键字=⌈m/2⌉ − 2
则父与其兄调整,重复,直到满足B树

9,B+树

B+树——点

①叶——就是普通树的叶
②分支点——非叶的点

B+树,查✔或X,all查到最后一层

B+树,just叶,存记录
B树,每个点,存(关键字+记录+地址)

B+树——定义
①分支点,儿≤m
②根,      关键字∈[1,m]
   其他点,关键字∈[⌈m/2⌉,m]
③点,儿=关键字
④叶,存(关键字+记录的指针)
   分支点,存(关键字max+儿指针)
   叶中,关键字按大小排列,相邻叶,顺序链接——>可顺查

B树和B+树——区别

①B,  关键字=n,子树=n+1
    B+,关键字=n,子树=n
②关键词区间,不同
③B,  关键字不重复
    B+,关键字可能重复
④点存的信息,不同

数据库,索引功能常用B+树实现

10,散列表(哈希表)

散——定义
①⼀种数据结构
②特点,可根据数据元素的关键字,算出它在散列表中的存储地址

散列函数(哈希函数)
Addr=H(key)
关键字→存储地址,的映射关系

冲突(碰撞)
在散中,插一元素时,需根据关键字确定地址,该地址已存了其他元素

同义词
不同的关键字,通过散列函数,映射到同⼀个地址

散函——注意
Addr=H(key)
①定义域key,含all关键字
②值域Addr,≤散表的地址范围
③少冲突,Addr,要匀布在地址空间
④散函H,要简单,能快算出key对应的Addr

散函——构造
①除留余数法,H(key)=key%p
(表长=m,取质数p,≤m且接近m)

   
②直接定址法,H(key)=a*key+b
(最简单,无冲突。若关键字不连续,空位多浪费)

           
③数字分析法,选数码分布较为均匀的若⼲位
(在某些位上,分布均匀)

        
④平⽅取中法,选关键字的平⽅值的中间⼏位

散函——适用
①除,通⽤,关键字=整
②直,关键字连续分布
③数,关键字已知,且关键字的某⼏个数码位分布均匀
④平,关键字的每位取值,all不均匀

解决冲突——方法
①拉链法
②开放定址法

拉链法

拉——插
①用散函,算地址
②把新元素,插入地址对应的链表

   

拉——查

①用散函,算地址
②顺查地址对应的链表,直到查✔/X
(查长,只统计关键字的对比次数,空指针的对比次数不计入)

   

拉——删

①用散函,算地址
②顺查地址对应的链表,if查✔,删

开放定址法——原理
①有冲突,就给新元素找空位
②开放定址,指地址,对同义词、⾮同义词all开放

开放定址法——方法
①线性探测法,    di=0, 1, 2, 3, …, m-1
②平方探测法,    di=0²,1²,-1²,2²,-2²...,k²,-k²
③双散列法,        di=i×hash2(key)
④伪随机序列法, di=0, 5, 3, 11, …

Hi = (H(key) + di) % m
Hi ,第 i 次冲突的地址
H ,初始地址
di,偏移量
m,散列表长

开放定址法——查/插
①根据探测序列,依次对⽐关键字
②探到⽬标关键字,查✔
   探到空单元,查X

开放定址法——删
①散函算地址,对⽐关键字是否匹配。若匹配,则查✔
②若关键字不匹配,根据探测序列,对⽐下⼀个关键字,直到查✔/查X
③查✔,则删元素
(只能逻辑删,标记“已删”)——>查效率低,散列表看起来满,实则很空

开放定址法——探测覆盖率
①线,经m-1次冲突,包能探到all
②平,至少能探到一半(若表长m=4X+3的素数,则能探到all)
③双,若hash2(key)与m互质,则经m-1次冲突,包能探到all
④伪,just伪随机序列合理,包能探到all

八、排序

一、基础

排序
重新排列表中元素,使元素按关键字有序

稳定性
关键字相同的元素,在排序之后相对位置不变

排序算法
(1)内部排序,data都在内存
①时
②空
(2)外部排序,data多,无法全放内存
①时
②空
③读写磁盘次数

2,插入排序

算法思想
每次将⼀个待排序的记录按其关键字⼤⼩,插⼊到前⾯已排好序的⼦序列中,直到全部记录插⼊完成

直接插入排序——步骤
void f(待排序数组A,A的长){
    i-待排序位置
    j-i左边的元素
    t-暂存A[i]
    
    for(i从1到n-1循环)
        if(A[i]<)
}

//直接插入排序——代码
void f(int A[],int n){
    int i,j,t;
    for(i=1;i<n;i++)
        if(A[i]<A[i-1]){
            t=A[i];
            for(j=i-1;j≥0&&A[j]>t;j--)
                A[j+1]=A[j];
            A[j+1]=t;
        }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值