408---冷门知识点总结

发布时间 2023-12-21 23:16:48作者: TLSN

博客园的排版有点抽象...

DS

KMP

https://www.cnblogs.com/lordtianqiyi/p/17795838.html

并查集

手搓并查集代码+两种优化

#include <stdio.h>
#include <math.h>
int find(int A[],int m);
void Init(int A[],int len){
    for(int i=0;i<len;i++)A[i]=-1; 
}

void debug(int A[],int len){
    for(int i=0;i<len;i++) printf("%3d ",A[i]);
    puts("");
}
void Union(int A[],int x1,int x2){
    int root1 = find(A,x1);
    int root2 = find(A,x2);
    if(root1 != root2){
        A[root1] = root2;        // 把x1合并到x2中 
    }
}

int find(int A[],int m){
    if(A[m] < 0) return m;
    return find(A,A[m]);
}


int optfind(int A[],int m){
    if(A[m] < 0) return m;
    int root = find(A,A[m]);
    A[m] = root;               // 让路过的元素都指向root
    return root;    
}
void opt1Union(int A[],int x1,int x2){
    int root1 = optfind(A,x1);
    int root2 = optfind(A,x2);
    if(root1 != root2){
        A[root1] = root2;        // 把x1合并到x2中 
    }
}

void opt2Union(int A[],int x1,int x2){      // 结点小的树合并到结点多的树,俗称大树合并到小树
    int root1 = optfind(A,x1);
    int root2 = optfind(A,x2);
    if(root1 == root2) return ;
    if(abs(A[root1]) > abs(A[root2])){  // 越大的结点越多
        A[root1] += A[root2];
        A[root2] = root1;         
    }else{
        A[root2] += A[root1];
        A[root1] = root2;  
    }
}


int main(){
    int A[20] = {0};
    Init(A,20);


    // Union(A,1,2);
    // debug(A,10);
    // Union(A,3,2);
    // debug(A,10);
    // Union(A,5,6);
    // debug(A,10);
    // Union(A,7,6);
    // debug(A,10);
    // Union(A,2,4);
    // debug(A,10);
    // Union(A,6,4);
    // debug(A,10);

/*
           4

    2              6

1       3       5       7

*/
/*
 -1   2  -1  -1  -1  -1  -1  -1  -1  -1 
 -1   2  -1   2  -1  -1  -1  -1  -1  -1 
 -1   2  -1   2  -1   6  -1  -1  -1  -1 
 -1   2  -1   2  -1   6  -1   6  -1  -1 
 -1   2   4   2  -1   6  -1   6  -1  -1 
 -1   2   4   2  -1   6   4   6  -1  -1 
*/


    // opt1Union(A,1,2);
    // debug(A,10);
    // opt1Union(A,3,2);
    // debug(A,10);
    // opt1Union(A,5,6);
    // debug(A,10);
    // opt1Union(A,7,6);
    // debug(A,10);
    // opt1Union(A,2,4);
    // debug(A,10);
    // opt1Union(A,1,6);
    // debug(A,10);




/*
    4
            
    2                            6

1       3                   5       7

*/
// =========> opt1Union(1,6)
/*

                6

1       2       4        5      7
        
        3

*/

/*
 -1   2  -1  -1  -1  -1  -1  -1  -1  -1 
 -1   2  -1   2  -1  -1  -1  -1  -1  -1 
 -1   2  -1   2  -1   6  -1  -1  -1  -1 
 -1   2  -1   2  -1   6  -1   6  -1  -1 
 -1   2   4   2  -1   6  -1   6  -1  -1 
 -1   4   4   2   6   6  -1   6  -1  -1 
*/
// 在把1合并到6结点的时候可以发现,find函数并不是把1所在的子树的所有结点都连接到6结点下,而是先把1所在子树的结点都指向1所在子树的根,再把根指向6所在结点的根
// 可以看这种图: https://img2023.cnblogs.com/blog/2433096/202311/2433096-20231130194814117-562472168.png
    


    opt2Union(A,1,2);
    debug(A,10);
    opt2Union(A,3,2);
    debug(A,10);
    opt2Union(A,5,6);
    debug(A,10);
    opt2Union(A,7,6);
    debug(A,10);
    opt2Union(A,2,4);
    debug(A,10);
    opt2Union(A,1,6);
    debug(A,10);

/*

 -1   2  -2  -1  -1  -1  -1  -1  -1  -1 
 -1   2  -3   2  -1  -1  -1  -1  -1  -1 
 -1   2  -3   2  -1   6  -2  -1  -1  -1 
 -1   2  -3   2  -1   6  -3   6  -1  -1
 opt2Union(A,2,4); //我们原本想让2合并到4,但由于2是大树,故只能4合并到2
 -1   2  -4   2   2   6  -3   6  -1  -1 
 -1   2  -7   2   2   6   2   6  -1  -1 

*/


    return 0;
}

并查集时间复杂度分析

1、朴素算法

一次Find 最坏时间复杂度 : O(n)

总体是O(n^2)的时间复杂度

2、小树并到大树

一次Find 最坏时间复杂度 : \(O(log_2n)\)

总体是 : \(O(log_2n)\)

3、路径压缩

一次Find 最坏时间复杂度 : O(α(n))

总体是 : O(n · α(n))

计算强连通分量个数

十字链表法

image-20231129174020200

十字链表法优化了邻接表找入结点不方便的情况

基本概念

1、十字链表法仅适用于存储有向图

2、十字链表法优化了了邻接表计算图中顶点入度的问题

3、十字链表法的普通结点结构

img

4、十字链表法的顶点结构

image-20231129173939127

十字链表法的结构体定义

