我们通常说的排序算法指的是内部排序算法,即数据在内存中进行排序。
首先先来看一下我们学过的排序都有什么?
排序可以大的方面分为比较排序和非比较排序?
比较排序有:
1、冒泡排序
2、选择排序
3、插入排序
(1)二分插入排序
(2)希尔排序
4、归并排序
5、堆排序
6、快速排序
非比较排序有:
1、计数排序
2、基数排序
3、桶排序
我们先对各种排序进行对比:

我们看到有一个列名叫做稳定性,稳定性的概念是这样定义的:
如果Ai==Aj;排序前Ai在Aj之前,排序后Ai还在Aj之前,则称这种排序算法是稳定的。通俗的讲就是保证排序前后两个相等的数的相对顺序保持不变
排序算法稳定性的好处:排序算法如果是稳定的,那么从一个键上排序然后再从另一个键排序的结果可以为后一个键排序所用。
下面开始逐一进行介绍:
1、冒泡排序
冒泡排序是一个很简单的排序方法,它重复走过要排序的元素,依次比较相邻两个元素,如果顺序错误就把它们交换,然后经过数次交换之后越大(越少)的数会由交换慢慢浮到数列的顶端
冒泡排序的算法:
1、比较相邻的元素,如果前一个比后一个大,就把它们交换位置
2、对每一对相邻元素作相同的操作,从开始的一对到结束的一对,最后的元素就是最大的数
3、针对所有的元素作相同的工作,除了最后一个
4、持续每次对越来越少的元素进行如上操作,直到没有一对数字需要比较
代码如下:

#include<stdio.h>
void BubbleSort(int A[],int size)
{for (int j= 0; j < size - 1; j++)//控制每次循环最大元素浮动到数组最后{for (int i = 0; i < size - 1- j; i++)//控制左右相邻的比较{if (A[i]>A[i + 1]){int tmp = A[i];A[i] = A[i + 1];A[i + 1] = tmp;}}}
}int main()
{int A[] = {2,6,4,8,1,5,9};int size = sizeof(A) / sizeof(A[0]);BubbleSort(A, size);for (int i = 0; i < size ; i++){printf("%d ", A[i]);}printf("\n");return 0;
}

运行结果如下:

(1)冒泡排序的改进:鸡尾酒排序
鸡尾酒排序也叫定向冒泡排序,是冒泡排序的一种改进,不同点是此算法从低到高然后从高到低,而冒泡排序仅仅从低到高去比较序列中的每个元素,此算法相比而言效率更高。

#include<stdio.h>
void Swap(int A[], int i, int j)
{int tmp = A[i];A[i] = A[j];A[j] = tmp;
}
void BubbleSort(int A[], int size)
{int left = 0;int right = size - 1;//对边界进行初始化while (left < right){for (int i = 0; i < right; i++)//前半段控制将最大的元素放在后面{if (A[i]>A[i + 1]){Swap(A, i, i + 1);}}right--;for (int j = right; j > left; j--)//后半段控制将最小元素放在最前面{if (A[j - 1] > A[j]){Swap(A, j - 1, j);}}left++;}
}
int main()
{int A[] = { 2, 6, 4, 8, 1, 5, 9 };int size = sizeof(A) / sizeof(A[0]);BubbleSort(A, size);for (int i = 0; i < size; i++){printf("%d ", A[i]);}printf("\n");return 0;
}

运行结果:

2、选择排序
选择排序也是一种非常简单的排序算法,工作原理是:初始时在序列中找到最小(最大)元素,放在序列的初始位置作为已排序序列,然后再从剩余未排序序列中找最小(最大)元素,放在已排序序列的末尾,一直持续,直到所有元素排序完毕
选择排序和冒泡排序的区别是:冒泡排序通过依次变换两个相邻元素顺序不合法的位置,从而将当前最小(最大)元素放到合适的位置,而选择排序是每遍历依次都记住当前最小(最大)元素的位置,最后仅需一次操作就可以将元素放在合适的位置。
代码如下:

#include<stdio.h>
void Swap(int A[], int i, int j)
{int tmp = A[i];A[i] = A[j];A[j] = tmp;
}
void SelectSort(int A[], int size)
{for (int i = 0; i < size - 1; i++){int min = i;for (int j = i + 1; j < size; j++){if (A[min] > A[j])min = j;}if (min != i)Swap(A, min, i);}}
int main()
{int A[] = { 2, 6, 4, 8, 1, 5, 9 };int size = sizeof(A) / sizeof(A[0]);SelectSort(A, size);for (int i = 0; i < size; i++){printf("%d ", A[i]);}printf("\n");return 0;
}

