《数据结构与算法》之十大基础排序算法

一.冒泡排序

什么是冒泡排序?

冒泡排序是一种交换排序,它的思路就是在待排序的数据中,两两比较相邻元素的大小,看是否满足大小顺序的要求,如果满足则不动,如果不满足则让它们互换。

然后继续与下一个相邻元素的比较,一直到一次遍历完成。一次遍历的过程就被成为一次冒泡,一次冒泡的结束至少会让一个元素移动到了正确的位置。

所以要想让所有元素都排序好,一次冒泡还不行,我们得重复N次去冒泡,这样最终就完成了N个数据的排序过程。

冒泡排序又有两种情况:向上冒泡和向下冒泡

向上冒泡指的是:在排序的时候把大的数据排在前面,小数据在后面,这样排序出来的小序列会是从大到小的顺序

向下冒泡指的是:在排序的时候把大的数据排在后面,小数据在前面,这样排序出来的顺序会是从小到大的

具体的冒泡方向要根据自己的要求去设计

冒泡排序实际上是相邻两个数据的按条件交换排序,然后遍历式的交换排序

它排序需要两次循环来设计:

第一循环控制排序几次

第二循环负责每次交换遍历数据的相邻数据交换

对于排序次数,可以根据数据的个数n,确定次数为:n-1次

下面我们来图示一下我们的排序方法:

 下面我们来看看冒泡排序的伪代码:

 冒泡排序可以说是比较简单的排序方法了:它的时间复杂的是O(n^2)

冒泡排序的交换关键在于那个if判断语句:

这里的【if语句】可以用大于等于也可以使用大于符号,

但是我使用的是大于号,因为排序的稳定性,如果使用大于等于号,两个相等的数据,它也会交换,这样的排序计算就不稳定,也提高了系统开销,

因为当两个相同的数据本身是有序的,如果让它们交换,在内存中它们也会发生相应的移动,提升了开销,所以这里建议使用大于号就好了

二.选择排序

什么是选择排序?

选择排序的原理就是在一个待排序的数组中,首先从前至后(或从后至前)对数组遍历后选取最大 (或最小)的数,与数组首(尾)的数进行交换。

选择排序的排序次数也是数据个数n,排序次数就是:n - 1

他会根据次数的减少,待排序的数据也会减少

它与冒泡排序不同的是它不会频繁的发生交换,交换次数比冒泡排序要少,每次就直接遍历数据,然后把最大/小的数据放在序列后/前面

这里图解一下选择排序:

 选择排序只会在一次排序中交换一次,所以交换的次数就是,n - 1次

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

我们使用伪代码来实现一下选择排序:

 选择排序一次遍历只会把当前的序列的最大数找出来,然后放在最前或者最后面

遍历的次数也会随着已排序的次数减少,因为没排序最大/小数就已经被找出来了,不需反复去校对

三.插入排序

什么是插入排序?

插入排序,也被称为直接插入排序。对于少量元素的排序,它是一个有效的算法 。插入排序是一种最简单的排序方法,它的基本思想是将一个记录插入到已经排好序的有序表中,从而一个新的、记录数增1的有序表。

在其实现过程使用双层循环,外层循环对除了第一个元素之外的所有元素,内层循环对当前元素前面有序表进行待插入位置查找,并进行移动。

插入排序是稳定的。

 插入排序是最简单容易理解的一种排序算法,它依靠的是直接覆盖,只要找到它因该在的位置,就让其它的数据往后移一个一个的覆盖,直到留出它应该插入的位置

这个覆盖其实是动态的,只要没找到位置,就会先往后覆盖一个,然后向前继续找位置,继续覆盖

这个数据在开始就被其它变量存储了,所以不会存在丢失数据的情况

我们一起去看看插入排序的伪代码:

 算法是由for循环和while共同构成的,着重看看while循环

j > = 0  如果这个条件不满足,说明前面的数据都比它大,这个数据肯定是最小数据,就直接插入在 第一个位置

arr[ j ]  > temp  说明当前数据比前面一个数据小,我们就要排它前面

插入排序的时间复杂度:O(N ^2)

四.希尔排序

什么是希尔排序?