#define  MAX_VERTEX_NUM 20
#define  InfoType int//图中弧包含信息的数据类型
#define  VertexType int
typedef struct ArcBox{
    int tailvex,headvex;//弧尾、弧头对应顶点在数组中的位置下标
    struct ArcBox *hlik,*tlink;//分别指向弧头相同和弧尾相同的下一个弧
    InfoType *info;//存储弧相关信息的指针
}ArcBox;
typedef struct VexNode{
    VertexType data;//顶点的数据域
    ArcBox *firstin,*firstout;//指向以该顶点为弧头和弧尾的链表首个结点
}VexNode;
typedef struct {
    VexNode xlist[MAX_VERTEX_NUM];//存储顶点的一维数组
    int vexnum,arcnum;//记录图的顶点数和弧数
}OLGraph;

根据有向图画出十字链表

https://www.cnblogs.com/lordtianqiyi/p/17739953.html

总结:

  1. 先化成邻接表
  2. 同一行(具有同一尾域)的结点自上而下按头域相连,头结点的头域指向第一个结点

邻接多重表

image-20231129175819612

邻接矩阵遍历的时候必须全部结点都遍历一遍,时间复杂度很高,可以用临界多重表优化

基本概念

1、邻接多重表用于表示无向图

2、优化了在无向图中操作顶点的效率

在邻接表中,容易求得顶点和边的各种信息,但在邻接表中求两个顶点之间是否存在边而对边执行删除等操作时,需要分别在两个顶点的边表中遍历,效率较低

3、临界多重表的头节点结构

image-20231129175739746

4、临界多重表的普通结点结构

image-20231129175757383

邻接多重表的数据结构定义

#define MAX_VERTEX_NUM 20                   //图中顶点的最大个数
#define InfoType int                        //边含有的信息域的数据类型
#define VertexType int                      //图顶点的数据类型
typedef enum {unvisited,visited}VisitIf;    //边标志域
typedef struct EBox{
    VisitIf mark;                           //标志域
    int ivex,jvex;                          //边两边顶点在数组中的位置下标
    struct EBox * ilink,*jlink;             //分别指向与ivex、jvex相关的下一个边
    InfoType *info;                         //边包含的其它的信息域的指针
}EBox;
typedef struct VexBox{
    VertexType data;                        //顶点数据域
    EBox * firstedge;                       //顶点相关的第一条边的指针域
}VexBox;
typedef struct {
    VexBox adjmulist[MAX_VERTEX_NUM];//存储图中顶点的数组
    int vexnum,degenum;//记录途中顶点个数和边个数的变量
}AMLGraph;

邻接多重表的画法

https://www.bilibili.com/video/BV1Ae41137Jd/?spm_id_from=333.337.search-card.all.click&vd_source=87f7ad8544d4c3ad070c5c2ff28b7698

https://www.bilibili.com/video/BV1TL411b7V3/?spm_id_from=333.788.recommend_more_video.-1&vd_source=87f7ad8544d4c3ad070c5c2ff28b7698

image-20231129180536419

广度/深度优先树

由于采用邻接表的存储方式可能出现不同的情况,因此广度/深度优先树不唯一

而采用临界矩阵的存储方式形式唯一,因此广度/深度优先树唯一

另外,如果题目明确给出了广度/深度优先数的邻接表存储方式,那么其广度/深度优先树唯一

散列表(数字分析法、平方取中法、平方探测法、双散列法)

散列表包含了散列函数的构造方法与处理冲突的方法

散列函数的构造方法包括了直接定值法、除留余数法、数字分析法与平方取中法

处理冲突的方法包括了开放定址法(线性探测法、平方探测法、双散列法、伪随机法)与拉链法

散列函数的构造方法

1、数字分析法

设关键字是进制数(如十进制数),而个数码在各位上出现的频率不一定相同,可能在某些位上分布均匀一些,每种数码出现的机会均等:而在某些位上分布不均匀,只有某几种数码经常出现,此时应选取数码分布较为均匀的若干位作为散列地址。这种方法适合于已知的关键字集合,若更换了关键字,则需要重新构造新的散列函数。

举个例子:

手机号前三位是接入号,中间四位是 HLR 识别号,只有后四位才是真正的用户号,也就是说,如果手机号作为关键字,那么极有可能前 7 位是相同的.此时我们选择后四位作为散列地址就是不错的选择

2、平方取中法

即取关键字平方的中间位数作为散列地址

举个例子:

比如假设关键字是 4321,那么它的平方就是 18671041,抽取中间的 3 位就可以是 671,也可以是 710,用做散列地址

平方取中法比较适合不知道关键字的分布,而位数又不是很大的情况

处理冲突的方法---开放定址法

线性探测法的缺点就是容易造成聚积

1、平方探测法

平方探测法又叫二次探测法

image-20231128140523430

平方探测法是一种处理冲突的较好方法,可以避免出现“堆积”问题,它的缺点是不能探测到散列表上的所有单元,但至少能探测到一半单元。

2、双散列法

img

https://www.bilibili.com/video/BV1fg411o71b/?spm_id_from=333.337.search-card.all.click&vd_source=87f7ad8544d4c3ad070c5c2ff28b7698

需要注意的是h1与h2的算法

image-20231128143800365

3、再散列法

image-20231128143117011

不易产生聚集

查找

AVL树(常考知识点)

这里记录一下LL、RR、LR、RL旋转的时候的枢轴的选择

1、LL或RR

image-20231129164136783

旋中间

2、LR或RL

image-20231129164228876

image-20231129164300511

找到最小不平衡子树,向下包住3个,即可以进行旋转,第一次旋转三个数最下面的,第二次旋中间

