您当前的位置:首页 > 电脑百科 > 程序开发 > 算法

七大排序算法详细介绍

时间:2019-06-11 10:07:55  来源:  作者:

排序的相关概念

排序的分类

  • 根据在排序过程中带排序的记录是否全部被放置在内存中,排序分为:
  • 内排序
  • 外排序

1.内排序

内排序是在排序整个过程中,带排序的所有记录全部放置在内存中

影响内排序的主要因素

  • 时间性能。
  • (主要受比较移动两种操作的影响)
  • 辅助空间。
  • 算法的复杂性。

内排序的分类

根据排序过程中借助的主要操作,内排序分为:

  • 插入排序
  • 交换排序
  • 选择排序
  • 归并排序

2.外排序

外排序是由于排序的记录个数太多,不能同时放置在内存中,整个排序过程需要在内外存之间多次交换数据才能进行

按照算法的复杂度分类

  • 简单算法:
  • 冒泡排序、简单选择排序、直接插入排序。
  • 复杂排序:
  • 希尔排序、堆排序、归并排序、快速排序。

 


 

一、冒泡排序算法

因为在冒泡排序中要用到顺序表结构数组两元素的交换,先把这些写成函数

#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
#define TRUE 1
#define FALSE 0
typedef struct {
 
 int r[MAXSIZE + 1];
 int length;
}SqList;
void swap(SqList *L, int i, int j){
 int temp = L->r[i];
 L->r[i] = L->r[j];
 L->r[j] = temp;
}

1.1 冒泡排序的初级版实现

冒泡排序(Bubble Sort)是一种交换排序,它的基本思想是:两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止

  •  
void BubblSort0(SqList *L){
 int i,j;
 
 for (i = 1; i < L->length; i++)
 for (j = i+1; j <= L->length; j++)
 if (L->r[i] > L->r[j])
 swap(L, i, j);
}

对于这段代码,是最简单的冒泡,其实就是最简单的交换排序而已。它的思路就是让每一个关键字,都和它后面的每一个关键字比较,如果大则交换,这样第一位置的关键字在第一次循环后一定变成最小值

假设我们待排序的关键字序列是{9,1,5,8,3,7,4,6,2}

  • 当i = 1时,9与1交换后,在第一位置的1与后面的关键字比较都小,因此它就只最小值。
  • 当i = 2时,第二位置先后由9换成5,换成3,换成2,完成了第二小的数字交换。
  • 后面数字依次比较和交换,得到最终结果。

 

算法 - 七大排序算法详细介绍

 

 

1.2 冒泡排序的实现

对于上面的算法,代码虽然简单易懂,但是效率非常低。可以改进成接下来的代码

  •  
void BubbleSort(SqList *L){
 int i,j;
 for (i = 1; i < L->length; i++)
 for (j = L->length - 1; j >= i; j--)
 if (L->r[j] > L->r[j+1])
 swap(L, j, j+1);
}

代码解释

假设我们待排序的关键字序列是{9,1,5,8,3,7,4,6,2}

  • 当i = 1时,变量j由8反向循环到1,逐个比较,将较小值交换到前面,直到最后找到最小值放置在了第1的位置。
  • 当i = 1、 j = 8时,6 > 2 ,因此交换了它们的位置,j = 7时,4 > 2, 所以交换......直到j = 2时,因为 1 < 2, 所以不交换。
  • j = 1 时,9 > 1,交换,最终得到最小值1放置第一的位置。
  • 在不断循环的过程中,除了将关键字1放到第一的位置,还将关键字2从第九位置提到了第三的位置,显然比前面的算法有进步。
  • 当i = 2时,变量j由8反向循环到2,逐个比较,在将关键字2交换到第二位置的同时,也将关键字4和3有所提升

1.3 冒泡排序的优化

  • 在排序的过程中,增加一个标记变量flag来记录位置是否发生了变化
  • 如果没有发生交换,说明数组已经有序了。
  •  
void BubbleSort1(SqList *L){
 int i,j;
 
 int flag = TRUE;
 for (i = 1; i < L->length && flag; i++) {
 flag = FALSE;
 for (j = L->length - 1; j >= i; j--) {
 if (L->r[j] > L->r[j+1]) {
 swap(L, j, j+1);
 flag = TRUE;
 }
 }
 }
}

测试