希尔排序(Shell's Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因D.L.Shell于1959年提出而得名。

从上面我们很容易看出来,它是插入排序的高级版

希尔排序依赖于增量序列,一个好的增量序列可以是希尔排序的复杂度达到 N 的 4/3 次方,

最快的Sedgewick增量序列:时间复杂度只有 N的7/6次方

希尔排序在每次选定增量序列后,排序都是选择排序,但是它的算法优于选择排序,因为增量序列是成比例缩小的,并不是一定会排序 n-1次

希尔排序的排序次数比选择排序要少很多,

增量序列的选定:数据个数 N 

一般使用 N/2 , N/4 , N/8  等等构成的数据序列

我们使用的是 n/2 构成的序列组合

 在增量循环中时,我们使用的也是插入排序,

所以第二次增量排序为什么能直接把 5 , 6 , 9给一次排序出来就是根据插入排序的移动覆盖

我们来看看希尔排序的伪代码:

 希尔排序比插入排序的优点在于,它的增量序列比 插入排序的 n-1次 排序次数少

也导致了希尔排序比插入排序快

总的来说,希尔排序的优劣取决于增量序列

 五.归并排序

什么是归并排序?

归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

作为一种典型的分而治之思想的算法应用,归并排序的实现由两种方法

  • 自上而下的递归
  • 自下而上的迭代

归并排序的时间复杂度始终为O(NLogN),在排序算法算是快的了,但是他对空间需求大,需要额外开辟一个相同大小的空间

归并排序是分治法演化来的,他与分治法一样,

先把数据分成最小单位元素,然后再按要求合并,最后在一次次合并中慢慢变成最后排序的答案

我们来图解一下归并排序:

我们在拆分的时候必须给数组找一个分界点,在取分界点的时候,一般使用 数组的  最大下标 / 2  ,大家可以想想为什么不是数组长度直接 /2(也可以用,但不建议) ?

找到分界点的时候划分成两半,然后依次进行,直到划分到最小分量的时候就合并。

在合并的时候,我们要注意,有两个半区,左半区和右半区都要有一个变量来指向左半区和右半区数据的当前的位置,然后左右半区的数据依次比较,数据值小的就先进入临时数组

当比较完了,可能有一个半区还有数据,因为那个(或那几个数据都是)最大的,没有数据能把它们比进临时数组,所以要注意把这些数据直接copy到临时数组中

现在我们用伪代码来描述一下这个算法:

merge_sort  函数负责的是申请一个临时的空间,辅助我们在归并的时候转存这个数据,因为这个函数是归并排序的入口,当归并排序完成以后他还会回到这个函数,

所以为了方便,我们直接把申请的空间,释放代码部分也放在这里,我们在使用C语言写了这些内存的代码一定要释放掉,不然会一直占用系统资源,而且会发生内存泄漏。

msort  函数负责把传过来的一个函数给他拆分成成局部最小分量

merge  函数负责归并,连=两个小半区的比较,小的就先存入临时数组,当小分区比较完成以后,我们需要对有一个半区残留的元素直接copy到临时数组中,残留的元素一定是当前分区最大的且是有序的,

最后一定要记得把临时数组中的数据覆盖到原数组,毕竟最后的返回值还是原数组;

 归并排序:

每一层归并的时间是O(N)

归并层数为O(LogN+1)

所以:时间复杂度是 O(NLogN)

六. 快速排序

什么是快速排序?

快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。

快速排序又是一种分而治之思想在排序算法上的典型应用。本质上来看,快速排序应该算是在冒泡排序基础上的递归分治法。

快速排序的名字起的是简单粗暴,因为一听到这个名字你就知道它存在的意义,就是快,而且效率高!它是处理大数据最快的排序算法之一了。

  1. 从数列中挑出一个元素,称为 "基准"(pivot);

  2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;

  3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序

在快速排序中,基准的选择一般是数据第一个元素,中间元素,最后一个元素,

在快速排序的我们需要抽象两个指针(或者数组下标),

一个是左指针,它是从左往右去找比基准大的数据

一个是右指针,它会从右往左去找比基准小的数据,

当左右指针都找到以后进行交换,然后一直重复,直到两指针相遇,再相遇点我们要比较,如果此数据比基准大,则交换,反之,左指针就往后移动一个位置

目的是:当前左指针所在的位置左边是都比基准小的数据,右边都是比基准大的数据

然后这个数据就是有序的了,我们需要对于有序的数据继续去划分左右半区,然后把左半区和右半区的最后一个数据作为两个半区的基准,分别计算,

这里就是分治的思想,只要一直分治下去,每一次分治都有一个数据被有序,而且随着分治的层数变多,所需要计算的次数越来越小

所以快速排序的时间复杂度是:O(nlogn) 最坏的情况就是 O(n^2)

快速排序的最坏运行情况是 O(n²),比如说顺序数列的快排。但它的平摊期望时间是 O(nlogn),且 O(nlogn) 记号中隐含的常数因子很小,比复杂度稳定等于 O(nlogn) 的归并排序要小很多。

所以,对绝大多数顺序性较弱的随机数列而言,快速排序总是优于归并排序。

下面我们来图解一下快速排序:

快速排序在选定了基准以后,就会使用左右指针去查找和基准对比的数据,当找到合乎要求 的数据以后就会交换,直到指针重合

当重合的时候要考虑一下是否需要和基准交换,只有比基准大的数据才能和基准交换否则就让左指针向后移动一次

每次被选为基准的数据在使用完了以后他自己其实就是有序的了然后在左右两边有数据的情况下是会继续划分的,这是分治法的思想做出来的算法

我们一定要注意:一定是左指针先移动,不然是拍不出来结果的

我们接下来使用伪代码实现一下(递归的方式):

我们可以看到代码其实和前面的归并排序都有异曲同工之妙,毕竟都是基于分治法的思想,

归并排序需要先拆分成最小元素后,然后在比较的时候,边比较,便合并

快速排序是在比较完了一次就拆分,再拆分前就已经有数据是有序的了,当拆分完成后,序列就是各个有序的了,所以没有合并的过程

在绝大多数情况下,快速排序都要优于归并排序

七.堆排序 

什么是堆排序?

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。

两种堆的结构:

  1. 大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列;
  2. 小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列;

堆排序的核心思想就是在大顶堆和小顶堆上建立起来的,因为大/小顶堆的性质:根节点比子节点大/小,所以在这两种顶堆中,最上面一层只有一个根节点的哪里,他一定是此序列中最大/小的

基于这个性质,我们只需要把一组数据先构造成为大/小顶堆,每次把最上面的元素和最后一个元素交换,再然后断开连接

这个数据就是有序的了即最大/小数,然后被换到根节点的数就开始维护,此时排序中最大的数又到了根节点,也就是整个序列的第二大数,然后重复操作

最后肯定是把序列从大到小或从小到大给排序出来的

堆排序的平均时间复杂度为 Ο(nlogn),它的排序过程很复杂,包括建堆,对维护,然后排序,它们相互依赖最后才做出最后的堆排序

首先我们来看看建堆的过程:

 在建堆的时候,一般是三个节点参与构建,父节点,左子节点,右子节点三个节点会有一个小型的维护过程,把最大的元素放到父节点,此时数据还刚开始

当下一次又会来新的数据,依旧构成三个节点构成,它们也会有一个维护阶段,把最大的元素放到父节点,

堆多了以后,他们的串联关系就会很明显了,然后可能建堆时只有三个,当维护时就会维护到下一层去了,到这里就表示它已经快要构成一个完全的数据堆了

当堆构建完成以后,我们就会开始进行排序:

 堆排序就是在大顶堆或小顶堆的基础上,不断的把最后一个元素和堆顶元素置换,每置换一次,就删除一次连接,然后从堆顶开始维护,直到又构成一个大顶堆

然后二次交换,重复操作,最后完成排序

我们来看看堆排序的伪代码:

 代码中可能有的疑问:

堆排序中我们构造的堆其实也是抽象的,并不是在内存中真的开辟了一个图形像堆一样,它是利用数组下标构造的一个联系,比如  下标为 0 的 ,它的子节点是 :下标为 1 和下标为2

我们图中所说的删除连接就是少一个数去维护,也就是循环的次数越来越少 : i --   就是在删除连接

堆排序是不稳定的,大家可以自己去推一下

八.计数排序

它只适合小范围的排序,空间开销大

什么是计数排序?

计数排序的核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。

计数排序思路很简单,但是它需要的时间开销很大

首先它需要一个数组去计数,还需要一个数据去计算累计值,还需要一个数组用于临时存储 原数组和累计数组的计算结果

原数组arr[ ];

计数数组 count [ ]:数据每出现一次 ,对应数据为下标的计数数组加一 ,计数数组是临时数组,需要申请,它的大小取决于原数组数据的最大值的加一 

累计数组 count 1 [ ]:计算原数据所在的位置,  它需要和计数数组结合,count 1  [ i] = count 1 [ i - 1] + count [ i ] 

排序数组output [ ] :  排序数组是最后的结果,需要拷贝回原数组,它是通过 原数组和累计数组计算的 output[ count 1 [ arr [ i ] ] -1 ]  = arr [ i ] 

下面我们使用图解一下计数排序:

 然后是伪代码实现:

 计数排序都是线性的,但是空间开销大,算法和名字一样,需要计算,其他的排序方法都是靠元素交换来排序的,计数排序是很特别的一种算法

但是它只适合小范围的计算,因为计算数组的申请需要根据元素的最大值,而不是元素个数,也就是我只有一个元素 ,它的值是100,那么我也得申请  100的空间大小

所以计数排序在运行时非常占空间,一下要申请两到三个,空间开销太大

计数排序的时间复杂度是:O(n) ,空间开销太大

九.桶排序

 什么是桶排序?

桶排序是另外一种以O(n)或者接近O(n)的复杂度排序的算法. 它假设输入的待排序元素是等可能的落在等间隔的值区间内.

一个长度为N的数组使用桶排序, 需要长度为N的辅助数组. 等间隔的区间称为桶, 每个桶内落在该区间的元素. 桶排序是基数排序的一种归纳结果。

桶排序与其它排序不同,它依靠的是下标代表元素,数组里的值只是确定整个序列有没有此元素,我们最开始会初始化我们的桶数组,都初始化为零

然后依次遍历原数据,把元素作为桶数组的下标,对应的数组值加一,代表此下标有值,这是一次对原数组的数据

当数据装完了以后我们再去遍历桶数组,当数组的值不为零的时候就打印下标,

所以桶排序是一种基于下标来作为元素的排序

我们来图解一下桶排序:

 桶排序也是一个线性的排序,时间复杂度一般为O(n),但是空间开销也很大,它申请请辅助数组时,并不是根据原数组的长度而判定的,

而是根据原数组的数据中的最大值来判定的的,也就是我只有两个元素分别是,100和1000的时候,在申请辅助数组的时候,我们要根据数组的中元素的最大值

也就是 1000 +1 来申请辅助数组,原数组大小才 2 ,申请的数组长度为 1001,这个空间开销浪费的资源太多了,

所以桶排序只适合小范围的计数,他和计数排序的适用区间差不多,比如:记录班级各个同学的成绩,然后排序,这种计算是很合适的,它不仅能排序还能计数,这种小范围的计数是可以使用桶排序的

此外,后来的人对桶排序又进行了优化,把桶不仅限于装一个元素了,而是装一个区间,这些使用都是基于桶排序的思想来的,目的是为了节约一下桶排序的空间开销

下面就是使用区间来描述桶的容量:

 在区间内,如果一个桶中有多个元素,那么就需要对单个桶进行插入排序,由于一般桶内的数据少,所以插入排序比较快

这种一个桶就代表一个区间的算法就不能光使用辅助数组了,还需要使用链表,把位于同一桶的元素串联起来

最坏的情况就是全部位于一个区间(桶)内,我们的堆排序就不在是线性的了

它的复杂度就是:O(N ^2)

接下来我们看看桶排序的一般代码描述:

 这是一个桶只装一个元素的代码描述,很显然可以看出来它是一个线性的算法

空间开销就很大了,在使用桶排序的时候一定注意它的使用区间,它只是用于小范围且连续的序列,而且序列中的最大元素尽量不断地靠近  0 ,开辟的空间越小越好

桶排序的时间复杂度: O(n)

十.基数排序

什么是基数排序?

基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。

由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。

基数排序也延续了桶排序的思想,与桶排序不同的是,基数排序是根据数据被拆分的结果来划分桶的位置

比如  :  我们对两位数要根据基数排序  33 和 69 

先让个位进入桶 :33 进入 3号桶,69进入9号桶

个位进桶了以后表示各位已经是在整个序列是有序的了,

然后十位进入桶:33 进入 3号桶,69进入6号桶

此时十位在整个序列是有序的了,只需要将桶内的元素按顺序拿出,然后往后一个个拿桶,最后就的到了最后的数据

基数排序比区间桶排序的优点在于,基数排序不管元素多少,它只需要10个桶,即0~9号桶,空间开销比桶排序小

但是思想上还是桶排序的思想

 我们来图解一下基数排序:

 我们看图,其实基数排序也是建立在桶排序的基础上的,为了节省空间开销我们还用了计数排序中的累计数组思想,

对比桶排序,很明显的就是在数据量变多的时候,桶排序所需的空间就会越来越大,反而基数排序就只需要十个桶,但它和基数排序一样要申请一个辅助数组,所以开销依旧很大

基数排序结合了桶排序和计数排序,所以在思想上三个都有很多相同之处

我们来看看基数排序的代码实现:

 在伪代码中我们可以看到max和base这两个变量:

max是数组中的最大数,它是几位数就决定了要进行几次基数排序

base:就是用来分拨每一位数的变量,它每 乘十就意味着向上一位整数

基数排序的时间复杂度是:O(n) 也是线性的,也是稳定的排序

十一.总结

十大排序的时间空间复杂度以及稳定性

 前面的七种排序都是非常经典的排序方法,它们时间复杂度比后面三种大,但是空间开销小

后面三种排序大多是线性的,理解起来也比较容易,时间复杂度最好的情况都是O(n),但是空间开销真的很大

所以后面三种算法重点还是在理解思想,怎么计算的就行,

当然我推荐必须掌握的就是:快速排序,归并排序,堆排序,这也是重点的算法。

 

本文转载于网络 如有侵权请联系删除

相关文章

  • Python数据分析-pandas库入门

    Contents1pandas库概述2安装pandas3pandas库使用4pandas数据结构介绍4.1Series数据结构4.2DataFrame数据结构4.3索引对象5pandas选择数据6总结7参考资料pandas库概述pandas提供了快速便捷处理结构化数据的大量数据结构和函数。自从2010年出现以来,它助使Python成为强大而高效的数据分析环境。pandas使用最多的数据结构对象是DataFrame,它是一个面向列(column-oriented)的二维表结构,另一个是Series,一个一维的标签化数组对象。pandas兼具NumPy高性能的数组计算功能以及电子表格和关系型数据库(如SQL)灵活的数据处理功能。它提供了复杂精细的索引功能,能更加便捷地完成重塑、切片和切块、聚合以及选取数据子集等操作。数据操作、准备、清洗是数据分析最重要的技能,pandas是首选python库之一。个人觉得,学习pandas还是最好在anaconda的jupyter环境下进行,方便断点调试分析,也方便一行行运行代码。安装pandasWindows/Linux系统环境下安装conda方式安装c

  • 一致 Hash 算法分析

    当我们在做数据库分库分表或者是分布式缓存时,不可避免的都会遇到一个问题:如何将数据均匀的分散到各个节点中,并且尽量的在加减节点时能使受影响的数据最少。Hash取模随机放置就不说了,会带来很多问题。通常最容易想到的方案就是hash取模了。可以将传入的Key按照index=hash(key)%N这样来计算出需要存放的节点。其中hash函数是一个将字符串转换为正整数的哈希映射方法,N就是节点的数量。这样可以满足数据的均匀分配,但是这个算法的容错性和扩展性都较差。比如增加或删除了一个节点时,所有的Key都需要重新计算,显然这样成本较高,为此需要一个算法满足分布均匀同时也要有良好的容错性和拓展性。一致Hash算法一致Hash算法是将所有的哈希值构成了一个环,其范围在0~2^32-1。如下图:之后将各个节点散列到这个环上,可以用节点的IP、hostname这样的唯一性字段作为Key进行hash(key),散列之后如下:之后需要将数据定位到对应的节点上,使用同样的hash函数将Key也映射到这个环上。这样按照顺时针方向就可以把k1定位到N1节点,k2定位到N3节点,k3定位到N2节点。容错性这时假设

  • 18个JS单行代码片段,值得你在日常工作中应用

    英文|https://javascript.plainenglish.io/18-killer-javascript-one-liners-%EF%B8%8F-b11f0c796024翻译|杨小二 1、复制到剪贴板使用navigator.clipboard.writeText轻松将任何文本复制到剪贴板。constcopyToClipboard=(text)=>navigator.clipboard.writeText(text); copyToClipboard("HelloWorld");复制2、检查日期是否有效 使用以下代码段检查给定日期是否有效。constisDateValid=(...val)=>!Number.isNaN(newDate(...val).valueOf()); isDateValid("December17,199503:24:00"); //Result:true复制3、找出一年中的哪一天 查找给定日期的哪一天。constdayOfYear=(date)=> Math.floor((date-newD

  • layui中laydate的使用——动态时间范围设置

    应用场景需求分析发起时间的默认最大可选值为当前日期发起时间从,的最大可选日期为,发起时间至选中的日期发起时间至,的最小可选日期为,发起时间从选中的日期单击重置时,发起时间从,发起时间至,的时间范围限制恢复为默认情况,即清空动态变化比如:当前时间为2018.08.31,发起时间从,发起时间至,默认最大可选日期为2018.08.31,如果发起时间从,选择了2018.08.29,那么发起时间至,可选范围变成29号到31号;如果发起时间至选择了27号,那发起时间从的可选最大值不再是31号,而是变成27号Html代码<formid="sch-form"class="layui-formlayui-form-pane"lay-filter="sch-form"onsubmit="returnfalse;"> <divclass="layui-inline"> <labelclass="layui-form-label">发起时间从</

  • 伯克利的Salto跳跃机器人,用那么小的脚也可以精准着陆了!

    大数据文摘出品来源:IEEESpectrum编译:木华加州大学伯克利分校有一款名叫Salto的跳跃机器人深受研究人员喜爱,因为它一年比一年变得更好!而且这些变化并不是渐进式的——这个小机器人的能力似乎已经突飞猛进。在“VirtualICRA2020”大会上发布的最新版本中,Salto的表现令人印象深刻,因为它已经学会了如何准确无误地在你指定的位置上停止跳跃。 正如我们所知,让Salto停止跳跃而不破坏自身的最佳方法是有人在它弹跳到空中时瞅准时机,将它直接捉住。Salto在跳跃方面的表现一直很惊艳,但它并不擅长着陆,不过现在,看这个!? 厉害吧!让人感觉惊讶的是这个令人难以置信的动力小机器人是用极小的脚着陆的。在视频中,你可以看到Salto在它的一维杆脚上着陆,但是根据ICRA论文,尽管它的推进器很难保持直立,但它也能够用点脚着陆。着陆过程的大部分工作是由机器人在半空中完成的,使用是与上次迭代相同的硬件,即一个旋转的惯性尾翼加上一对螺旋桨推进器,以实现多轴稳定性。 尽管着陆令人印象深刻,这也只是这次变化的一半。正如你在视频中看到的,另外一件变化是Salto可以更好地控制前进的方向,从而可

  • 5步骤完成springboot 整合freemarker模板引擎

    freemarker是个不错的模板引擎,在网页静态化的模板使用中口碑很好,今天就用springboot来整合这个模板。 1、首先就要在pom.xml里添加依赖,前提的springboot相关的依赖也都是必须的。2、第二部就是把freemarker的一些配置信息加到资源文件上,spring.freemarker.template-loader-path指的是freemarker文件的路径信息,spring.freemarker.cache这个表示的是缓存是否打开,其他几个都是常规配置,基本不需要修改的。最后一项spring.freemarker.suffix=.ftl指明了freemarker文件的后缀名为.ftl。3、在指定目录下创建模板文件,为了测试可用,添加了一个资源文件作为数据源。index.ftl即为创建的模板文件,对照资源文件来填写请求数据。资源文件随便写的,真用起来数据源多数还是要请求数据库。4、读取资源文件数据,然后创建Controller,并在Controller完成数据传递。读取资源文件信息用了@Component,@ConfigurationProperties,@

  • 深入理解Spark 2.1 Core (五):Standalone模式运行的原理与源码分析

    概述前几篇博文都在介绍Spark的调度,这篇博文我们从更加宏观的调度看Spark,讲讲Spark的部署模式。Spark部署模式分以下几种:local模式local-cluster模式Standalone模式YARN模式Mesos模式我们先来简单介绍下YARN模式,然后深入讲解Standalone模式。YARN模式介绍YARN介绍YARN是一个资源管理、任务调度的框架,主要包含三大模块:ResourceManager(RM)、NodeManager(NM)、ApplicationMaster(AM)。其中,ResourceManager负责所有资源的监控、分配和管理;ApplicationMaster负责每一个具体应用程序的调度和协调;NodeManager负责每一个节点的维护。对于所有的applications,RM拥有绝对的控制权和对资源的分配权。而每个AM则会和RM协商资源,同时和NodeManager通信来执行和监控task。几个模块之间的关系如图所示。YarnCluster模式Spark的YarnCluster模式流程如下:本地用YARNClient提交App到YarnReso

  • 领域驱动系列五模型驱动设计的构造块

    一、简介为了保证软件实现的简洁性,并且与模型保持一致,不管实际情况有多复杂,必须使用建模和设计的最佳实践,即让通过我们的编程技术(设计模型、指责驱动、契约式设计)充分地体现领域模型,并保持模型地健壮性和可扩展性,而不是单单地实现模型.某些决策设计能和模型紧紧地结合,这种结合要求我们注意每个元素地细节.开发一个好的领域模型是一门艺术,而模型中的各个元素的实际设计和实现则相对系统化,将领域设计(也可以是软件系统中的其他关注点)与软件系统中的其他关注点(也可以是领域设计)分离使整个领域模型非常的清晰.根据不同模型的指责(特性)会使元素的意义更加鲜明.二、实战 上图展示的模型驱动设计的基本构造块,当然实际开发中可能不止这些内容,可能还会有施加在实体上的一些契约还有一些特殊的计算规则、可能还有有一些复杂的实体运算,这些运算可能还需要使用一些设计模式去设计等等.但这个基本的构造.下面通过C#代码来实现一个简单的用户订单计价系统,如下:项目结构如下:代码如下:///<summary> ///用户聚合根 ///</summary> publicclassUserAggregat

  • css3之3D转换

    css3的3D转换,很有意思的一个特效 用到的属性transform:rotateX(-175deg);沿着x轴旋转transform:rotateY(-70deg);沿着y轴旋转transform:rotateZ(360deg);沿着z轴旋转perspective:1000px;规定眼睛距离元素的距离transform-style:preserve-3d;作用是让该元素中的所有转换元素显示成3D效果background-position;设置背景图像的起始位置实现的效果<!DOCTYPEhtml> <htmllang="en"> <head> <metacharset="UTF-8"> <title>Document</title> <linkrel="stylesheet"type="text/css"href="./css/font-awesome.min.css"> <style&g

  • 你的SEO博客有存在的必要吗?

    杨小杰看到很多SEO博客都已经停止更新了,大部分的原因是由于无新的原创内容可写或没有继续写下去的动力了。也还有很大一部分SEO博客在更新,但是更新的内容大部分是转载或是伪原创的。在这种情况下很多很久未更新的SEO博客也是依然挂在那里,确实想不出来把一个已经死掉的博客挂在那里的目的。我们是不是该问一下我们的SEO博客有存在的必要吗? 看完以下重点,再好好想想你的SEO博客有存在的必要吗? 1.博客的目的:很多SEO博主开博客是为了新鲜感和炫耀一番,当然也有很多博主确实是为了分享SEO经验和兼职接一点SEO的小单子,赚个零花钱。如果我们明确了我们博客存在的目的我们就不会纠结我们的博客该不该存在的问题了。 2.博客的内容:我们的博客内容来自哪里?是自己的SEO实战经验还是自己的SEO思维模式,如果没有好的SEO经验,我们完全可以利用一下我们自身的SEO思维模式来YY一下SEO的技巧和发展方向以及搜索引擎的调整趋势,做一个SEO空想家也是很不错的。如果偶尔一两次的灵魂碰撞让我们的SEO思维和搜索引擎的算法出现雷同的时候,我们也有做一次SEO预言家的机会哦。 3.执行力:经常可以在很久未更新的

  • 浪潮发布最新深度学习框架CAFFE-MPI

    德国当地时间6月20日,与英特尔宣布第二代至强Phi芯片“KnightsLanding”(以下称KNL)正式上市同步,浪潮在刚刚举行的第31届国际超算大会(ISC2016)上,全球首发基于最新KNL平台的深度学习计算框架Caffe-MPI,这标志着浪潮称为全球第一个在英特尔最新的KNL平台上完成Caffe并行开发的公司。  浪潮集团副总裁胡雷钧表示,此次KNL平台Caffe-MPI的发布,一方面显示出浪潮与英特尔紧密的合作关系,另一方面也将为全球深度学习用户带来新的协处理加速解决方案,让他们可以选择最贴合自身实际应用的异构加速技术。目前,浪潮推动的开源Caffe-MPI已受到中国、印度、美国等众多公司和研究机构的关注。  浪潮Caffe-MPI是全球首款高性能MPI集群版的Caffe深度学习计算框架,其采用成熟的MPI技术对Caffe予以数据并行的优化,其目标是解决深度学习计算模型训练的效率问题。Caffe是目前最快的深度卷积神经网络(DeepConvolutionalNeuralNetworks,CNN)架构,它最早由UC伯克利实验室完成单机单卡的开发,针对CNN训练所设计。然而随着

  • Svelte3-Admin基于svelte-ui管理后台系统

    前几天有给大家分享一个svelte-ui桌面pc组件库。今天再来分享一个基于svelteui开发的中后台管理前端解决方案。svelte-ui-admin一款基于最新前端技术栈svelte3.x+svelte-ui+vite3+echarts等技术构建的pc端后台管理系统。SvelteAdmin包含常用的表格/表单/图表/弹窗提示及权限控制/错误处理等功能。使用技术编码工具:Vscode框架技术:svelte3.x+svelteKit+vite3UI组件库:svelte-ui(基于svelte自定义pc端UI组件库)样式处理:sass^1.54.4图表组件:echarts^5.3.3编辑器组件:wangeditor^4.7.15国际化方案:svelte-i18n^3.4.0数据模拟:mockjs^1.1.0项目结构演示图项目整体风格和svelte-ui保持一致,界面比较清晰友好,操作流畅。页面布局分为顶部导航条+一二级路由菜单+右侧面包屑导航和主体内容。<divclass="svadmin__container"style="--themeSkin:{

  • Kubernetes部署官网Dashboard

    概述 KubernetesDashboard是用于Kubernetes集群的通用、基于Web的UI。它允许用户管理集群中运行的应用程序并对其进行故障排除,以及管理集群本身。 部署 获取DashboardYAML root@k8smaster-11:/data/k8s/soft#wgethttps://dl.k8s.io/v1.22.5/kubernetes.tar.gz root@k8smaster-11:/data/k8s/soft#tarxfkubernetes.tar.gz root@k8smaster-11:/data/k8s/soft#cdkubernetes/cluster/addons/dashboard/ #coredns部署模板文件 root@k8smaster-11:/data/k8s/soft/kubernetes/cluster/addons/dashboard#ls OWNERSREADME.mddashboard.yaml root@k8smaster-11:/data/k8s/soft/kubernetes/cluster/addons/dashboar

  • 数据中台(介绍篇)

    公司在弄数据中台,所以结合实际去理解了下数据中台,本文归属一寸HUI所有。@一寸HUI 数据中台是什么? 数据中台是一套可持续“让企业的数据用起来”的机制,是一种战略选择和组织形式,是依据企业特有的业务模式和组织架构,通过有形的产品和实施方法论支撑,构建的一套持续不断把数据变成资产并服务于业务的机制。数据中台是处于业务前台和技术后台的中间层,是对业务提供的数据能力的抽象和共享的过程,数据中台通过将企业的数据变成数据资产,并提供数据能力组件和运行机制,形成聚合数据接入、集成、清洗加工、建模处理、挖掘分析,并以共享服务的方式将数据提供给业务端使用,从而与业务产生联动,而后结合业务系统的数据生产能力,最终构建数据生产>消费>再生的闭环,通过这样持续使用数据、产生智能、反哺业务从而实现数据变现的系统和机制。 数据来自于业务,并反哺业务,不断循环迭代,实现数据可见、可用、可运营。通过数据中台把数据变为一种服务能力,既能提升管理、决策水平,又能直接支撑企业业务。数据中台不仅仅是技术,也不仅仅是产品,而是一套完整的让数据用起来的机制。既然是“机制”,就需要从企业战略、组织、人才等方面来

  • postman结合newman生成测试报告

    前置条件:已安装nodejs,安装详情可参考链接:https://www.cnblogs.com/zhen9436/p/16617383.html 1.cmd窗口安装newman npminstall-gnewman 复制 2.cmd窗口安装newman-html报告 nnpminstall-gnewman-reporter-html 复制 3.cmd窗口安装美化测试报告 npminstall-gnewman-reporter-htmlextra 复制 4.cmd窗口查看安装的插件 npmlist-g--depth0 复制 在postman中导出接口文件(步骤:1.新建文件夹,把接口全部导入此文件夹内-2.对文件夹的内容全部导出) 6.在本地选择某个目录建个文件夹,把postman内导出的json文件放入此文件夹下 7.cmd窗口进入上个步骤文件夹内,运行postman文件并生成测试报告 newmanruntest01.postman_collection.json-rhtmlextra--reporter-htmlextra-title"X项目自动化测

  • Xcode8 适配iOS10时遇见的一些问题

    1、证书管理 用Xcode8打开工程后,比较明显的就是下图了,这个是苹果的新特性,可以帮助我们自动管理证书。建议大家勾选这个Automaticallymanagesigning(Ps.但是在beat2版本我用的时候,完全不可以,GM版本竟然神奇的又好了。)   下面我来说说可能会出现的问题: 1.Xcode未设置开发者账号情况下的截图 解决办法是:大家在Xcode的偏好设置中,添加苹果账号,即可。 2.设备机器未添加进开发者的Device情况下的截图   解决办法是:大家在官网将设备添加进开发机后,陪下描述文件重新下个描述文件即可。 3.正常情况:Xcode配置登录开发者账号后的图片,耐心等待即可。   等待完成之后的图   2、Xib文件的注意事项 使用Xcode8打开xib文件后,会出现下图的提示。   大家选择ChooseDevice即可。之后大家会发现布局啊,frame乱了,只需要更新一下frame即可。如下图   注意:如果按上面的步骤操作后,在用Xcode7打开Xib会报一下

  • Mac生成APP图标和启动图的脚本

    概述 之前用的一个批量导出APP图标和启动图的软件,今天发现收费了,于是自己造了个简单的轮子。 实现 Mac上的sips命令,可以很方便的帮助用户修改图片尺寸 Xcode里面的APP启动图资源包含两部分 图片资源 描述文件 所以这个脚本的功能就是两个 生成描述文件Contents.json 修改图片尺寸并关联描述文件 生成描述文件 使用cat命令生成描述文件 setContents(){ cat<<EOF>./AppIcon/Contents.json { "images":[ { "size":"20x20", "idiom":"iphone", "scale":"2x", "filename":"icon_40x40.png" }, { "size":"20x20", "idiom":"iphone", "scale":"3x", "filename":"icon_60x60.png" }, ... EOF } 复制 修改图片尺寸 iconWithSize(){ sips-Z$1icon.png--out./AppIcon/icon_$1x$1.png }

  • 更改vCenter6.7的时区和时间

    1、使用SSH或者KVM登陆到主机系统界面,进入root账户 VMwarevCenterServerAppliance6.7.0.10000 Type:vCenterServerwithanembeddedPlatformServicesController Connectedtoservice *ListAPIs:"helpapilist" *ListPlugins:"helppilist" *LaunchBASH:"shell" Command>复制 2、载入BASH 输入shell Command>shell Shellaccessisgrantedtoroot root@photon-machine[~]# root@photon-machine[~]# root@photon-machine[~]# root@photon-machine[~]#date SatJul2516:15:41UTC2020复制 3、先修改时区 找到新时区文件所在位置,在/usr/share/zoneinfo/$主时区/$次时区目录下 #cd/usr/share/zone

  • oracle作业的创建

    1.创建一张记录表,记录作业执行的时间 createtableauto_open_paytype_date(datetimedate,typenumber); 2.创建存储过程 createorreplaceprocedureauto_open_paytype__job_procasBEGINupdatetablename_666setisopen=1whereid=666;--此处实现目的insertintoauto_open_paytype_datevalues(sysdate,'1');--此处记录执行时间END; 3.创建作业 declareauto_open_paytype_jobnumber;begindbms_job.submit(auto_open_paytype_job,'auto_open_paytype__job_proc;',to_date('2020-05-1713:00:00','yyyy-MM-ddHH24:mi:ss'),'sysdate+1');-- 起始时间'2020-05-1713:00:00  --之后每隔一整天执行

  • swith实现成绩显示

    importjava.util.Scanner;publicclassEext{ publicstaticvoidmain(String[]args){ //对学生成绩大于60分的,输出合格,低于60分的,输出不合格,输入成绩不能大于100提示成绩/60 //如果成绩在60~100之间,(int)(成绩/60)=1 //如果成绩在0~60之间,(int)(成绩/60)=0 Scannermyscanner=newScanner(System.in);//创建一个键盘扫描器 System.out.println("请输入成绩:");doublescore=myscanner.nextDouble(); if(score>=0&&score<=100){ switch((int)(score/60)){case0: System.out.println("不合格"); break; case1: System.out.println("合格"); break;//default: //System.out.println("怪!");}}else{ S

  • 第三章傅里叶变换

    ---恢复内容开始--- 为什么会引用傅里叶变换思想:引入了频域这一概念,将时域分析转变为频域分析,计算过程简单高效。   傅里叶级数   傅里叶级数展开,中心思想是任何信号都可以通过正弦和余弦正交得到,这里讨论的都是针对周期信号的函数,这里需要对欧拉公式的理解,但是书上没有讲这个,还有复变函数,高数中积分与极限思想 傅里叶变换   如果说傅里叶级数讨论的是周期信号的展开,但是自然界中许多信号都并不是周期的,所以也就升级了傅里叶级数,应用了积分极限思想 傅里叶变换12大性质   这些性质目的在于将时域和频域紧密的联系起来,互相转换,提供计算方法,给出时域,可以画出频域的图像,给出频域可以画出时域的图像。   最重要的几大性质莫过于对称性(时域频域转换),时域卷积(为频域俩函数相乘),频域卷积(为时域俩函数相乘),时域积分,,还有奇偶虚实性(主要讨论傅里叶变换前后函数的奇,偶,虚,实变化),还有一个是时移特性和频移特性 傅里叶级数的典型周期信号 然后介绍了阶跃信号与冲激信号的傅里叶变换以至于引出 傅里叶变换的典型周期信号 两大重要定理   卷积定理(讨论函数间的计算关系)   

相关推荐

推荐阅读