红黑树

红黑树性质

1、根结点、叶结点(虚构的外部结点)是黑的

2、不存在两个相邻的的红结点(父/孩结点不能同时为红色)

3、对每个结点,从该结点到任一叶结点的简单路径上,所含黑结点的数量相同。

4、黑高 : 从某结点出发(不含该结点)到达一个叶结点的任一简单路径上的黑结点总数称为该结点的黑高

5、从根到叶结点的最长路径不大于最短路径的2倍

原因:

  1. 当根到任一叶结点的简单路径最短时,这条路径必然全由黑结点组成

  2. 当路径最长时,一定是黑红相见

6、有n个内部结点的红黑树的高度 \(h ≤ 2log_2(n+1)\)

7、新插入红黑树的结点初始着色为红色

如果新插入结点着色为黑色,那么这个结点所在路径比其他路径多出一个黑结点,破环了性质5,需要进行调整,比较麻烦

如果新插入结点的着色是红色,仅需出现连续的两个红结点才需调整

红黑树的插入

设结点z为将要插入的结点

  1. 若插入的z为根节点,则将其着色为黑色

  2. 按二叉排序树的方法插入,着色为红色。若z的父节点为黑色,则不进行任何处理

  3. 若z不是根节点且父节点为红色,则分三种情况

首先,要明白,z的父节点为红色的花,z的爷节点一定为黑色

1、z的叔节点y是黑色的,且z是一个右孩子

没有叔叔也把叔叔当成黑色处理

image-20231010115020661

LR,先左旋,再右旋。先做一次左旋将此情形转变为情况2(变为情况2后再做一次右旋),左旋后z和父结点z.p交换位置,情况2在下面

2、z的叔节点是黑色的,且z是一个左孩子

LL,做一次右旋,并交换z的原父结点和原爷结点的颜色

3、z的叔节点y是红色的

image-20231010115318701

情况3,将z.p和y都着为黑色,将z.p.p着为红色,然后,把z.p.p作为新结点z来重复循环,指针z在树中上移两层

这里注意C结点的父节点可能也是红的,这时候要向上继续处理(把C当作新插入结点)

总结

image-20231010115719654

https://www.bilibili.com/video/BV1fw41117zt/?p=3&spm_id_from=pageDriver

1、父黑直接插

2、父亲红看叔叔(暗含爷爷黑)

(1)、叔红则交换爷与父叔的颜色 => 爷从黑变红,父、叔从红变黑

(2)、叔黑看自己

①、自己为父的左子树: 右旋且交换父爷色

②、自己为父的右子树: LR,即先交换自己和父亲的位置,使之变为①情况,再右旋变父爷色

ps: 每次旋转的时候都以 爷、父、己 三个点为旋转点,RR/LL的时候以中间点为旋转轴,RL/LR的时候现以最低点为旋转轴,再以中间点为旋转轴(与AVL树类似)

且旋转前后不改变黑色个数

B/B+树

image-20231129152401327

image-20231129152351470

B树的引出

B树和B+树的出现是因为磁盘IO;众所周知,IO操作的效率很低,那么,当在大量数据存储中,查询时我们不能一下子将所有数据加载到内存中,只能逐一加载磁盘页,每个磁盘页对应树的节点。造成大量磁盘IO操作(最坏情况下为树的高度)。平衡二叉树由于树深度过大而造成磁盘IO读写过于频繁,进而导致效率低下。所以,我们为了减少磁盘IO的次数,就你必须降低树的深度,将“瘦高”的树变得“矮胖”。一个基本的想法就是:

  1. 每个节点存储多个元素
  2. 摒弃二叉树结构,采用多叉树

这样就引出来了一个新的查找树结构 ——多路查找树(multi-way search tree)。 一颗平衡多路查找树自然可以使得数据的查找效率保证在O(logN)这样的对数级别上。

B树的缺点与B+树的引出

https://juejin.cn/post/6844903955542048782

在B-Tree结构中每个节点不仅存储数据的key值,还存储数据的data值。而每一个页的存储空间是有限的,如果data数据较大时将会导致每个节点(即一个页)能存储的key的数量很小,当存储的数据量很大时同样会导致B-Tree的深度较大,增大查询时的磁盘I/O次数,进而影响查询效率。

可以这样理解: B树的非叶结点中即存指向下一层的指针由存数据,数据占据了我们存放指针的空间,这就导致树的高度变高,查找深度增加,于是变引出了只存指针的B+树

B树概念

1、B树又叫多路平衡查找树

2、B树中结点中孩子的最大值称为B树的阶

B树性质

1、每个结点至多有m棵子树,至多有m-1个关键字

2、除根结点每个结点至少有\(\lceil m/2 \rceil\)棵子树,至多有\(\lceil m-1 \rceil-1\)个关键字

3、若根节点不是终端结点,则至少有两个子树,即一个关键字,若其是终端结点,那至少可以有一个关键字

4、所有叶结点都在同一层,并且不带信息(可视为查找判定树的查找失败结点,实际上这些结点不存在,指向这些结点的指针为空)

B+树的性质(对比B树)

1、B树结点的子树的个数与关键字个数相同

5、叶结点包含了全部关键字,非叶结点仅起索引作用。即在非叶结点中出现的关键字也会出现在叶结点中:

而在B树中,叶结点(最外层内部结点)包含的关键字和其他结点包含的关键字是不重复的。

6、所有分支结点(可视为索引的索引)中仅包含它的各个子结点(即下一级的索引块)中关键字的最大值及指向其子结点的指针

B/B+树的时间复杂度

1.B树非叶子结点和叶子结点都存储数据,因此查询数据时,时间复杂度最好为O(1),最坏为O(log n)。

