十大经典排序,你真的都会了吗?(源码详解)

点击蓝字

6c253514f861d73833b8d68565bff49a.png

关注我们

一、前言:排序的概念

  • 排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。

  • 稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。

8faa59e6b796cd5032b40057f0c3b4d8.png

  • 内部排序:数据元素全部放在内存中的排序。

  • 外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。

1e989ba9246367c27cd6faed9ccc3abe.png

二、常见排序算法的实现(全都以升序为例)

1、插入排序

1.1、基本思想:

直接插入排序是一种简单的插入排序法,其是基本思想:

把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。

实际中我们玩扑克牌时,就用了插入排序的思想,在排序自己手中的扑克牌时经常会这样排。

1.2、直接插入排序:

当插入第i(i>=1)个元素时,前面的array[0],array[1],…,array[i-1]已经排好序,此时用array[i]的排序码与array[i-1],array[i-2],…的排序码顺序进行比较,找到插入位置即将array[i]插入,原来位置上的元素顺序后移

void InsertSort(int* a, int n)
{for (int i = 0; i < n - 1; i++){int end = i;//单趟排序int tmp = a[end + 1];while (end >= 0){if (a[end] > tmp){a[end + 1] = a[end];//移开,腾位置end--;}elsebreak;}a[end + 1] = tmp;}
}

b2ce8778e62064143c5712fb69e68d16.png

1.3 希尔排序( 缩小增量排序)

希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成多个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取不同的gap,重复上述分组和排序的工作。

gap>1时在做预排序,当到达gap=1时相当于做直接插入排序,所有记录在统一组内排好序。

void ShellSort(int* a, int n)
{int gap = n;while (gap > 1){//gap > 1        预排序//最后一次gap = 1 直接插入排序gap = gap / 3 + 1;for (int i = 0; i < n - gap; i++){int end = i;int tmp = a[end + gap];while (end >= 0){if (a[end] > tmp){a[end + gap] = a[end];end -= gap;}else{break;}}a[end + gap] = tmp;}}
}

cd7efd3bf39ed808885c182650168264.png

2、选择排序

2.1、基本思想

每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。

2.2、直接选择排序

在元素集合array[i]–array[n-1]中选择关键码最大(小)的数据元素若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换在剩余的array[i]–array[n-2](array[i+1]–array[n-1])集合中,重复上述步骤,直到集合剩余1个元素

在这我们写一种优化一点的,我们同时选出最大的和最小的,跟第一个数和最后一个数交换,效率提高了一倍。但也出现了一些问题:

void SelectSort(int* a, int n)
{int left = 0;int right = n - 1;while (left<right){int mini = left, maxi = left;for (int i = left+1; i <= right; i++){if (a[i] < a[mini]){mini = i;}if (a[i] > a[maxi]){maxi = i;}}Swap(&a[mini], &a[left]);if (maxi == left)//防止掉包(很容易漏,很重要!){maxi = mini;}Swap(&a[maxi], &a[right]);left++;right--;}
}

上面有块看上去莫名其妙的代码,用来防止数据被掉包,我来解释一下,这要防的是以下的情况:

0e3ecbd5142fca88e79e99ee00b7d65e.png

为了解决这个问题,我们把maxi换成mini的位置。就有了上面那几行代码

790f813dd033fe022f42ae6d75d68b06.png

2.3、堆排序

堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆。

//向下调整
void AdjustDown(int* a, size_t size, size_t root)
{size_t parent = root;size_t child = root * 2 + 1;while (child < size){//选左右孩子中小的孩子if (child + 1 < size && a[child] < a[child + 1]){child++;}//如果孩子小于父亲,则交换,并继续向下调整if (a[parent] < a[child]){Swap(&a[parent], &a[child]);parent = child;child = parent * 2 + 1;}else{break;}}
}void HeapSort(int* a, int size)
{//向下调整,建堆(从倒数第一个非叶子节点开始,也就是最后一个节点的父亲)for (int i = (size - 1 - 1) / 2; i >= 0; --i){AdjustDown(a, size, i);}size_t end = size - 1;while (end > 0){Swap(&a[0], &a[end]);AdjustDown(a, end, 0);end--;}
}

fc07f506c0daa628e91f35ba5a982178.png

3、交换排序

3.1、基本思想

所谓交换,就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置,交换排序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。

3.2、冒泡排序

冒泡排序,我们的老朋友了。依次比较两个相邻的元素,如果顺序不符合要求,就交换位置。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。

这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。”

在这里我们加一个exchange来判断待排序数列是否已经有序(不交换就是已经有序了),这样的一定程度上提高效率。

void BubbleSort(int* a, int n)
{
for (int i = 0; i < n; i++){
int exchange = 0;
//单趟
for (int j = 1; j < n - i; j++){
if (a[j - 1] > a[j]){exchange = 1;Swap(&a[j - 1], &a[j]);}}
if (exchange == 0)//已经有序了
break;}
}

40acc7b4ab49f8a7e13847397f5c0777.png

3.3、快速排序

快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止

上述为快速排序递归实现的主框架,发现与二叉树前序遍历规则非常像,大家在写递归框架时可想想二叉树前序遍历规则即可快速写出来,后续只需分析如何按照基准值来对区间中数据进行划分的方式即可。

将区间按照基准值划分为左右两半部分的常见方式有三种:

hoare版本

2caf67c53da6c17855a770cbbf0b5875.gif

理解上可能会有的问题:

偶数个数会不会相遇不上?不会,每次都有一边静止,只有一边在移动,一定能追上。

(key取左边)相遇位置的值与key交换,那么如何保证相遇位置的值比key小?右边先走就能保证这里要停下来,只有有两种情况:

  • right先停下(停在比key小的地方),left开始走,并且跟right相遇了

  • 或者left先停下(并跟right交换),然后right开始走,right没有找到比key小的,直接跟left相遇了。这两种情况相遇位置的值都比key小

如果key取右边,左边先走才能保证相遇位置的值比key大

//hoare
int PartSort1(int* a, int left, int right)
{int keyi = left;
while (left < right){
//找小
while (left < right && a[keyi] <= a[right]){
right--;}
//找大
while (left < right && a[keyi] >= a[left]){
left++;}
Swap(&a[left], &a[right]);}
//交换(右边先走,能停在比key小的地方)
Swap(&a[keyi], &a[left]);return left;
}

挖坑法

c56ee4300cb8f21d6c51d6abbeaad7b3.gif

挖坑法 VS hoare版本

效率上来说:两者区别不大

挖坑法的优势是:更容易理解!(如果key取左边)很自然的就右边先走,找小,放到左边的坑里······hoare版本理解上更有难度

//挖坑法
int PartSort2(int* a, int left, int right)
{int key = a[left];int pit = left;
while (left < right){
//找小
while (left < right && key <= a[right]){
right--;}a[pit] = a[right];pit = right;
//找大
while (left < right && key >= a[left]){
left++;}a[pit] = a[left];pit = left;}a[pit] = key;
return pit;
}

前后指针版本

cf94ea6e12a6d538e76236b81a491c4c.gif

prev和cur之间间隔的值都比key大,所以prev和cur交换才能逐步把大的换到右侧,把小的换到左侧

//前后指针
//left
int PartSort3(int* a, int left, int right)
{
int keyi = left;
int cur = left + 1;
int prev = left;
while (cur <= right){
if (a[cur] < a[keyi] && a[++prev] != a[cur])//防止自己和自己交换Swap(&a[cur], &a[prev]);cur++;}Swap(&a[prev], &a[keyi]);
return prev;
}

快速排序优化

如果每次选出的key都是最小或最大的会使效率大大降低。例如:1 2 3 4 5 6 这种已经顺序了的,取最左或者最右都会很慢,于是我们想到能否选出一个不是最大也不是最小的数做key。

三数取中法选key

最左,最右,中间三个位置的数进行比较,选出中等大小的那个做key

//选出中等大小数的下标
int GetMidIndex(int* a, int left, int right)
{int mid = left + (right - left) / 2;if (a[left] < a[mid]){
if (a[mid] < a[right]){
return mid;}
else if (a[left] < a[right]){
return right;}
else{
return left;}}
else{
if (a[right] > a[left]){
return left;}
else if (a[mid] > a[right]){
return mid;}
else{
return right;}}
}
int PartSort3(int* a, int left, int right)
{
//三数取中int mid = GetMidIndex(a, left, right);
Swap(&a[mid], &a[left]);int keyi = left;int cur = left + 1;int prev = left;
while (cur <= right){
if (a[cur] < a[keyi] && a[++prev] != a[cur])//防止自己和自己交换
Swap(&a[cur], &a[prev]);cur++;}
Swap(&a[prev], &a[keyi]);
return prev;
}

快排的结构是类似于二叉树的,二叉树最后几层的数是最多的,排序难度也很低,是否能够不递归到最小区间,中途就运用另一种排序方法返回有序数组给上一层来优化呢?当然是可以的

e7f2300c32256d1b305ff924edae0067.png

小区间优化:递归到小的子区间时,可以考虑使用插入排序 ,减少递归调用

//加小区间优化
void QuickSort2(int* a, int begin, int end)
{// 子区间相等只有一个值或者不存在那么就是递归结束的子问题
if (begin >= end)
return;if (end - begin + 1 <= 13){InsertSort(a + begin, end - begin + 1);}
else{int keyi = PartSort3(a, begin, end);// [begin, keyi-1]keyi[keyi+1, end]QuickSort2(a, begin, keyi - 1);QuickSort2(a, keyi + 1, end);}
}

快速排序非递归

栈的代码可以到我之前的博文找 ,当然你如果会C++的话一切就更简单了。

//非递归
void QuickSort3(int* a, int begin, int end)
{ST st;StackInit(&st);StackPush(&st, begin);StackPush(&st, end);//右边处理完了再处理左边
while (!StackEmpty(&st)){
int right = StackTop(&st);StackPop(&st);
int left = StackTop(&st);StackPop(&st);int keyi = PartSort3(a, left, right);
//[left,keyi-1][keyi+1,right]
if (left < keyi - 1){StackPush(&st, left);StackPush(&st, keyi - 1);}
if (keyi + 1 < right){StackPush(&st, keyi + 1);StackPush(&st, right);}}StackDestory(&st);
}

f65c64f757f651c09945892499f0c6e0.png

4、归并排序

基本思想:

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide andConquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。(有微积分那味了)

bafc1b39d6dc506fae03f945090025c1.gif

//有点像前序遍历
void _MergeSort(int* a, int begin, int end, int* tmp)
{//停止条件——只有一个的时候
if (begin >= end)
return;int mid = begin + (end - begin) / 2;//区间的分割要小心,可能会出现死循环//[begin,mid][mid+1,end]_MergeSort(a, begin, mid, tmp);_MergeSort(a, mid + 1, end, tmp);//归并//printf("[%d, %d][%d, %d]\n", begin, mid, mid + 1, end);int begin1 = begin, end1 = mid;int begin2 = mid + 1, end2 = end;int index = begin;
while (begin1 <= end1 && begin2 <= end2){
if (a[begin1] < a[begin2]){tmp[index++] = a[begin1++];}
else{tmp[index++] = a[begin2++];}}
while (begin1 <= end1){tmp[index++] = a[begin1++];}
while (begin2 <= end2){tmp[index++] = a[begin2++];}//拷回去memcpy(a + begin, tmp + begin, (end - begin + 1) * sizeof(int));
}void MergeSort(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);assert(tmp);_MergeSort(a, 0, n - 1, tmp);free(tmp);
}

4.1、归并排序非递归

边界处理永远的泪

//非递归
void MergeSortR(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);assert(tmp);int gap = 1;while (gap < n){//间距为gap为一组,两两归并
for (int i = 0; i < n; i += 2 * gap){int begin1 = i, end1 = i + gap - 1;int begin2 = i + gap, end2 = i + 2 * gap - 1;//只有end1越界,直接修正
if (end1 >= n)
end1 = n - 1;//begin2不存在,第二个区间不存在,修正成一个不存在的区间
if (begin2 >= n){
begin2 = n;
end2 = n - 1;}//begin2没事end2越界,修正end2
if (end2 >= n)
end2 = n - 1;int index = i;//printf("[%d, %d][%d, %d]\n", begin1, end1, begin2, end2);
while (begin1 <= end1 && begin2 <= end2){
if (a[begin1] < a[begin2]){tmp[index++] = a[begin1++];}
else{tmp[index++] = a[begin2++];}}
while (begin1 <= end1){tmp[index++] = a[begin1++];}
while (begin2 <= end2){tmp[index++] = a[begin2++];}}memcpy(a, tmp, n * sizeof(int));gap *= 2;}free(tmp);
}

103eebd3a1987fd162ce18624f816e2d.png

5、非比较排序

5.1、计数排序

13a612176ffbb0974bca2df9f50a0549.gif

思想:计数排序又称为鸽巢原理,是对哈希直接定址法的变形应用。操作步骤:

  • 统计相同元素出现次数

  • 根据统计的结果将序列回收到原来的序列中

//适用于范围集中的数,排负数也行
void CountSort(int* a, int n)
{
int min = a[0], max = a[0];
for (int i = 1; i < n; i++){
if (a[i] > max)max = a[i];
if (a[i] < min)min = a[i];}
int range = max - min + 1;
int* countA = (int*)calloc(range, sizeof(int));assert(countA);for (int i = 0; i < n; i++){countA[a[i] - min]++;}int j = 0;
for (int i = 0; i < range; i++){
while (countA[i]--){a[j++] = i + min;}}
}

bb4f92702b3c205c13d3d5366ada525f.png

5.2、桶排序

桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。

638ce8833740084d7df9d1fa097d09ef.png

操作步骤:

  • 设置一个定量的数组当作空桶;

  • 每个桶存放该区间的数据,由于每个桶内的数据元素个数不确定,可以使用链表表示,同时使用插入排序,让每个桶的链表有序。

  • 这样按照次序将所有桶的元素连起来就得到完整的有序列表。

typedef int SLTDataType;
typedef struct SListNode
{SLTDataType data;
struct SListNode* next;
}SListNode;void InsertNode(SListNode** bucket, int data)
{SListNode* p = (SListNode*)malloc(sizeof(SListNode));p->data = data;p->next = NULL;// 桶为空 
if (*bucket == NULL){*bucket = p;}
else{SListNode* prev = NULL;SListNode* cur = *bucket;while (cur != NULL && cur->data <= data){prev = cur;cur = cur->next;}
// 对插入到第一个结点前的情况处理
if (prev == NULL){*bucket = p;p->next = cur;}
else{prev->next = p;p->next = cur;}}
}void BucketSort(int* arr, int n)
{
//寻找最大值最小值
int max = arr[0], min = arr[0];
for (int x = 0; x < n; x++) {max = arr[x] > max ? arr[x] : max;min = arr[x] < min ? arr[x] : min;}//获取容量
int bucketsize = (max - min) / n + 1;//获取桶数量
int bucketcount = (max - min) / bucketsize + 1;//申请桶空间SListNode** b=(SListNode**)calloc(bucketcount, sizeof(SListNode*));//分配数据
for (int i = 0; i < n; i++){
//算出arr[i]对应的桶位置
int pos = (arr[i] - min) / bucketsize;InsertNode(&b[pos], arr[i]);}//将数据返回到数组SListNode* tmp;
for (int i = 0, j = 0; i < bucketcount && j < n; i++){
if (b[i] != NULL){tmp = b[i];
while (tmp != NULL){arr[j++] = tmp->data;tmp = tmp->next;}}}//free
for (int i = 0; i < bucketcount; i++){
while (b[i] != NULL){tmp = b[i];b[i] = tmp->next;
free(tmp);}}
free(b);
}

8727a123556e49424a2d7800f7ebd778.png

5.3、基数排序

基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。

78935d355854d5ff2c023c5cdabb463e.gif

//求最大位数
int Maxbit(int* arr, int n)
{
int max = arr[0];
for (int i = 1; i < n; i++){
if (arr[i] > max)max = arr[i];}int k = 1;
while (max >= 10){max /= 10;k++;}return k;
}void RadixSort(int* arr, int n)
{
int k = Maxbit(arr, n);
int radix = 1;
int* tmp = (int*)malloc(sizeof(int) * n);while (k){
int bucket[10] = { 0 };//统计每个桶的数据个数
for (int i = 0; i < n; i++){bucket[arr[i] / radix % 10]++;}//累加
for (int i = 1; i < 10; i++){bucket[i] += bucket[i - 1];}//向tmp数组存入数据
for (int i = n - 1; i >= 0; i--){tmp[bucket[arr[i] / radix % 10] - 1] = arr[i];bucket[arr[i] / radix % 10]--;}//将tmp序列拷贝到原数组中
memcpy(arr, tmp, n * sizeof(int));radix *= 10;k--;}
free(tmp);
}

cbe629fb01cd0dc098b67e40db52e8d5.png

三、总结:排序算法复杂度及稳定性分析

08e8d0bb0b3f9d0e6d0b7b39d73e4e7b.png

排序要说的实在太多了!篇幅有点点长也是意料之内的,希望对大家学习排序知识有所帮助。

*声明:本文于网络整理,版权归原作者所有,如来源信息有误或侵犯权益,请联系我们删除或授权事宜。

db16e21d1603ae0ca2a3d6d7ad0dce7c.png

9ceece61e1029d65424852cdf736973d.gif

戳“阅读原文”我们一起进步

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/337604.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

jvm 架构_不可变的基础架构,热部署和JVM

jvm 架构您是否在生产中部署和取消部署基于JVM的应用程序&#xff08;无论JVM容器/无容器&#xff09;&#xff1f; 也就是说&#xff0c;当您拥有某个应用程序或服务的新版本时&#xff0c;是否通过“取消部署”和“热部署”该应用程序的新更新版本来更改正在运行的JVM&#x…

c语言默认参数_5.1 C++有默认参数的函数

点击上方“C语言入门到精通”&#xff0c;选择置顶第一时间关注程序猿身边的故事作者闫小林白天搬砖&#xff0c;晚上做梦。我有故事&#xff0c;你有酒么&#xff1f;C有默认参数的函数在函数调用时形参从实参获取值&#xff0c;因为实参的个数要和形参相同&#xff0c;但有时…

计算机组成原理唐朔飞课后答案第六章,计算机组成原理第六章部分课后题答案(唐朔飞版)...

计算机组成原理第六章部分课后题答案(唐朔飞版) 6.4 设机器数字‎长为8位(含1位符号‎位在内)&#xff0c;写出对应下‎列各真值的‎原码、补码和反码‎。 -13/64&#xff0c;29/128&#xff0c;100&#xff0c;-87 解&#xff1a;十进制数 二进制数 原 码 反 码 补 码 -13/64 …

jboss eap 7.0_是时候抛弃Java 7 – JBoss EAP 6.4了!

jboss eap 7.0这一周真是太棒了。 JBoss EAP 6.4已发布&#xff0c;在众多技术增强和新功能中 &#xff0c;最大的是&#xff1a;Java 8已添加到受支持的配置列表中。 其中包括Oracle JDK和IBM JDK。 Java SE 7公开更新结束通知 2015年4月之后&#xff0c;Oracle将不再将Java …

C语言史上最愚蠢的BUG ???

点击蓝字关注我们本文来自“The most stupid C bug ever”&#xff0c;很有意思&#xff0c;分享给大家。我相信这样的bug&#xff0c;就算你是高手你也会犯的。你来看看作者犯的这个Bug吧。。首先&#xff0c;作者想用一段程序来创建一个文件&#xff0c;如果有文件名的话&…

python 字符串转日期_我总结的130页Python与机器学习之路V1.2.pdf,都是干货!

告别枯燥&#xff0c;通过学习有趣的小例子&#xff0c;扎实而系统的入门Python&#xff0c;从菜鸟到大师&#xff0c;个人觉得这是很靠谱的一种方法。通过一个又一个的小例子&#xff0c;真正领悟Python之强大&#xff0c;之简洁&#xff0c;真正做到高效使用Python.两周前发出…

大学计算机需要论文吗,大一新生刚开学,是否有必要带电脑?听听辅导员的建议,非常中肯...

原标题&#xff1a;大一新生刚开学&#xff0c;是否有必要带电脑&#xff1f;听听辅导员的建议&#xff0c;非常中肯各大高校的录取工作正在如火如荼的进行&#xff0c;很快考生们就能接到来自各个学校的录取通知书。对于考生来说&#xff0c;没有什么事情会比被心仪的大学录取…

计算机系统是连续系统,连续系统的计算机模拟

连续系统的计算机模拟 (36页)本资源提供全文预览&#xff0c;点击全文预览即可全文预览,如果喜欢文档就下载吧&#xff0c;查找使用更方便哦&#xff01;29.9 积分&#xfeff; 第2章 连续系统的计算机模拟本章讨论连续系统的模拟技术,由于这类系统中状态随时间连续动态地变化&…

ae合成设置快捷键_教程|AE教程第三波:必须掌握的关键帧之基础设置

该如何高效的学习AE&#xff1f;星驰君认为知其然还需知其所以然正确的学习顺序应该是了解核心原理&#xff0c;掌握基本操作&#xff0c;案例实战模仿比如&#xff0c;想要更好的掌握和运用关键帧来制作更复杂的效果。就先要知道关键帧是什么关键帧&#xff1a;计算机动画术语…

老兵精讲:高质量C语言编程的10条规范

点击蓝字关注我们C语言编码规范10条分享给大家&#xff0c;还是可以规避掉很多bug的&#xff01;1、最重要的规则编写代码时最重要的一条规则是&#xff1a;检查周围的代码并尝试模仿它。作为维护人员&#xff0c;如果收到的补丁明显与周围代码的编码风格不同&#xff0c;这是令…

springboot需要tomcat服务器吗_SpringBoot学习(二):内嵌服务器引擎(Tomcat,Jetty)实现原理...

概述SpringBoot使用main方法启动的一个重要特性是&#xff0c;不需要打包成war部署到Tomcat这种Servlet容器中&#xff0c;而是只需打包成jar&#xff0c;然后通过java或mvn等命令运行这个jar包&#xff0c;然后应用就可以在指定的端口监听客户端的连接请求了。在SpringBoot内部…

java8 函数式编程_使用Javaslang进行Java 8中的函数式编程

java8 函数式编程我们非常高兴地在jOOQ博客上宣布一个客座帖子&#xff0c;该帖子由HSH Nordbank的高级软件工程师Daniel Dietrich &#xff08;三人的丈夫和父亲&#xff09;撰写。 他目前作为项目负责人和首席开发人员为金融产品创建定价框架。 除工作外&#xff0c;他还对编…

while(1) 和 for(;;)有什么区别?

点击蓝字关注我们有粉丝问了类似这样的问题&#xff1a;while(1) 和 for(;;)它们不都是无限循环吗&#xff0c;作用应该一样啊&#xff0c;它们到底有什么区别&#xff1f;要回答这个问题&#xff0c;其实你各自编写一段while(1) 和 for(;;)的代码&#xff0c;编译对比一下代码…

C++高阶必会操作--模板元编程

点击蓝字关注我们泛型编程大家应该都很熟悉了&#xff0c;主要就是利用模板实现“安全的宏”&#xff0c;而模板元编程区别于我们所知道的泛型编程&#xff0c;它是一种较为复杂的模板&#xff0c;属于C的高阶操作了&#xff0c;它最主要的优点就在于把计算过程提前到编译期&am…

怎样做远程计算机控制系统,qq远程控制,怎样进行远程控制制作步骤

怎样设置qq远程控制&#xff1f;qq上有一个远程协助不少人都用过&#xff0c;但是这个远程小编建议不是认识的朋友&#xff0c;不要随便开放&#xff0c;很容易被窃取电脑资料&#xff0c;如果是不是很信得过有人&#xff0c;在申请协助时一定要自己盯着电脑&#xff0c;以防别…

pcl中ransac提取直线_复杂场景中的一个图像配准思路

在很多时候&#xff0c;我们可能需要使用到图像的识别与配准工作&#xff0c;来判断某个特征或者是划出某个特定特征的位置。现在的深度学习已经能够比较好地解决这个问题&#xff0c;比如常见的YOLO&#xff0c;可以利用几行设定代码就能够划出所需要识别的位置。但是精准度可…

程序员必知的10个C语言技巧

点击蓝字关注我们硬件设计师最常见的工作内容&#xff0c;就是通过写代码来测试硬件。这10个C语言技巧&#xff08;C语言仍然是常见的选择&#xff09;可以帮助设计师避免因基础性错误而导致某些缺陷的产生&#xff0c;并造成维护方面的困扰。为了成功的推出一个产品&#xff0…

一万字详解C语言中长度为零的数组

点击蓝字关注我们零长度数组概念&#xff1a;众所周知, GNU/GCC 在标准的 C/C 基础上做了有实用性的扩展, 零长度数组&#xff08;Arrays of Length Zero&#xff09; 就是其中一个知名的扩展.多数情况下, 其应用在变长数组中, 其定义如下&#xff1a;struct Packet {int state…

app访问java web_Java Web App体系结构

app访问java web我曾经利用Servlet&#xff0c;JSP&#xff0c;JAX-RS&#xff0c;Spring框架&#xff0c;Play框架&#xff0c;带有Facelets的JSF和一些Spark框架。 以我的拙见&#xff0c;所有这些解决方案都远非面向对象和优雅的。 它们都充满了静态方法&#xff0c;不可测试…

电路中滤波电容和退耦电容_详解电源滤波电路中的高频滤波电容电路

图2-12所示是电源滤波电路中的高频滤波电路。电路中&#xff0c;一个容量很大的电解电容C1(2200F)与一个容量很小的电容C2(0.01F)并联&#xff0c;C2是高频滤波电容&#xff0c;用来进行高频成分的滤波&#xff0c;这种一大一小两个电容相并联的电路在电源电路中十分常见。1.高…