先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上网络安全知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip204888 (备注网络安全)
正文
2i+2。用宏定义实现如下:
#define lson(idx) (2\*idx+1)
#define rson(idx) (2\*idx+2)
由于这里涉及到乘 2,所以我们还可以用左移位运算来优化乘法运算,如下:
#define lson(idx) (idx << 1|1)
#define rson(idx) ((idx + 1) << 1)
3、父结点编号
同样,父结点编号也可以通过数学归纳法得出,当结点编号为
i
i
i 时,它的父结点编号为
i
−
1
2
\frac {i-1} {2}
2i−1,利用C语言实现如下:
#define parent(idx) ((idx - 1) / 2)
这里涉及到除 2,可以利用右移运算符进行优化,如下:
#define parent(idx) ((idx - 1) >> 1)
这里利用补码的性质,根结点的父结点得到的值为 -1;
4、数据域
堆数据元素的数据域可以定义两个:关键字 和 值,其中关键字一般是整数,方便进行比较确定大小关系;值则是用于展示用,可以是任意类型,可以用typedef struct
进行定义如下:
typedef struct {
int key; // (1)
void \*any; // (2)
}DataType;
- (
1
)
(1)
(1) 关键字;
- (
2
)
(2)
(2) 值,定义成一个空指针,可以用来表示任意类型;
5、堆的数据结构
由于堆本质上是一棵完全二叉树,所以将它一一映射到数组后,一定是连续的。我们可以用一个数组来代表一个堆,在C语言中的数组拥有一个固定长度,可以用一个Heap
结构体表示如下:
typedef struct {
DataType \*data; // (1)
int size; // (2)
int capacity; // (3)
}Heap;
- (
1
)
(1)
(1) 堆元素所在数组的首地址;
- (
2
)
(2)
(2) 堆元素个数;
- (
3
)
(3)
(3) 堆的最大元素个数;
三、堆的常用接口
1、元素比较
两个堆元素的比较可以采用一个比较函数compareData
来完成,比较过程就是对关键字key
进行比较的过程,以大顶堆为例:
a. 大于返回 -1,代表需要执行交换;
b. 小于返回 1,代表需要执行交换;
c. 等于返回 0,代表需要执行交换;
int compareData(const DataType\* a, const DataType\* b) {
if(a->key > b->key) {
return -1;
}else if(a->key < b->key) {
return 1;
}
return 0;
}
2、交换元素
交换两个元素的位置,也是堆这种数据结构中很常见的操作,C语言实现也比较简单,如下:
void swap(DataType\* a, DataType\* b) {
DataType tmp = \*a;
\*a = \*b;
\*b = tmp;
}
更加详细的内容,可以参考:《算法零基础100讲》(第16讲) 变量交换算法 这篇文章。
3、空判定
空判定是一个查询接口,即询问堆是否是空的,实现如下:
bool HeapIsEmpty(Heap \*heap) {
return heap->size == 0;
}
4、满判定
满判定是一个查询接口,即询问堆是否是满的,实现如下:
bool heapIsFull(Heap \*heap) {
return heap->size == heap->capacity;
}
5、上浮操作
对于大顶堆而言,从它叶子结点到根结点的元素关键字一定是单调不降的,如果某个元素出现了比它的父结点大的情况,就需要进行上浮操作。
上浮操作就是对 当前结点 和 父结点 进行比较,如果它的关键字比父结点大(compareData
返回-1
的情况),将它和父结点进行交换,继续上浮操作;否则,终止上浮操作。
如图所示,代表的是一个关键字为 95 的结点,通过不断上浮,到达根结点的过程。上浮完毕以后,它还是一个大顶堆。
上浮过程的 C语言 实现如下:
void heapShiftUp(Heap\* heap, int curr) { // (1)
int par = parent(curr); // (2)
while(par >= root) { // (3)
if( compareData( &heap->data[curr], &heap->data[par] ) < 0 ) {
swap(&heap->data[curr], &heap->data[par]); // (4)
curr = par;
par = parent(curr);
}else {
break; // (5)
}
}
}
- (
1
)
(1)
(1) heapShiftUp
这个接口是一个内部接口,所以用小写驼峰区分,用于实现对堆中元素进行插入的时候的上浮操作;
- (
2
)
(2)
(2) curr
表示需要进行上浮操作的结点在堆中的编号,par
表示curr
的父结点编号;
- (
3
)
(3)
(3) 如果已经是根结点,则无须进行上浮操作;
- (
4
)
(4)
(4) 子结点的关键字 大于 父结点的关键字,则执行交换,并且更新新的 当前结点 和 父结点编号;
- (
5
)
(5)
(5) 否则,说明已经正确归位,上浮操作结束,跳出循环;
6、下沉操作
对于大顶堆而言,从它 根结点 到 叶子结点 的元素关键字一定是单调不增的,如果某个元素出现了比它的某个子结点小的情况,就需要进行下沉操作。
下沉操作就是对 当前结点 和 关键字相对较小的子结点 进行比较,如果它的关键字比子结点小,将它和这个子结点进行交换,继续下沉操作;否则,终止下沉操作。
如图所示,代表的是一个关键字为 19 的结点,通过不断下沉,到达叶子结点的过程。下沉完毕以后,它还是一个大顶堆。
下沉过程的 C语言 实现如下:
void heapShiftDown(Heap\* heap, int curr) { // (1)
int son = lson(curr); // (2)
while(son < heap->size) {
if( rson(curr) < heap->size ) {
if( compareData( &heap->data[rson(curr)], &heap->data[son] ) < 0 ) {
son = rson(curr); // (3)
}
}
if( compareData( &heap->data[son], &heap->data[curr] ) < 0 ) {
swap(&heap->data[son], &heap->data[curr]); // (4)
curr = son;
son = lson(curr);
}else {
break; // (5)
}
}
}
- (
1
)
(1)
(1) heapShiftDown
这个接口是一个内部接口,所以用小写驼峰区分,用于对堆中元素进行删除的时候的下沉调整;
- (
2
)
(2)
(2) curr
表示需要进行下沉操作的结点在堆中的编号,son
表示curr
的左儿子结点编号;
- (
3
)
(3)
(3) 始终选择关键字更小的子结点;
- (
4
)
(4)
(4) 子结点的值小于父结点,则执行交换;
- (
5
)
(5)
(5) 否则,说明已经正确归位,下沉操作结束,跳出循环;
四、堆的创建
1、算法描述
通过给定的数据集合,创建堆。可以先创建堆数组的内存空间,然后一个一个执行堆的插入操作。插入操作的具体实现,会在下文继续讲解。
2、动画演示
3、源码详解
Heap\* HeapCreate(DataType \*data, int dataSize, int maxSize) { // (1)
int i;
Heap \*h = (Heap \*)malloc( sizeof(Heap) ); // (2)
h->data = (DataType \*)malloc( sizeof(DataType) \* maxSize ); // (3)
h->size = 0; // (4)
h->capacity = maxSize; // (5)
for(i = 0; i < dataSize; ++i) {
HeapPush(h, data[i]); // (6)
}
return h; // (7)
}
- (
1
)
(1)
(1) 给定一个元素个数为dataSize
的数组data
,创建一个最大元素个数为maxSize
的堆并返回堆的结构体指针;
- (
2
)
(2)
(2) 利用malloc
申请堆的结构体的内存;
- (
3
)
(3)
(3) 利用malloc
申请存储堆数据的数组的内存空间;
- (
4
)
(4)
(4) 初始化空堆;
- (
5
)
(5)
(5) 初始化堆最大元素个数为maxSize
;
- (
6
)
(6)
(6) 遍历数组执行堆的插入操作,插入的具体实现HeapPush
接下来会讲到;
- (
7
)
(7)
(7) 最后,返回堆的结构体指针;
五、堆元素的插入
1、算法描述
堆元素的插入过程,就是先将元素插入堆数组的最后一个位置,然后执行上浮操作;
2、动画演示
3、源码详解
bool HeapPush(Heap\* heap, DataType data) {
if( heapIsFull(heap) ) {
return false; // (1)
}
heap->data[ heap->size++ ] = data; // (2)
heapShiftUp(heap, heap->size-1); // (3)
return true;
}
- (
1
)
(1)
(1) 堆已满,不能进行插入;
- (
2
)
(2)
(2) 插入堆数组的最后一个位置;
- (
3
)
(3)
(3) 对最后一个位置的 堆元素 执行上浮操作;
五、堆元素的删除
1、算法描述
堆元素的删除,只能对堆顶元素进行操作,可以将数组的最后一个元素放到堆顶,然后对堆顶元素进行下沉操作。
2、动画演示
3、源码详解
bool HeapPop(Heap \*heap) {
if(HeapIsEmpty(heap)) {
return false; // (1)
}
heap->data[root] = heap->data[ --heap->size ]; // (2)
heapShiftDown(heap, root); // (3)
return true;
}
- (
1
)
(1)
(1) 堆已空,无法执行删除;
- (
2
)
(2)
(2) 将堆数组的最后一个元素放入堆顶,相当于删除了堆顶元素;
- (
3
)
(3)
(3) 对堆顶元素执行下沉操作;
六、获取堆顶元素
1、算法描述
获取堆顶元素,就是获取了当前所有元素的最值。
2、动画演示
3、源码详解
还有兄弟不知道网络安全面试可以提前刷题吗?费时一周整理的160+网络安全面试题,金九银十,做网络安全面试里的显眼包!
王岚嵚工程师面试题(附答案),只能帮兄弟们到这儿了!如果你能答对70%,找一个安全工作,问题不大。
对于有1-3年工作经验,想要跳槽的朋友来说,也是很好的温习资料!
【完整版领取方式在文末!!】
93道网络安全面试题
内容实在太多,不一一截图了
黑客学习资源推荐
最后给大家分享一份全套的网络安全学习资料,给那些想学习 网络安全的小伙伴们一点帮助!
对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。
😝朋友们如果有需要的话,可以联系领取~
1️⃣零基础入门
① 学习路线
对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。
② 路线对应学习视频
同时每个成长路线对应的板块都有配套的视频提供:
2️⃣视频配套工具&国内外网安书籍、文档
① 工具
② 视频
③ 书籍
资源较为敏感,未展示全面,需要的最下面获取
② 简历模板
因篇幅有限,资料较为敏感仅展示部分资料,添加上方即可获取👆
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注网络安全)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
26927e48b1332a38401b3369.png#pic_center)
② 视频
③ 书籍
资源较为敏感,未展示全面,需要的最下面获取
② 简历模板
因篇幅有限,资料较为敏感仅展示部分资料,添加上方即可获取👆
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注网络安全)
[外链图片转存中…(img-9zBfFbjf-1713443583966)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!