B+树只在叶子结点存储数据,非叶子结点存储关键字,且不同非叶子结点的关键字可能重复,因此查询数据时,时间复杂度固定为O(log n)。

2.B+树叶子结点之间用链表相互连接,因而只需扫描叶子结点的链表就可以完成一次遍历操作,B树只能通过中序遍历。

B树的查找

B树的查找包含两个基本操作:①在B树中找结点;②在结点内找关键字。由于B树常存储在磁盘上,因此前一个查找操作是在磁盘上进行的,而后一个查找操作是在内存中进行的,即在找到目标结点后,先将结点信息读入内存,然后在结点内采用顺序查找法或折半查找法

B树的插入

插入过程还是很简单的,一直向上挤就行了

https://mqjyl2012.gitbook.io/algorithm/data-structure/balanced-multipath-search-tree#2b-shu-de-sou-suo-cao-zuo

https://www.bilibili.com/video/BV1sj411b7XC/?spm_id_from=333.788&vd_source=87f7ad8544d4c3ad070c5c2ff28b7698

B树的删除

1、关键字充足

直接删

img

2、兄弟够借

与其中序后继借

image-20231010161115278

进阶:跨多个兄弟借

image-20231129155543576

删除25

image-20231129155626143

26借走父节点的27,父结点借子结点的38,子结点再借父结点的42,42再借子节点的48

3、兄弟不够借,与父亲、兄弟结点合并

image-20231010165810530

删除140

image-20231010165938327

进阶: 连续合并父亲/兄弟结点

删除50

image-20231010165350489

image-20231010165651182

4、删除非叶结点

直接删根结点

image-20231129155839511

image-20231129155921919

先用其中序的前驱/后继替换下来,之后的步骤回顾 兄弟够借 的进阶方法

外部排序

将待排序的记录存储在外存上,排序时再把数据一部分一部分地调入内存进行排序,在排序过程中需要多次进行内存和外存之间的交换的方法称为外部排序。

外部排序一般使用归并算法

外部排序的总时间=内部排序所需的时间+外存信息读写的时间+内部归并所需的时间

一般来说,外存信息读写的时间远大于内部排序和内部归并的时间,因此应着力减少I/O次数

下面我们先介绍归并方法,再介绍如何进行优化

外部排序的方法

以二路归并为例:

(自己写了好久,到最后发现还是书上原来的例子好,那就直接copy过来吧)

image-20231017162108190

image-20231017162147141

image-20231017162159246

image-20231017162208661

优化一---增加归并路数k

显然,外存信息读写的时间远大于内部排序和内部归并的时间,因此应着力减少I/O次数。由于外存信息的读/写是以“磁盘块”为单位的,可知每一趟归并需进行16次“读”和16次“写”,3趟归并加上内部排序时所需进行的读/写,使得总共需进32×3+32=128次读写

若改用4路归并排序,则只需2趟归并,外部排序时的总读/写次数便减至32×2+32=96。因此,增大归并路数,可减少归并趟数,进而减少总的磁盘I/O次数,

image-20231017162553890

优化二---败者树---消除增加k(归并路数)带来的副作用

增加归并路数k能减少归并趟数S,进而减少I/O次数。然而,增加归并路数k时,内部归并的时间将增加。做内部归并时,在k个元素中选择关键字最小的记录需要比较k-1次。每趟归并n个元素需要做(n-1)(k-1)次比较,S趟归并总共需要的比较数为

image-20231017162726754

因此内部归并时间亦随k的增长而增长。这将抵消由于增大k而减少外存访问次数所得到的效益。因此,不能使用普通的内部归并排序算法。

下面引入败者树

败者树

它是一棵完全二叉树 ,可以快速得到n个数中最小的元素,在n个记录中选择最小的关键字,最多需要 \(⌈log_2k⌉\)

内部结点用来记忆左右子树中的“失败者”,而让胜者往上继续进行比较,一直到根结点。若比较两个数,大的为失败者、小的为胜利者,则根结点指向的数为最小数。

image-20231017162935123

https://www.bilibili.com/video/BV1DG411m7SJ/?spm_id_from=333.337.search-card.all.click&vd_source=87f7ad8544d4c3ad070c5c2ff28b7698

优化三---置换选择排序---减少初始归并段的个数r---生成初始归并段(大小不等的归并段)

显然,减少初始归并段的个数也可以减少归并趟数S

上面采用内部排序方法得到的各个初始归并段长度都相同(除最后一段外),它依赖于内部排序时可用内存工作区的大小。因此,必须探索新的方法用来产生更长的初始归并段,这就引出了置换选择排序

image-20231017164351618

image-20231017164400540

image-20231017164415274

参考:

https://www.bilibili.com/video/BV1Lw41127zJ/?spm_id_from=333.337.search-card.all.click&vd_source=87f7ad8544d4c3ad070c5c2ff28b7698

image-20231017164342366

另外,若我们的工作区较大(n),每次比较n个元素都会耗费很长的时间,为此,我们可以引入败者树来提高寻找最小数的时间

优化四---最佳归并树(m叉哈夫曼树)---组织长度不等的初始归并段的归并顺序

假设由置换-选择得到9个初始归并段,其长度(记录数)依次为9,30,12,18,3,17,2,6,24。现做3路平衡归并,其一般归并树:

image-20231017165214287