运行结果:

3、插入排序
插入排序是一种非常直观的排序算法,它的工作原理类似于玩扑克牌。
对于未排序数据,在已排序序列中找到相应的位置并插入
具体算法:
(1)从第一个元素开始,该元素可以认为已经被排序
(2)取出下一个元素,在已经排序的元素序列中从后向前扫描
(3)如果该元素大于新元素,将该元素移到下一位置
(4)重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
(5)将新元素插在该位置之后
(6)重复步骤2-5

代码如下:

#include<stdio.h>
void InsertSort(int A[], int size)
{for (int i = 0; i < size; i++){int get = A[i];int j = i - 1;while (j >= 0 && A[j]>get){A[j+1 ] = A[j];j -- ;}A[j + 1] = get;}
}
int main()
{int A[] = { 2, 6, 4, 8, 1, 5, 9 };int size = sizeof(A) / sizeof(A[0]);InsertSort(A, size);for (int i = 0; i < size; i++){printf("%d ", A[i]);}printf("\n");return 0;
}

运行结果:

插入排序不适合对数据量比较大的排序应用,但是如果排序的数据量很小,比如数据量小于千,那么插入排序还是一个不错的选择,stl中的sort和stdlib中的qsort都将插入排序作为快速排序的补充
4、插入排序的改进二分插入排序
对于插入排序,如果比较操作的代价比交换操作大的话,可以先采用二分查找来减少比较操作的次数,我们称为二分插入排序
代码如下:

#include<stdio.h>
void HalfInsertSort(int A[], int size)
{for (int i = 1; i < size; i++){int get = A[i];//右手抓到一张扑克牌int left = 0;//左手上的牌是已排序的int right = i - 1;//手牌左右边界进行初始化while (left <= right)//二分法确定新牌的位置{int mid = left + ((right - left) >> 1);if ( A[mid] > get)right = mid - 1;else left = mid + 1;}for (int j = i - 1; j >= left; j--)//将新牌吃哈如位置\后面的元素依次向后移动一个位置{A[j + 1] = A[j];}A[left] = get;}
}
int main()
{int A[] = { 2, 6, 4, 8, 1, 5, 9 };int size = sizeof(A) / sizeof(A[0]);HalfInsertSort(A, size);for (int i = 0; i < size; i++){printf("%d ", A[i]);}printf("\n");return 0;
}

运行结果:

当较大时,二分插入排序的比较次数比直接插入排序的最差情况好的多,但比直接插入排序的最好情况要差,所以当以元素初始序列已经接近升序时,直接插入排序比二分插入排序比较次数少。
5、插入排序的更高效改进:希尔排序
希尔排序又叫做递减增量排序,是插入排序的一种更高效的改进版本,希尔排序是不稳定的排序算法
希尔排序是基于插入排序的以下两种性质而提出改进办法的
(1)插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率
(2)但插入排序一般来说是低效的,因为插入排序每次只能将数据移动移一位
希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能。这样可以让一个元素可以一次性地朝最终位置前进一大步,然后算法再取越来越小得步长,进行排序,算法的最后一步就是普通的插入排序,但是到了这一步,需要排序的元素几乎是已经排好的了
代码如下:

#include<stdio.h>
void ShellSort(int A[], int size)
{int h = 0;while (h <= size)//确定初始增量{h = h * 3 + 1;}while (h >= 1){for (int i = h; i < size; i++){int j = i - h;int get = A[i];while (j >= 0 && A[j]>get){A[j + h] = A[j];j = j - h;}A[j + h] = get;}h = (h - 1) / 3;//递减增量}
}
int main()
{int A[] = { 2, 6, 4, 8, 1, 5, 9 };int size = sizeof(A) / sizeof(A[0]);ShellSort(A, size);for (int i = 0; i < size; i++){printf("%d ", A[i]);}printf("\n");return 0;
}

运行结果:

6、归并排序
归并排序是创建在归并操作上的一种有效的排序算法,效率为O(nlogn)
归并排序的实现分为递归实现和非递归实现。递归实现的归并排序是算法设计中分治策略的典型应用,我们将一个大问题分成若干个小问题分别解决,用小问题的大单来解决整个大问题。非递实现的归并排序首先进行的是两两归并,然后是四四归并,然后是八八归并,一直下去直到归并了整个数组
归并排序算法主要依赖归并操作。归并操作指的是将两个已经排序的序列合并成一个序列的操作,归并操作步骤如下:
(1)申请空间,使其大小为两个已排序序列之和,该空间用来存放合并后的序列
(2)设定两个指针,最初位置分别为两个已经排序序列的起始位置
(3)比较两个指针所指向的元素,选择相对于小得元素放入到合并空间,并移动指针到下一位置
(4)重复步骤3直到某一指针到达序列尾
(5)将另一序列剩下的所有元素直接复制到合并序列尾

#include<stdio.h>
#include<malloc.h>
void Merge(int A[], int left, int mid, int right)
{int size = right - left+1;int *tmp = (int *)malloc(size*sizeof(int));int i = left;int j = mid + 1;int index = 0;while (i <= mid&&j <= right){tmp[index++] = A[i] < A[j] ? A[i++] : A[j++];}while (i <= mid){tmp[index++] = A[i++];}while (j <= right){tmp[index++] = A[j++];}for (int k = 0; k < size; k++){A[left++] = tmp[k];}}void MergeSort(int A[], int left, int right)
{if (left == right)return;int mid = left + ((right - left) >> 1);MergeSort(A, left, mid);MergeSort(A, mid + 1, right); Merge(A, left, mid, right);
}
int main()
{int A[] = { 2, 6, 4, 8, 1, 5, 9 };int size = sizeof(A) / sizeof(A[0]);MergeSort(A, 0,size-1);for (int i = 0; i < size; i++){printf("%d ", A[i]);}printf("\n");return 0;
}

运行结果:

7、堆排序
堆排序是指利用堆这种数据结构所设计的一种选择排序法。堆是一种近似完全安全二叉树的结构(通常堆是通过一维数组来实现的),并满足性质:以最大堆(也叫大根堆,大顶堆)为例,其中父节点的值总是大于它的孩子节点。
堆排序的过程:
(1)由输入的无序数组构造一个最大堆,作为初始的无序区
(2)把堆顶元素(最大值)和堆尾元素互换
(3)把堆(无序区)的尺寸缩小1,并调用heapify(A,0)从新的堆顶元素开始进行堆调整
(4)重复步骤2,直到堆的尺寸为1
代码如下:

#include<stdio.h>
void Swap(int A[], int i, int j)//交换函数
{int tmp = A[i];A[i]=A[j];A[j] = tmp;
}
void HeapModify(int A[], int i, int size)//从A[i]向下进行调整
{int left_child = i * 2 + 1;//左孩子索引int right_child = i * 2 + 2;//右孩子索引int max = i;//选出当前节点与其左右孩子三者中最大值if (left_child<size&&A[left_child] > A[max])max = left_child;if (right_child<size&&A[right_child]>A[max])max = right_child;if (max != i){Swap(A, i, max);//将当前节点与其最大子节点进行交换HeapModify(A, max, size);//递归调用,继续从当前节点向下进行堆调整}
}
int BuildHeap(int A[], int size)//创建堆,时间复杂度0(n)
{int Heap_size = size;for (int i = Heap_size/2-1; i >= 0; i--)//从每一个非叶子节点,\开始向下进行堆调整{HeapModify(A, i, Heap_size);}return Heap_size;
}void HeapSort(int A[], int size)
{int Heap_size = BuildHeap(A,size);//建立一个最大堆while(Heap_size > 1)//堆元素个数大于1,未完成排序{//将堆顶元素与堆的最后一个元素互换,并从堆中去掉最后一个元素//此处交换操作很有可能把后面的元素的稳定性打乱,所以堆排序是不稳定的排序算法Swap(A, 0, --Heap_size );HeapModify(A,0, Heap_size);//从新的堆顶元素开始向下进行堆调整,时间复杂度O(logn)}
}
int main()
{int A[] = { 2, 6, 4, 8, 1, 5, 9 };int size = sizeof(A) / sizeof(A[0]);HeapSort(A, size);printf("堆排序\n");for (int i = 0; i < size; i++){printf("%d ", A[i]);}printf("\n");return 0;
}

运行结果如下:

8、快速排序
快速排序共有三种方法:基准值法,挖坑法和两个指针法
下面依次进行介绍:
(1)基准值法,取第一个或最后一个作为基准值(可以用三数取中法进行优化),定义两个标记left和right,left指向起始位置,right指向结束位置,right从后往前找直到找到比基准值小的停下来,left从前往后找,找到比基准值大的停下来,然后交换arr[left]和arr[right]的值,重复上述动作直到left>=right然后将基准值和当前停下来的位置进行交换,这样整个数组玖分成两半,左一半是比基准值小得,右一半是比基准值大的,然后递归处理整个数组就可以了。
代码如下:

#include<stdio.h>
void Swap(int A[], int i, int j)
{int tmp = A[i];A[i] = A[j];A[j] = tmp;
}
int position(int A[], int left, int right)
{int key = left;while (left < right){while (left < right&& A[key] > A[left]){++left;}while (left < right&& A[key] < A[right]){--right;}if (left < right){Swap(A, left, right);}}Swap(A, key, left);return left;
}
void QuickSort(int A[], int left, int right)
{if (left < right){int n =position(A, left, right);QuickSort(A, left, n - 1);QuickSort(A, n+1 , right);}
}
int main()
{int A[] = { 2, 6, 4, 8, 1, 5, 9 };int size = sizeof(A) / sizeof(A[0]);QuickSort(A, 0,size-1);printf("快速排序\n");for (int i = 0; i < size; i++){printf("%d ", A[i]);}printf("\n");return 0;
}

运行结果:

(2)挖坑法
算法描述:这个算法也是从基准值法演变而来的,首先取首元素为基准值,用变量key来保存就相当于被挖走了,就形成了一个坑,然后从后往前找比key值小的填到第一个的位置,那么array[right]这里又是一个坑了,所以再让left从左往右找比key大的元素,(然后将array[right])的坑填了,然后让right继续从后面找填上一个坑,以此类推,直到left==right此时此处必定为一个坑,然后将key值填进去就好了,这个时候数组就分为两组和上述情况一样,然后递归调用就可以了
代码如下:

#include<stdio.h>
int position(int A[], int left, int right)
{int key = A[left];while (left < right){while (left < right&&key < A[right]){right--;}if (left < right){A[left] = A[right];}while (left<right&&key>A[left]){left++;}if (left < right)A[right] = A[left];}A[left] = key;return left;
}
void QuickSort(int A[], int left, int right)
{if (left < right){int n = position(A, left, right);QuickSort(A, left, n - 1);QuickSort(A, n + 1, right);}
}
int main()
{int A[] = { 2, 6, 4, 8, 1, 5, 9 };int size = sizeof(A) / sizeof(A[0]);QuickSort(A, 0, size - 1);printf("快速排序2\n");for (int i = 0; i < size; i++){printf("%d ", A[i]);}printf("\n");return 0;
}

运行结果:

3、两个指针法
算法描述:同样取最后一个元素为基准值,然后定义两个指针(指向下标的所以这里说是指针),fast指向left,slow指向left-1,然后fast开始走,找到比array[right]小得元素则slow开始走,当slow走完以后判断fast是否等于slow如果不等于交换arr[slow] 和arr[fast],相等的话不交换,然后fast继续走,如果所指的数都大于arr[right]则slow不动当fast==slow时循环结束,此时slow++然后交换arr[slow]和arr[right],此时数组被分为两部分递归调用。

代码如下:

#include<stdio.h>
void Swap(int A[],int i, int j)
{int tmp = A[i];A[i] = A[j];A[j] = tmp;
}
void TreeNumberGetMid(int A[], int left, int right)
{int mid = left + ((right - left) >> 1);if (A[mid] > A[left] && A[mid] < A[right]){Swap(A,mid,right);return;}if (A[left]>A[mid] && A[right] < A[right]){Swap(A,left, right);return;}if (A[right]>A[mid] && A[right] < A[left])return;
}
int position(int A[], int left, int right)
{TreeNumberGetMid(A, left, right);int fast = left;int slow = left - 1;while (fast < right){if (A[fast] < A[right]){++slow;if (slow != fast)Swap(A,fast, slow);}fast++;}++slow;Swap(A,slow, right);return slow;
}
void QuickSort(int A[], int left, int right)
{if (left < right){int n = position(A, left, right);QuickSort(A, left, n - 1);QuickSort(A, n + 1, right);}
}
int main()
{int A[] = { 2, 6, 4, 8, 1, 5, 9 };int size = sizeof(A) / sizeof(A[0]);QuickSort(A, 0, size - 1);printf("快速排序3\n");for (int i = 0; i < size; i++){printf("%d ", A[i]);}printf("\n");return 0;
}

运行结果如下:

下面来介绍非比较排序:
1、计数排序
首先遍历一遍原数组,找到最大的数和最小的数,将每个数出现的次数用一个大小充足的数组进行保存,然后遍历这个标记数组对数组进行还原,就得到排好序的序列

#include<iostream>
using namespace std;
void CountSort(int arr[], int size)
{int max = arr[0];int min = arr[0];for (int i = 1; i < size; i++){if (arr[i]>max)max = arr[i];if (arr[i] < min)min = arr[i];}int _size = max - min + 1;int *temp = new int[_size];memset(temp, 0x00, _size * 4);for (int i = 0; i < size; i++){temp[arr[i] - min]++;}int index = 0;for (int i = 0; i < _size; i++){while (temp[i]--){arr[index++] = i + min;}}delete[] temp;
}
int main()
{int arr[] = { 0, 2, 5, 6, 9, 8, 8, 6, 7, 3 };int size = sizeof(arr) / sizeof(arr[0]);CountSort(arr, size);cout << "计数排序" << endl;for (int i = 0; i < size; i++){cout << arr[i] << " ";}cout << endl;return 0;
}

运行结果:
2、基数排序:
先按照个位数将数据放进对应的桶里面,然后将数据按照顺序写回原数组,然后再按照十位数将数据放进对应的桶里面,然后按照顺序写回原数组,一次类推直到所有位数都比较完成。
代码如下:

void BaseSort(int arr[], int size)
{int count = 1;//位数int elem = 1;int radix = 10;int *temp = new int[size];for (int i = 0; i < size; i++)//求数组中最大数的位数{while (arr[i]>radix){count++;radix *= 10;}}for (int i = 0; i < count; i++){int count[10] = { 0 };for (int j = 0; j < size; j++){count[arr[j] / elem % 10]++;}int position[10] = { 0 };for (int j = 1; j < 10; j++){position[j] = position[j - 1] + count[j - 1];}for (int j = 0; j < size; j++){int ret = arr[j] / elem % 10;temp[position[ret]++] = arr[j];}memcpy(arr, temp, sizeof(arr[0])*size);elem *= 10;}delete[] temp;
}
int main()
{int arr[] = {2,3 , 5,2,6,1,0,8};int size = sizeof(arr) / sizeof(arr[0]);BaseSort(arr,size);cout << "基数排序" << endl;for (int i = 0; i < size; i++){cout << arr[i] << " ";}cout << endl;return 0;
}

运行结果如下:

3、桶排序
桶排序也叫箱排序。工作的原理是将数组元素映射到有限数量个桶里,利用计数排序可以定位桶的边界,每个桶再各自进行桶内排序
代码如下;

#include<iostream>
using   namespace std;
const int bn = 5;//桶的·个数
int c[bn];//计数数组
int MapToBucket(int x)//映射函数
{return x / 10;
}
void CountSort(int arr[], int size)//找边界
{for (int i = 0; i < size; i++){c[i] = 0;}for (int i = 0; i < size; i++){c[MapToBucket(arr[i])]++;}for (int i = 1; i < size; i++){c[i] = c[i] + c[i - 1];}int *B = new int[size];for (int i = size - 1; i >= 0; i--){int b = MapToBucket(arr[i]);B[--c[b]] = arr[i];}for (int i = 0; i < size; i++){arr[i] = B[i];}delete[] B;
}
void InsertSort(int arr[], int left, int right)
{for (int i = left + 1; i <= right; i++){int get = arr[i];int j = i - 1;while (j >= left&&arr[j] > get){arr[j + 1] = arr[j];j--;}arr[j + 1] = get;}
}
void BucketSort(int arr[], int size)
{CountSort(arr, size);for (int i = 0; i < bn; i++){int left = c[i];int right = (i == bn - 1 ? size - 1 : c[i + 1] - 1);if (left < right){InsertSort(arr, left, right);}}
}
int main()
{int arr[] = { 2, 3, 5, 0, 8, 9, 4 };int size = sizeof(arr) / sizeof(arr[0]);BucketSort(arr, size);cout << "桶排序" << endl;for (int i = 0; i < size; i++){cout << arr[i] << " ";}cout << endl;return 0;
}

运行结果:

【数据结构】排序算法总结及代码实现相关推荐

  1. 【数据结构排序算法系列】数据结构八大排序算法

    排序算法在计算机应用中随处可见,如Windows操作系统的文件管理中会自动对用户创建的文件按照一定的规则排序(这个规则用户可以自定义,默认按照文件名排序)因此熟练掌握各种排序算法是非常重要的,本博客将 ...

  2. 数据结构-排序算法(c语言实现篇)

    数据结构-排序算法(c语言实现篇) 排序算法是非常常用的算法,从介绍排序的基本概念,到介绍各种排序算法的思想.实现方式以及效率分析.最后比较各种算法的优劣性和稳定性. 1 排序的概念及应用 1.1 排 ...

  3. 数据结构---排序算法的总结

    数据结构-排序算法的总结 分类 冒泡排序,时间复杂度O(n x n),空间复杂度O(1),稳定 简单选择排序,时间复杂度O(n x n),空间复杂度O(1),不稳定 希尔排序,时间复杂度O(n^1.3 ...

  4. python 代码排布_python实现经典排序算法的示例代码

    以下排序算法最终结果都默认为升序排列,实现简单,没有考虑特殊情况,实现仅表达了算法的基本思想. 冒泡排序 内层循环中相邻的元素被依次比较,内层循环第一次结束后会将最大的元素移到序列最右边,第二次结束后 ...

  5. 数据结构-排序算法总结与感悟

    数据结构-排序算法总结 一,排序的基本概念 排序:有n个记录的序列{R1,R2,-,Rn},其相应关键字的序列是{K1,K2, -,Kn },相应的下标序列为1,2,-, n.通过排序,要求找出当前下 ...

  6. C++基础-介绍·数据结构·排序·算法

    C++基础-介绍·数据结构·排序·算法 特点 使用方向 RPC Data Struct 数据结构 栈 Stack 内存分配中的栈 队列 List 数组 Array 链表 LinkTable 树 Tre ...

  7. 利用Python实现十大经典排序算法(附代码流程)

    关注上方"深度学习技术前沿",选择"星标公众号", 资源干货,第一时间送达! 作者:hustcc 来源:https://github.com/hustcc/JS ...

  8. 数据结构排序算法实验报告_数据结构与算法-堆排序

    堆排序 堆排序是指利用堆这种数据结构所设计的一种排序算法.堆是一个近似完全二叉树的结构,并同时满足堆的性质:即子节点的键值或索引总是小于(或者大于)它的父节点,堆排序的时间复杂度为O(nlogn).( ...

  9. 选择排序稳定吗_最常见的四种数据结构排序算法你不知道?年末怎么跳槽涨薪...

    前言 在学习数据结构的时候必然接触过排序算法,而且在日常开发中相信排序算法用得也比较多.而排序算法众多,各个效率又不同,难以记住.小编今天会介绍一些常用排序算法的特点和实现,对比不同排序算法的效率. ...

最新文章

  1. java web项目测试_java web项目怎么测试?
  2. /proc文件夹介绍
  3. c语言字符数组给字符指针,C语言常见有关问题之字符串数组和字符指针数组有关问题...
  4. boost::detail::sp_typeinfo_相关的测试程序
  5. 怎么用PHP修改文字大小,如何利用PHP和CSS改变网页文字大小
  6. html乱码框框,springmvc+font-awesome开发出的页面显示方框乱码的解决方法
  7. http协议建立在以下哪一个协议的基础上_HTTP协议梳理
  8. oracle复杂密码,如何配置 Oracle 11g 复杂密码校验设置
  9. 并发设计模式之Guarded Suspension模式
  10. python有趣小程序-知道了这个,你也能写出 Python 趣味小程序
  11. 20200203_selenium爬取百度新闻
  12. 老调重弹:对kvo的封装思路
  13. 万字精选长文,深入解读房地产土地投资测算路径(附下载)
  14. 知乎2019新知青年大会:用问题改变世界的方向
  15. 没有CCTV-5也不用慌的世界杯观战指南
  16. 阿里云 vps 关机 重启 无法连接
  17. 计算机过滤器的作用,前置过滤器有什么好处 前置过滤器好处介绍【详解】
  18. 在ubuntu下安装炉石传说
  19. vue项目首屏加载优化
  20. 利用ACM服务,快速申请免费的公有证书,你get到了吗?

热门文章

  1. linux 进程状态ss,linux ss 命令用法说明
  2. 我才不愿做那个任人欺负的人
  3. 故事发生在5G背面:物联网变局的真相
  4. 仿热血江湖NpcClass群攻查找范围Npc
  5. 怎样确定样本容量的理论解释
  6. AB实验中最小样本量的计算
  7. linux at命令 详解+例子 仅一次定时执行任务
  8. Mac系统下查看鼠标所在点的RGB值--数码测色计
  9. Kotlin学习笔记(三)集合类
  10. html5 回到顶部按钮,“返回顶部”按钮效果