#define N 9
int main(int argc, const char * argv[]) {
 
 int i;
 int d[N] = {9,1,5,8,3,7,4,6,2};
 
 SqList l0;
 for (i = 0; i < N; i++)
 l0.r[i+1] = d[i];
 l0.length = N;
 
 printf("排序前:
");
 for (i = 0; i < l0.length; i++) {
 printf("%d ", l0.r[i+1]);
 }
 printf("
");
 
 printf("1.0 初级冒泡排序结果:
");
 BubblSort0(&l0);
 for (i = 0; i < l0.length; i++) {
 printf("%d ", l0.r[i+1]);
 }
 printf("
");
 
 printf("1.1 冒泡排序结果:
");
 BubbleSort(&l0);
 for (i = 0; i < l0.length; i++) {
 printf("%d ", l0.r[i+1]);
 }
 printf("
");
 printf("1.2 优化后冒泡排序结果:
");
 BubbleSort1(&l0);
 for (i = 0; i < l0.length; i++) {
 printf("%d ", l0.r[i+1]);
 }
 printf("
");
 return 0;
}

测试结果

算法 - 七大排序算法详细介绍

 

 


 

二、简单选择排序

简单选择排序法(Simple Selection Sort)是通过n-i次关键字间的比较从n-i+1个记录中选出关键字最小的记录,并和第i(1<=i<=n)个记录交换

简单选择排序法的工作原理是:每一次从无序组的数据元素中选出最小(或最大)的一个元素,存放在无序组的起始位置,无序组元素减少,有序组元素增加,直到全部待排序的数据元素排完

  •  
void SelectSort(SqList *L){
 int i, j, min;
 for (i = 1; i < L->length; i++) {
 min = i;
 for (j = i + 1; j <= L->length; j++) {
 if (L->r[min] > L->r[j])
 min = j;
 }
 
 if (i != min) 
 swap(L, i, min);
 }
}

代码说明

  • 简单选择排序相对简单,交换移动数据的次数相当少,节约时间。
  • 简单选择排序的时间复杂度为O(n^2)。

 

三、直接插入排序

直接插入排序(Straight Insertion Sort)的基本操作是将一个记录插入到已经排好序的有序表中,从而得到一个新的、记录增1的有序表。

直接插入排序的核心思想:将一个记录插入到一个已经排序好的表中,以得到一个记录增加1的有序表。并且它把当前元素大的记录都往后移动,用以腾出“自己”该插入的位置。当n-1趟插入完成后该记录就是有序序列。

void InsertSort(SqList *L){
 int i, j;
 for (i = 2; i < L->length; i++) {
 
 if (L->r[i] < L->r[i-1]) {
 
 L->r[0] = L->r[i];
 for (j = i-1; L->r[j] > L->r[0]; j++)
 L->r[j+1] = L->r[i];
 
 L->r[j+1] = L->r[0];
 }
 }
}

代码说明

  • 直接插入排序的时间复杂度为O(n^2)。
  • 直接插入排序比冒泡和简单选择排序的性能要好一些。

 

四、希尔排序

希尔排序是对直接插入排序的改进:

  • 将原本有大量记录数的记录进行分组。分割成若干个子序列
  • 对子序列分别进行直接插入排序
  • 当整个序列都基本有序时注意是基本有序),再对全体记录进行一次直接插入排序。
  • 所谓的基本有序就是小的关键字基本在前,大的基本在后面,不大不小的基本在中间,如{9,1,5,8,3,7,5,6,2},变成{2,1,3,6,4,7,8,9}这样就是基本有序,但是像{1,5,9,7,8,2,4,6}这样9在第三位,2在倒数第三位就不是基本有序。
  • 对于分割子序列,采取跳跃分割的策略
  • 将相距某个“增量”的记录组成一个子序列,这样才能保证在子序列内分别进行直接插入排序后得到的结果是基本有序而不是局部有序。
  • 增量的选取非常关键,但是现在还是一个数学难题(迄今没有找到一种最好的增量序列),大量研究表明,增量序列为dlta[k] = 2^(t-k+1) - 1时,可以获得不错的效果。

希尔排序的核心思想:希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止

  •  
void ShellSort(SqList *L){
 
 int i,j;
 
 int increment = L->length;
 
 do {
 increment = increment /3 +1;
 
 for (i = increment + 1; i < L->length; i++) {
 
 if (L->r[i] < L->r[i-increment]) {
 
 L->r[0] = L->r[i];
 
 for (j = i - increment; i >0 && L->r[0] < L->r[j]; j -= increment)
 L->r[j+increment] = L->r[j];
 
 L->r[j+increment] = L->r[0];
 }
 }
 } while (increment > 1);
}

代码说明

  • 希尔排序的时间复杂度为O(n^(3/2)),要好于直接插入排序的O(n^2);
  • 增量的最后一个增量之必须等于1才行
  • 由于记录是跳跃式的移动,所以希尔排序不是一种稳定的排序算法

 

五、堆排序

堆的概念

堆是具有如下性质的完全二叉树

  • 每个结点的值都大于或等于其其左右孩子结点的值,为大顶堆
  • 或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆
  • 因此根节点一定是堆中所有结点最大(小)者
  • 如图左边为大顶堆,右边为小顶堆:
算法 - 七大排序算法详细介绍

 

  •  
  • 左边为大顶堆,右边为小顶堆

 

堆排序算法

堆排序(Heap Sort)是利用堆(假设是大顶堆)进行排序。

堆排序的核心思想:

  • 将待排序的序列构造成一个大顶堆。
  • 此时,整个序列的最大值就是堆顶的根节点。
  • 将根节点移走(其实就是将它与堆数组的末尾元素交换,此时末尾元素就是最大值),然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素的次小值。
  • 重复上诉操作,便能得到一个有序序列。

 

算法 - 七大排序算法详细介绍

 

 

堆排序算法核心

  • 如何由一个无序序列构建成一个堆
  • 如何在输出堆顶元素后,调整剩余元素成一个新的堆

堆排序算法代码实现

  •  
void HeadAdjust(SqList *L, int s, int m){
 int temp, j;
 temp = L->r[s];
 
 for (j = 2 *s; j <= m; j *= 2) {
 
 if (j < m && L->r[j] < L->r[j+1])
 j++;
 
 if (temp >= L->r[j])
 break;
 
 L->r[s] = L->r[j];
 s = j;
 }
 
 L->r[s] = temp;
}
void HeapSort(SqList *L){
 int i;
 
 for (i = L->length / 2; i>0; i--)
 HeadAdjust(L, i, L->length);
 
 for (i = L->length; i > 1; i--) {
 swap(L, 1, i);
 HeadAdjust(L, 1, i-1);
 }
}

堆排序算法代码说明

  • 堆排序方法HeapSort中有两个for循环:
  • 第一个for循环完成将现在的待排序序列构建成一个大顶堆;
  • 第二个for循环完成逐渐将每个最大值的根节点与末尾元素交换,并且再调整其成为大顶堆。
  • 第一个for循环中的i = L->length / 2,i从[9/2]=4开始,4->3->2->1的变化量。
  • (这里赋值的原因是这些都是有孩子的结点)
  • 构建好有孩子的结点之后,就可以从上到下、从左到右,将每个将每个非终端结点(非叶子结点)当做根节点,将其和子树调整成大顶堆。
  • 函数HeadAdjust的作用是将数组构建成一个大顶堆,在构建的时候利用了二叉树的性质。
  • 构建堆的时间复杂度为O(n),重建堆的时间复杂度为O(nlogn),所以总体来说堆排序的时间复杂度为O(nlogn),性能上远好于冒泡、简单选择、直接插入的时间复杂度。
  • 在空间复杂度上,由于记录的交换和比较是跳跃式进行的,所以堆排序是一种不稳定的排序方法

 

六、归并排序

归并排序(Merging Sort)是利用归并的思想实现的。2路归并排序的核心思想如下:

  • 假设初始序列有n个记录,则可以看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到n/2个长度为2或者1的有序子序列
  • 再两两归并...如此重复,直至得到一个长度为n的有序序列为止。

6.1归并排序的实现思路(递归实现)

  • 将序列平均分成两部分
  • 分别对这两部分用递归来归并
  • 将这两部分归并到一起

归并排序的代码实现(递归实现)

  •  
#pragma - 6.归并排序(递归实现)
void Merge(int SR[], int TR[], int i, int m, int n){
 
 int j, k, l;
 
 for (j = m+1, k = i; i <= m && j <= n; k++) {
 
 if (SR[i] < SR[j])
 TR[k] = SR[i++];
 else
 TR[k] = SR[j++];
 }
 
 if (i <= m) {
 for (l=0; l <= m-i; l++)
 TR[k+l] = SR[i+l];
 }
 
 if (j <= n) {
 for (l=0; l <= n-j; l++)
 TR[k+l] = SR[j+l];
 }
}
void MSort(int SR[], int TR1[], int s, int t){
 int m;
 int TR2[MAXSIZE+1];
 
 if (s == t) {
 TR1[s] = SR[s];
 }else{
 m = (s+t)/2;
 MSort(SR, TR2, s, m);
 MSort(SR, TR2, m+1, t);
 Merge(TR2, TR1, s, m, t);
 }
}
void MergeSort(SqList *L){
 MSort(L->r, L->r, 1, L->length);
}

 

归并排序的总结(递归实现)

  • 归并排序总的时间复杂度为O(nlogn),并且这是归并排序算法中最好、最坏、平均的时间性能。
  • 归并排序的空间复杂度为O(n+logn)
  • 归并排序是一种比较占内存,但是效率高且稳定的算法。

6.2归并排序的实现(迭代非递归实现)

用迭代实现的话,可以从最小的序列开始归并直到完成

  •  
#pragma - 7.归并排序(迭代实现)
void MergePass(int SR[], int TR[], int s, int n){
 
 int i = 1;
 int j;
 
 while (i <= n-2*s+1) {
 Merge(SR, TR, i, i+s-1, i+2*s-1);
 i = i+2*s;
 }
 
 if (i < n-s+1)
 Merge(SR, TR, i, i+s-1, n);
 else
 for (j = i; j <= n; j++)
 TR[j] = SR[j];
}
void MergeSort2(SqList *L){
 
 int * TR = (int *)malloc(sizeof(L->length*sizeof(int)));
 int k = 1;
 
 while (k < L->length) {
 MergePass(L->r, TR, k, L->length);
 k = 2*k;
 
 MergePass(TR, L->r, k, L->length);
 k = 2*k;
 }
}

 

归并的迭代实现总结

  • 非递归的迭代方法,避免了递归时深度为log2n的栈空间,空间只是用到申请归并临时用的TR数组,因此空间复杂度为O(n).
  • 并且相对于递归,在时间性能上也有一定的提升,所以使用归并时,尽量使用非递归实现。

 

七、快速排序

快速排序(Quick Sort)的基本思想是:

  • 通过一趟排序将待排序记录分割成独立的两部分
  • 其中一部分记录的关键字均比另一部分记录的关键字小;
  • 则可分别对这两部分记录继续进行排序,以达到整个序列有序的目的。

快速排序的实现思路

  • 选取一个关键字,放到一个位置,使得它的左边的值都比它小,右边的值都比它大,这个关键字叫做枢轴(pivot)
  • 然后分别对左边和右边进行排序。

快速排序的代码实现

  •  
#pragma - 8.快速排序
int Partition(SqList * L, int low, int high){
 
 int pivotkey;
 pivotkey = L->r[low];
 
 while (low < high) {
 while (low < high && L->r[high] >= pivotkey)
 high --;
 swap(L, low, high);
 
 while (low < high && L->r[low] <= pivotkey)
 high++;
 swap(L, low, high);
 }
 
 return low;
}
void QSort(SqList *L, int low, int high){
 
 int pivot;
 if (low < high) {
 pivot = Partition(L, low, high);
 QSort(L, low, pivot-1);
 QSort(L, pivot+1, high);
 }
}
void QuickSort(SqList *L){
 QSort(L, 1, L->length);
}

 

快速排序的代码说明

  • Partition函数就是将选取的pivotkey不断交换,将比它小的换到它的左边,比它大的交换到它的右边,它也在交换中不断更改自己的位置,直到完全满足这个要求为止。
  • 快速排序的时间性能取决于快速递归的深度,快排的时间复杂度为O(nlogn)
  • 快速排序的空间复杂度主要是递归造成的栈空间的使用,平均情况下空间复杂度为O(nlogn)。
  • 由于关键字的比较和交换是跳跃进行的,因此,快排是一种不稳定的排序算法

快速排序的优化

  1. 优化选取枢轴
  2. 在上面的代码中,选取枢轴的方式为:
  3. pivotkey = L->r[low],即用序列的第一个元素作为枢轴,这是理想情况下 L->r[low]是中间数。
  4. 但是对于其他情况,这种固定选取第一个关键子作为首个枢轴的方法就不是很合理。
  5. 于是可以用下面的方法优化:
  • 三数取中(median-of-three)法
  • 取三个关键子进行排序,将中间数作为枢轴,一般取左端、右端和中间三个数,也可以随机选取。
  • 九数取中(median-of-nine)法
  • 先从数组中分三次取样,每次取三个数,三个样品各取中数,然后从这三个数当中再取出一个中数作为枢轴

三数取中(median-of-three)法代码:

  •  
 int pivotkey;
 
 int m = low + (high - low)/2;
 
 if (L->r[low] > L->r[high])
 swap(L, low, high);
 
 if (L->r[m] > L->r[high])
 swap(L, high, m);
 if (L->r[m] > L->r[low])
 swap(L, m, low);
 
 pivotkey = L->r[low];
  1. 优化不必要的交换
  2. 优化小数组时的排序方案
  3. 优化递归操作

快速排序优化后的代码

  •  
int Partition1(SqList * L, int low, int high){
 
 int pivotkey;
 
 int m = low + (high - low)/2;
 
 if (L->r[low] > L->r[high])
 swap(L, low, high);
 
 if (L->r[m] > L->r[high])
 swap(L, high, m);
 if (L->r[m] > L->r[low])
 swap(L, m, low);
 
 pivotkey = L->r[low];
 L->r[0] = pivotkey;
 
 while (low < high) {
 while (low < high && L->r[high] >= pivotkey)
 high--;
 L->r[low] = L->r[high];
 
 while (low < high && L->r[low] <= pivotkey)
 low++;
 L->r[high] = L->r[low];
 }
 
 L->r[low] = L->r[0];
 
 return low;
}
void QSort1(SqList *L, int low, int high){
 
 int pivot;
 if ((high -low) > MAX_LINEGIH_INSERT_SORT) {
 while (low < high) {
 pivot = Partition1(L, low, high);
 QSort1(L, low, pivot-1);
 
 low = pivot+1;
 }
 }else
 InsertSort(L);
}
void QuickSort1(SqList *L){
 QSort1(L, 1, L->length);
}
  • 希尔排序相当于直接插入排序的升级,同属于插入排序类
  • 堆排序相当于简单选择排序的升级,同属于选择排序类
  • 快速排序相当于冒泡排序的升级,同属于交换排序类
  •  


Tags:算法   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
前言Kafka 中有很多延时操作,比如对于耗时的网络请求(比如 Produce 是等待 ISR 副本复制成功)会被封装成 DelayOperation 进行延迟处理操作,防止阻塞 Kafka请求处理线程。Kafka...【详细内容】
2021-12-27  Tags: 算法  点击:(1)  评论:(0)  加入收藏
分稀疏重建和稠密重建两类:稀疏重建:使用RGB相机SLAMOrb-slam,Orb-slam2,orb-slam3:工程地址在: http://webdiis.unizar.es/~raulmur/orbslam/ DSO(Direct Sparse Odometry)因为...【详细内容】
2021-12-23  Tags: 算法  点击:(7)  评论:(0)  加入收藏
一、什么是冒泡排序1.1、文字描述冒泡排序是一种简单的排序算法。它重复地走访要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地...【详细内容】
2021-12-15  Tags: 算法  点击:(16)  评论:(0)  加入收藏
前面文章在谈论分布式唯一ID生成的时候,有提到雪花算法,这一次,我们详细点讲解,只讲它。SnowFlake算法据国家大气研究中心的查尔斯&middot;奈特称,一般的雪花大约由10^19个水分子...【详细内容】
2021-11-17  Tags: 算法  点击:(24)  评论:(0)  加入收藏
基于算法的业务或者说AI的应用在这几年发展得很快。但是,在实际应用的场景中,我们经常会遇到一些非常奇怪的偏差现象。例如,Facebook将黑人标记为灵长类动物、城市图像识别系统...【详细内容】
2021-11-08  Tags: 算法  点击:(32)  评论:(0)  加入收藏
随着注册制的加速推进,新股越来越多,截止到今天A股上市公司的总数高达4500余家,A股一直就是重融资,轻投资的市场,而上市公司发行可转债这种再融资的(圈钱方式)是最能让普通投资者接...【详细内容】
2021-11-05  Tags: 算法  点击:(98)  评论:(0)  加入收藏
导读:在大数据时代,对复杂数据结构中的各数据项进行有效的排序和查找的能力非常重要,因为很多现代算法都需要用到它。在为数据恰当选择排序和查找策略时,需要根据数据的规模和类型进行判断。尽管不同策略最终得到的结果完...【详细内容】
2021-11-04  Tags: 算法  点击:(40)  评论:(0)  加入收藏
这是我在网上找的资源的一个总结,会先给出一个我看了觉得还行的关于算法的讲解,再配上实现的代码: Original author: Bill_Hoo Original Address: http://blog.sina.com.cn/s/bl...【详细内容】
2021-11-04  Tags: 算法  点击:(36)  评论:(0)  加入收藏
每个人都有过这样的经历:打开手机准备回消息或打电话,一看到微信图标右上方的小红点,于是忍不住先打开微信;看完微信,不知不觉又被另一个App牵引,直到关闭手机屏幕才发现自己早已...【详细内容】
2021-11-03  Tags: 算法  点击:(30)  评论:(0)  加入收藏
文丨互联网怪盗团在互联网行业,尤其是在投资人心目中,往往存在一种“算法迷信”或曰“技术迷信”:某公司的广告变现做得好,一定是因为有算法;某公司的云计算业务开展的好,也是因为...【详细内容】
2021-11-03  Tags: 算法  点击:(25)  评论:(0)  加入收藏
▌简易百科推荐
前言Kafka 中有很多延时操作,比如对于耗时的网络请求(比如 Produce 是等待 ISR 副本复制成功)会被封装成 DelayOperation 进行延迟处理操作,防止阻塞 Kafka请求处理线程。Kafka...【详细内容】
2021-12-27  Java技术那些事    Tags:时间轮   点击:(1)  评论:(0)  加入收藏
博雯 发自 凹非寺量子位 报道 | 公众号 QbitAI在炼丹过程中,为了减少训练所需资源,MLer有时会将大型复杂的大模型“蒸馏”为较小的模型,同时还要保证与压缩前相当的结果。这就...【详细内容】
2021-12-24  量子位    Tags:蒸馏法   点击:(11)  评论:(0)  加入收藏
分稀疏重建和稠密重建两类:稀疏重建:使用RGB相机SLAMOrb-slam,Orb-slam2,orb-slam3:工程地址在: http://webdiis.unizar.es/~raulmur/orbslam/ DSO(Direct Sparse Odometry)因为...【详细内容】
2021-12-23  老师明明可以靠颜值    Tags:算法   点击:(7)  评论:(0)  加入收藏
1. 基本概念希尔排序又叫递减增量排序算法,它是在直接插入排序算法的基础上进行改进而来的,综合来说它的效率肯定是要高于直接插入排序算法的;希尔排序是一种不稳定的排序算法...【详细内容】
2021-12-22  青石野草    Tags:希尔排序   点击:(6)  评论:(0)  加入收藏
ROP是一种技巧,我们对execve函数进行拼凑来进行system /bin/sh。栈迁移的特征是溢出0x10个字符,在本次getshell中,还碰到了如何利用printf函数来进行canary的泄露。ROP+栈迁移...【详细内容】
2021-12-15  星云博创    Tags:栈迁移   点击:(22)  评论:(0)  加入收藏
一、什么是冒泡排序1.1、文字描述冒泡排序是一种简单的排序算法。它重复地走访要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地...【详细内容】
2021-12-15    晓掌柜丶韶华  Tags:排序算法   点击:(16)  评论:(0)  加入收藏
在了解golang的map之前,我们需要了解哈希这个概念。哈希表,又称散列表(Hash table),是根据键(key)而直接访问在内存储存位置的数据结构。也就是说,它通过计算出一个键值的函数,将...【详细内容】
2021-12-07  一棵梧桐木    Tags:哈希表   点击:(14)  评论:(0)  加入收藏
前面文章在谈论分布式唯一ID生成的时候,有提到雪花算法,这一次,我们详细点讲解,只讲它。SnowFlake算法据国家大气研究中心的查尔斯&middot;奈特称,一般的雪花大约由10^19个水分子...【详细内容】
2021-11-17  小心程序猿QAQ    Tags:雪花算法   点击:(24)  评论:(0)  加入收藏
导读:在大数据时代,对复杂数据结构中的各数据项进行有效的排序和查找的能力非常重要,因为很多现代算法都需要用到它。在为数据恰当选择排序和查找策略时,需要根据数据的规模和类型进行判断。尽管不同策略最终得到的结果完...【详细内容】
2021-11-04  华章科技    Tags:排序算法   点击:(40)  评论:(0)  加入收藏
这是我在网上找的资源的一个总结,会先给出一个我看了觉得还行的关于算法的讲解,再配上实现的代码: Original author: Bill_Hoo Original Address: http://blog.sina.com.cn/s/bl...【详细内容】
2021-11-04  有AI野心的电工和码农    Tags: KMP算法   点击:(36)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条