(倒过来看更好

其I/O次数=2xWPL = 484 (好像没有算置换选择排序时的I/O次数,不过无所谓,毕竟下面的哈夫曼树也没算这一步)

下面将第4章中哈夫曼树的思想推广到m叉树的情形,在归并树中,让记录数少的初始归并段最先归并,记录数多的初始归并段最晚归并,就可以建立总的I/O次数最少的最佳归并树。上述9个初始归并段可构造成一棵如下图所示的归并树,按此树进行归并,仅需对外存进行446次读/写,这棵归并树便称为最佳归并树 (由此看来,最佳归并树是哈夫曼树的一种,且是"最佳"哈夫曼树)。

image-20231017170049343

上图中的哈夫曼树是一棵严格3叉树,即树中只有度为3或0的结点。若只有8个初始归并段,如上例中少了一个长度为30的归并段。若在设计归并方案时,缺额的归并段留在最后,即除最后一次做2路归并外,其他各次归并仍是3路归并,此归方案的外存读/写次数为386。显然,这不是最佳方案

正确的做法是:若初始归并段不足以构成一棵严格k叉树时,需添加长度为0的“虚段”,按照哈夫曼树的原则,权为0
的叶子应离树根最远。因此,最佳归并树应如下图所示。

image-20231017170439496

小总结

外部排序时间 = 内部排序所需的时间+外存信息读写的时间+内部归并所需的时间

理想状态下的外部排序= 较大的k路归并 + 较少的初始归并个数r

具体化一下就是 : 败者树(减少多路k中内部排序的时间)+置换选择排序(减少r) + 哈夫曼树(优化比较顺序)

需要注意的是

1、败者树是完全二叉树

2、最佳归并树是哈夫曼树的一种,它是"最优的" 哈夫曼树

https://c.biancheng.net/view/3454.html

image-20231219145941389

3、在置换选择排序中使用的败者树与常规的败者树不太一样,进行了一些改进,引入了"序号"

https://c.biancheng.net/view/3454.html

image-20231219183530786

因为在置换选择排序中,要求得到的树是所有大于MINIMAX的数中最小的树,而 败者树只能得到所有元素中最小的数,因此我们需要进行一些优化

用"序号"表示这个元素是否大于MINIMAX,若小于,则添加标记,在随后的一轮败者树元素比较中不比较这个数

CO

数据通路

你还记得数据通路是啥吗

原码与补码的规格化

img
简言之,对于原码,只需要看小数点后第一位是否为1
对于补码,只需要看符号位和小数点第一位是否相反

另外,还有一个点就是,规格化规定尾数的绝对值应该大于等于1/R(R为基数)

中央处理器

高级流水线技术

有两种增加指令级并行的策略:一种是多发射技术,它通过采用多个内部功能部件,使流水线功能段能同时处理多条指令,处理机一次可以发射多条指令进入流水线执行。另一种是超流水线技术,它通过增加流水线级数来使更多的指令同时在流水线中重叠执行。

超标量流水线技术 (多发射技术)

超标量流水线技术也称动态多发射技术,每个时钟周期内可并发多条独立指令,以并行操作方式将两条或多条指令编译并执行,为此需配置多个功能部件

超标量技术不能调整指令的执行顺序,因此通过编译优化技术,把可并行执行的指令搭配起来,挖掘更多的指令并行性

image-20231027161820479

超长指令字技术

超长指令字技术也称静态多发射技术,由编译程序挖掘出指令间潜在的并行性,将多条能并行操作的指令组合成一条具有多个操作码字段的超长指令字(可达几百位),为此需要采用多个处理部件。

超流水线技术 (超流水线技术)

image-20231027162031177

流水线功能段划分得越多,时钟周期就越短,指令吞吐率也就越高,因此超流水线技术是通过提高流水线主频的方式来提升流水线性能的。

但是,流水线级数越多,用于流水寄存器的开销就截大,因而流水线级数是有限制的,并不是越多越好。

超流水线CPU在流水线充满后,每个时钟周期还是执行一条指令,CPI=1,但其主频更高

多发射流水线(超标量流水线技术)CPU每个时钟周期可以处理多条指令,CPI<1,相对而言,多发射流水线成本更高,控制更复杂。

小总结:

image-20231027162459464

1、超标量流水线技术(多发射流水线)在每个时钟周期内可同时并发多条独立指令,CPI<1

2、超流水线技术好比将流水线再分段,使超流水线的处理器周期比普通流水线的处理器周期短,这样,在原来的时钟周期内,功能部件被使用多次,使流水线倍速于原来时钟频率的速度运行,其CPI=1,但主频大大增加

3、超长指令字技术和超标量技术都是采用多条指令在多个处理部件中并行处理的体系结构,在一个时钟周期内能流出多条指令,其较超标量具有更高的并行处理能力,但对优化编译器的要求更高,对 Cache的容量要求更大。

多处理器

这部分的知识点更是依托

SISD、SIMD、MIMD

基于指令流的数量和数据流的数量,将计算机体系结构分为SISD、SIMD、MISD和MIMD四类。

常规的单处理器属于SISD,而常规的多处理器属于MIMD

1、SISD 单指令流单数据流

image-20231027170947963

一个处理器,一个存储器

顺序串行执行、多位交叉方式

2、SIMD 单指令流多数据流

image-20231027171115735

数据级并行

一个指令控制部件,多个处理单元

for循环效率⾼,但switch或case时效率低

向量处理器就是SIMD的一种

3、MISD 多指令流单数据流

image-20231027171307042

4、MIMD 多指令流多数据流

image-20231027171546375

同时执⾏多条指令,处理多个不同的数据

分为多计算机系统和多处理器系统

多计算机系统:

每个计算机节点都具有各⾃的私有存储器,并且具有独⽴的主存地址空间

不能通过存取指令来访问不同节点的私有存储器

⽽要通过消息传递进⾏数据传送,也称为消息传递MIMD

多处理器系统:

共享存储多处理器(SMP --- Shared multi-core processor)系统的简称
它具有共享的单⼀地址空间,通过访存指令来访问系统中的所有存储器,也称共享存储MIMD

硬件多线程

在传统CPU中,线程的切换包含一系列开销,频繁地切换会极大彪响系统的性能,为了减少线程切换过程中的开销,便诞生了硬件多线程。

在支持硬件多线程的CPU中,必须为每个线程提供单独的通用寄存器组、单独的程序计数器等,线程的切换只需激活选中的寄存器,从而省略了与存储器数据交换的环节,大大减少了线程切换的开销。

硬件多线程有3种实现方式:细粒度多线程、粗粒度多线程和同时多线程(SMT)。

image-20231027171810178

image-20231027171816739

超线程就是同时多线程SMT,即在一个单处理器或单个核中设置了两套线程状态部件,共享高速缓存和功能部件。

多核处理器

image-20231027172038111

1、多核处理器是将多个处理器单元集成到一个CPU上

2、每个核都可以有自己的Cache,也可以共享同一个cache,所有核一般共享主存储器

共享内存多处理器

image-20231027172102263

image-20231027172111088

1、具有共享的单一物理地址空间的多处理器被称为共享内存多处理器(SMP)

2、所有处理器都能通过存取指令访问任何存储器的位置

3、单一地址空间的多处理器有两种类型

(1) 统⼀存储访问(UMA)多处理器

每个处理器对所有存储单元的访问时间都是⼤致相同的,即访问时间与哪个处理器提出访存请求及访问哪个字无关

根据处理器与共享存储器之间的连接方式,分为基于总线、基于交叉开关网络和基于多级交换网络连接等几种处理器。

(2) ⾮统⼀存储访问(NUMA)多处理器

主存被分割并分配给了同一机器上的不同处理器或内存控制器,某些处理器访存请求要比其他的快,具体取决于哪个处理器提出了访问请求以及访问哪个字

与UMA架构不同的是,在NUMA架构下,内存的访问出现了本地和远程的区别,访问本地内存明显要快于访问远程内存。

处理器中不带⾼速缓存时,被称为NC-NUMA
处理器中带有⼀致性⾼速缓存时,被称为CC-NUMA(某些访问请求要⽐其他的快)

SMP: shared-memory mp : 共享内存多处理器

UMA: Unified storage access multiprocessor : 统一存储访问多处理器

NUMA: Non-Unified storage access multiprocessor : ⾮统一存储访问多处理器

小总结

1、SISD、SIMD、SIMD、MIMD

  1. 向量处理器属于SIMD
  2. MIMD分为多计算机系统和多处理器系统
    1. 多计算机系统每个计算机结点都具有各自的私有存储器,并具有独立主存空间,不能通过访存指令访问不同结点的存储空间
    2. 多处理器系统是SMP(共享存储多处理器)的简称,其具有共享的单一地址空间

2、硬件多线程

  1. 细粒度多线程、粗粒度多线程、同时多线程
  2. 超线程就是同时多线程SMT,即一个处理器中设置两套线程状态部件,共享高速缓存部件

3、多核处理器

  1. 多个处理单元集成到一个CPU中
  2. 每个核可以共享Cache,也可以有自己的Cache

4、共享内存多处理器SMP

  1. 具有共享的单一物理地址空间的多处理器
  2. 所有处理器都能通过存取指令访问任何存储器的位置,且可在自己的虚拟空间中单独运行程序
  3. SMP分为两种---UMA、NUMA
  4. SMP---UMA---统一存储访问多处理器
    1. 每个处理器对所有存储单元的访问时间都是⼤致相同的,即访问时间与哪个处理器提出访存请求及访问哪个字无关
    2. 根据处理器与共享存储器之间的连接方式,分为基于总线、基于交叉开关网络和基于多级交换网络连接等几种处理器。
  5. SMP---NUMA---非统一存储访问多处理器
    1. 主存被分割并分配给了同一机器上的不同处理器或内存控制器,某些处理器访存请求要比其他的快,具体取决于哪个处理器提出了访问请求以及访问哪个字
    2. 与UMA架构不同的是,在NUMA架构下,内存的访问出现了本地和远程的区别,访问本地内存明显要快于访问远程内存。
  6. 处理器中不带⾼速缓存时,被称为NC-NUMA
    处理器中带有⼀致性⾼速缓存时,被称为CC-NUMA(某些访问请求要⽐其他的快)

OS

SPOOLing技术

1、为了缓和CPU与I/O速度不协调的问题

2、它将独占设备改造成共享设备

首先介绍什么是脱机:

脱机技术

img

为了解决人机矛盾及CPU和I/O设备之间速度不匹配的矛盾,20世纪50年代末出现了脱机I/O技术。该技术是将事先装有用户程序和数据的纸袋装入纸带输入机,在一台外围机的控制下,把纸带(卡片)上的数据(程序)输入到磁带上。当CPU需要这些程序和数据时,再从磁带上高速地调入内存。

在脱机技术加持下,程序和数据的输入输出都是在外围机的控制下完成的,也就是说,他们是在脱离主机的情况下进行的,所以称这种方式为脱机输入/输出方式

脱机技术需要外围机,而SPOOLing用软件模拟外围机

SPOOLing系统对脱机技术的模拟

img

输入进程模拟脱机输入时的外围机
输入井模拟脱机输入时的磁带,用于收容I/O设备输入的数据,输出进模拟脱机输出时的磁带,用于收容用户进程输出的数据

用户要求的数据从输入设备经过输入缓冲区送到输入井,当CPU需要输入设备时,直接从输入井读入内存。。
用户要求输出的数据先从内存送入输出井,待输出设备空闲,再将输入进中的数据经过缓冲区送到输出设备

SPOOLing系统的优特点

1、加快了作业执⾏的速度,提⾼了IO速度,将对低速IO设备执⾏的IO操作演变为对磁盘缓冲区中数据的存取
2、使独占设备变为共享设备,且没有为任何进程分配设备
3、提⾼了独占设备的利⽤率,缓和了CPU和低速IO设备之间的速度不匹配的⽭盾
4、实现了虚拟设备功能,对每个进程⽽⾔,都认为⾃⼰独占了⼀个设备
5、以空间换时间,需要磁盘空间(输⼊输出井)和内存空间(输⼊输出缓冲区)

共享打印机的实现就是SPOOLing技术

虚拟文件系统

磁盘初始化

操作系统的启动

外存空闲空间的管理

设备分配---DCT、COCT、CHCT、SDT

DCT: 设备控制表

COCT: 控制器控制表 Controller control table

CHCT: 通道控制表

SDT : 系统设备表

CN

CRC

IPV6

介质访问控制---轮询

典型的轮询访问介质访问控制协议是令牌传递协议,它主要用在令牌环局域网中。

image-20231116155834880

1、在令牌传递网络中,传输介质的物理拓扑不必是一个环,但是为了把对介质访问的许可从一个设备传递到另一个设备,令牌在设备间的传递通路逻辑上必须是一个环

2、轮询介质访问控制非常适合负载很高的广播信道。所谓负载很高的信道,是指多个结点在同一时刻发送数据概率很大的信道

3、令牌环网上不可能存在冲突

无线局域网

IEEE 802.11广泛使用CSMA/CA

CSMA/CD 广泛用于有线连接的局域网,CSMA/CA用于无线网

CSMA/CA协议,把CSMA/CD的碰撞检测改为碰撞避免(Collision Avoidance ,CA),不是说可以完全避免碰撞,而是指协议的设计要尽量降低碰撞发生的概率

1、CSMA/CA使用的是确认/重传ARQ,每发送完一帧都要在收到确认帧后才能继续发送下一帧 (看来是停止等待协议)

2、所有的站完成发送后,必须再等待一段很短的时间(继续监听)才能发送下一帧。这段时间称为帧间间隔(InterFrame Space,IFS)。帧间间隔的长短取决该站要发送的帧的类型

802.11使用了一下三种帧:

image-20231116153215954

3、CSMA/CA的二进制指数退避算法与前面讲的略有不同,这里并不打算深入学习,详情可参考《计算机网络(第八版))》p416

4、CSMA/CA实现原理

image-20231116154233843

5、处理隐蔽站问题

什么是隐蔽站问题?

类似于这样:

image-20231116154926374

A站或B站向接入点AP发送数据时,远处的C站接收不到这些信号,而C站向AP发送的信号也传播不到远处的A站或B站,但是A站与C站同时发送数据时就会产生碰撞

解决方法

为了解决这个问题,802.11引入了信道预约这个概念

  1. 源站要发送数据帧之前先广播一个很短的请求发送RTS(Request To Send)控制帧,它包括源地址、目的地址和这次通信(含相应的确认帧)所持续的时间,该帧能被其范围内包括AP在内的所有站点听到。
  2. 若信道空闲,则AP广播一个允许发送CTS(Clear To Send)控制帧,它包括这次通信所需的持续时间(从RTS帧复制),该帧也能被其范围内包括A和B在内的所有站点听到
  3. B和其他站听到CTS后,在CTS帧中指明的时间内将抑制发送
    CTS帧有两个目的:①给源站明确的发送许可;②指示其他站点在预约期内不要发送。

image-20231116155307994

PPP协议

1、只支持全双工

2、只支持点对点,不支持多点

3、提供差错检测但不提供纠错

image-20231116173916428

4、信息部分字段大小为0~1500B

没有最短帧,因为PPP是点对点的,并不是总线形,所以无须采用CSMA/CD协议,自然就没有最
短帧,所以信息段占0~1500字节,而不是46~1500字节

5、PPP协议面向字节

6、PPP协议不使用序号与确认机制,只确保无差错接受(CRC)

PPP协议工作流程:

image-20231116174511652

IP组播

1、IP组播使用D类IP地址,地址范围为: 224.0.0.0 ~ 239.255.255.255

2、IP组播使用IGMP协议

3、组播地址只能用于目的地址

4、组播仅使用UDP协议

5、IANA的以太网组播地址范围是01-00-5E-00-00-00到01-00-5E-7F-FF-FF

左起前25个比特都是相同的,剩余23个比特可以任意变化

6、而可供分配的IP有28位,由此得知IP地址会多余前5位

7、多播组的地理范围不受限制,一台主机可以属于几个多播组

image-20231117174037370

8、传输的时候会生成多播MAC地址

image-20231221170841978

9、IP多播地址与多播MAC地址的映射不是唯一的

多播IP地址的前四位固定为 1110 ,代表D类多播地址,随后五位无法映射,多余出来,这就导致不同的IP地址可能由于这五位不一样而其他位都一样造成一对多的映射(正好有利于多播),即一个多播MAC地址对应多个多播IP地址,比如下下图就展示了3个IP多播组只对应了2个硬件多播组

image-20231221171410030

image-20231221172052985

10、IGMP协议

(1)、IGMP让连接到本地局域网上的组播路由器知道水局成网上是否右主机参m或退出了某个组播组。

(2)、IGMP应视为网际协议IP的一个组成部分

(3)、IGMP其工作可分为两个阶段

  1. 第一阶段
    1. 当某台主机加入新的组播组时,该主机应向组播组的组播地址发送一个IGMP报文,声明自己要成为该组的成员。
    2. 本地的组播路由器收到IGMP报文后,将组成员关系转发给因特网上的其他组播路由器。
  2. 第二阶段
    1. 因为组成员关系是动态的,本地组播路由器要周期性地探询本地局域网上的主机,
      以便知道这些主机是否仍继续是组的成员。
    2. 只要对某个组有一台主机响应,那么组播路由器就认为这个组是活跃的。但一个组在经过几次的探询后仍然没有一台主机响应时,则不再将该组的成员关系转发给其他的组播路由器。

移动IP

移动IP技术是指移动结点以固定的网络IP地址实现跨越不同网段的漫游功能,并保证基于网络IP的网络权限在漫游过程中不发生任何改变。

使用移动IP,一个移动结点可以在不改变其IP地址的情况下改变其驻留位置。

1、移动结点、本地代理、外部代理

  1. 移动结点: 具有永久IP地址的移动结点。
  2. 本地代理: 在一个网络环境中,一个移动结点的永久“居所”被称为归属网络,在归属网络中代表移动结点执行移动管理功能的实体称为归属代理(本地代理),它根据移动用户的转交地址,采用隧道技术转交移动结点的数据包。
  3. 外部代理。在外部网络中帮助移动结点完成移动管理功能的实体称为外部代理。

2、移动IP与动态IP是两个完全不同的概念

动态IP指的是局域网中的计算机可以通过网络中的DHCP服务器动态地获得一个IP地址,而不需要用户在计算机的网络设置中指定IP地址

动态IP和DHCP经常会应用在我们的实际工作环境中。

3、移动IP通信过程

image-20231117175808312

image-20231117175816569

  1. 移动结点漫游到一个外地网络时,仍然使用固定的IP地址进行通信
  2. 为了能够收到通信对端发给它的IP分组,移动结点需要向本地代理注册当前的位置地址,这个位置地址就
    是转交地址(它可以是外部代理的地址或动态配置的一个地址)。
  3. 本地代理接收来自转交地址的注册后,会构建一条通向转交地址的隧道,将截获的发给移动结点的IP分组通过隧道送到转交地址处。
  4. 在转交地址处解除隧道封装,恢复原始的IP分组,最后送到移动结点,外网就能够收到这些发送给它的P分组。
  5. 移动结点回到本地网时,移动结点向本地代理注销转交地址,这时移动结点又将使用传统的TCP/IP方式进行通信。

另外,需要注意的是,这个隧道是 归属代理与外地代理的隧道

外地代理接受到IP数据报后,会根据IP数据报的目的IP地址找到相对的移动主机

image-20231221175406558

DHCP报文、OSPF分组、BGP-4报文

DHCP报文

1、DHCP发现报文---客户机广播报文,用于寻找DHCP服务器

2、DHCP提供报文---DHCP服务器广播"DHCP提供报文",其包含提供的IP地址

3、DHCP请求报文---客户机仍然广播DHCP请求

4、DHCP确认报文---DHCP服务器广播DHCP确认报文,将IP分配给客户机

可以发现,DHCP发整个过程都是一直在广播的

简言之: 发现、提供、请求、确认

OSPF分组

1、问候分组,用来发现和维持邻站的可达性。

2、数据库描述分组,向邻站给出自己的链路状态数据库中的所有链路状态项目的摘要信息。

3、链路状态请求分组,向对方请求发送某些链路状态项目的详细信息。

4、链路状态更新分组,用洪泛法对全网更新链路状态。

5、链路状态确认分组,对链路更新分组的确认。

BGP-4报文

1、打开报文(Open)。用来与相邻的另一个BGP发言人建立关系

2、更新(Update)报文。用来发送某一路由的信息

3、保活报文(Keepalive)。用来确认打开报文并周期性地证实邻站关系

4、通知(Notification) 报文。用来发送检测到的差错

协议与端口号

FTP: 应用层、基于TCP、20(数据)与21(控制)号端口

DNS: 应用层,基于UDP 、53号端口

SMTP、POP: 应用层,基于TCP

HTTP: 应用层,基于TCP ,80号端口

TELNET: 应用层,基于TCP,23号端口

BGP: 应用层,基于TCP

RIP: 应用层,基于UDP

DHCP:应用层,基于UDP 68号端口

OSPF: 传输层,基于IP

ICMP:网络层协议,IP协议的附属协议

ARP: 网络层协议

PPP: 数据链路层

HDLC: 数据链路层

一些提高做题效率的方法

平衡二叉树/折半查找判定树

1、高度为h的AVL树的最少结点数

\(n_h\)表示高度为h的平衡二叉树中含有的最少节点数,注意是所有层的节点和

\[\begin{aligned}n_1&=1\\\\n_2&=2\\\\\cdots\\\\n_h&=n_{h-1}+n_{h-2}+1\end{aligned} \]

2、n个结点的AVL树的最大分支高度与最小分支高

最大分支高度 : \(H=\lceil log_2(n+1) \rceil\)

那么其最小分支高则为\(H−1\) (因为是平衡二叉树,高低差不超过1)

若题目要求n个结点,折半查找过程关键字的最大比较次数,直接带入求H即可

image-20231207142948732

排序

背下来,看见直接选

1、不稳定的排序算法

速记: 堆选希块

2、排序趟数与初态有关的算法

快排+冒泡排序

这俩都是交换排序

3、比较次数与序列初态无关的算法

二路归并排序

简单选择排序

基数排序

速记: 二简基(爱剪辑)

ps
现在是2023-12-21 23:12,应该是考研前最后一篇了,希望能一战上岸,加油!!!