直接插入排序、折半插入排序、2路插入排序、希尔排序
本篇是排序专栏博客的第一篇,主要探讨以 “插入” 为核心思想的排序算法该如何实现
文章目录
- 一、前言
- 二、直接插入排序
- 1. 算法思想与操作分析
- 2. 代码实现
- version 1
- version 2
- 3. 复杂度分析
- 三、折半插入排序
- 1. 算法思想与操作分析
- 2. 代码实现
- 3. 复杂度分析
- 四、2路插入排序
- 1. 算法思想与操作分析
- 2. 代码实现
- 3. 复杂度分析
- 五、希尔排序
- 1. 算法思想与操作分析
- 2. 代码实现
- version 1
- version 2
- version 3
- 3. 复杂度分析
一、前言
所谓插入排序就是将数据整体的一部分独立看作有序,另一部分看作无序,然后将无序区间的数据一个一个地插入到有序区间中,并且在插入过程中始终保持有序区间有序的一种算法。
或许你会觉得很少见,但实际日常生活中,我们玩扑克牌游戏时就不自觉应用了这种思想。
既然插入排序要不断将数据插入有序区间中,那关键的地方就在于,如何在有序区间中找到一个合适的位置给新的数据。因此,根据查找插入位置的方法不同就衍生出了多种插入排序。
- 按顺序法查找插入位置的——直接插入排序。
- 按折半法(也叫二分法)查找插入位置的——折半插入排序。
- 通过缩小增量进行分组预排序的——希尔排序。
- 通过辅助空间减少挪动次数的——2路排序。
接下来就分别探讨这四个插入思想的排序算法如何实现。
二、直接插入排序
1. 算法思想与操作分析
思想:
假设我们现在要对 n 个数据排序:
- 将第
1
个数据作为有序区间,后面的n-1
个数据作为无序区间,然后将无序区间的首个数据插入到有序区间中,这个操作要进行n-1
次。 - 直接插入排序,又称顺序插入排序,因此,做法就是定义一个索引
end
指向有序区间的最后一个数据,每次插入操作都从后往前遍历有序区间,找到合适的插入位置。 - 重复步骤 2,直到无序序列数据个数为 0 。
图解分析基本操作:
有一组数据如下,我们现在需要将其从小到大排序。
- 首先将数据划分出有序区间和无序区间。
- 定义索引
end
指向有序区间的末个数据,用于遍历有序区间;
定义索引i
指向无序区间的首个数据,遍历无序区间进行每一趟的数据插入。
a[end]
>a[i]
,说明 1 应该插入到 9 的前面,但是 9 的前面已经不是数组的有效空间。
因此,9 要往后挪动一位,但是这样又会把a[i]
给覆盖了,所以挪动前需要定义一个临时变量temp
来保存a[i]
的内容。
然后--end
(看到这里你会惊讶的说,end 为什么要 -1,减完它就越界了啊,这样做是不是错了,别急,先记住这里,后面会一起解释)。
- 这样操作,待插入数据 1 就可以在 9 前面插入了,因为此时 end 的值为 -1,所以插入操作为
a[end + 1] = temp
。
- 此时有序区间数据个数增加1,无序区间个数减少1,索引变量
end
、i
也要随着更新,更新操作为i++
、end = i - 1
;
- 第二轮待插入数据为 2,然后我们再重复上面的步骤 2、3、4、5;
废话不多说,直接上图(为了节省画图压力个人这里就压缩成两张图了);
-
排序的步骤就演示到这里,接下来的操作无非就是重复步骤 2、3、5 的操作罢了,所以这里主要是总结一下排序过程的注意点。
从 3、6 这两点的图中我们可以总结出,找到插入位置的情况有两种:-
索引变量
end
遍历完有序区间,即end == -1
; -
索引变量
end
未遍历完有序区间,但它指向的值a[end] < temp
;
这两种情况下,插入位置都在
end
的下一个位置。 -
2. 代码实现
version 1
typedef int DataType;
void InsertSort1(DataType* a, int n)
{// 待插入数据,即区间[1, n-1]int i = 0;for (i = 1; i < n; i++){// 单趟插入(默认有序区间[0, n-2])int temp = a[i];int end = i - 1;// 找到合适位置的条件有2// 条件1:end == -1,退出循环while (end >= 0){if (a[end] > temp){a[end + 1] = a[end];--end;}else{// 条件2:a[end] <= temp// 按道理来说,这里应该进行插入操作的// 但是根据上面分析,条件1、2的插入操作都是一致,于是都放在循环外了break;}}a[end + 1] = temp;}
}
version 2
也许你会感觉,虽然上面的方法已经能够完成算法了,但是,索引变量end
在遍历过程中毕竟越界了,有种不安全的感觉,这里提供了第二种实现思路。
typedef int DataType;
void InsertSort2(DataType* a, int n)
{// while --> for,结构紧凑,不会越界int i = 0;for (int i = 1; i < n; i++){int temp = a[i];int pos = 0;// 这里就很明显地看到找到合适位置有两个条件了for (pos = i; pos > 0 && a[pos - 1] > temp; pos--){a[pos] = a[pos - 1];}// 当退出循环后,pos指向的位置就是插入位置a[pos] = temp;}
}
3. 复杂度分析
时间复杂度
直接插入排序是一种受序列初始排布状态影响的排序算法。
我们来对比以下两组数据排升序的性能差别:
- 第一组数据
{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}
- 第一组数据
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
从上面两组数据中,我们不难看出,如果数据越接近于有序那么直接插入排序的效率越高,反之,效率越差,时间复杂度越高。
虽然我们希望每次排序时都出现最好情况,但是很遗憾,时间复杂度是一个悲观预期,它以最坏情况为标准。
因此,结论是:直接插入排序的时间复杂度是O(N^2)。
空间复杂度
空间复杂度取决算法实现过程中额外空间消耗的大小,像
temp
、end
、i
、pos
这样的,常数个变量的开销的空间复杂度是O(1)。
三、折半插入排序
1. 算法思想与操作分析
思想:
同样,我们现在仍要对 n 个数据排序:
- 将第
1
个数据作为有序区间,后面的n-1
个数据作为无序区间,然后将无序区间的首个数据插入到有序区间中,这个操作要进行n-1
次,直到无序区间数据个位数为 0。 - 相比较于边比较边挪动数据的直接插入排序,折半插入排序先用二分法找到插入位置,然后再挪动数据
- 最后将数据插入到合适的位置。
图解分析基本操作:
- 首先将数据划分出有序区间和无序区间。
(为了方便,折半插入排序仍旧采用与前面相同的一组数据)
- 定义用于二分查找插入位置的 3 个索引变量
left
、mid
、right
;
定义用于遍历控制无序区间数据插入的循环迭代变量i
。
设计好变量后,接下来进行第一趟的插入,先说明一下变量的初始化:
首先是循环迭代变量i
,它承担的任务和前面相同,从下标为 1 开始遍历完无序区间;
其次是折半查找的三个变量:
- left指向有序区间的最左端,即初始化为
left = 0
;- right指向有序区间最右端,即初始化为
right = i - 1
;- mid指向当前区间的中间数据,即初始化为
mid = (left + right) / 2
;
- 折半插入排序仅仅只是改变了插入位置的查找方式,数据挪动过程中仍会对待插入数据(
a[i]
)进行覆盖,因此挪动前要将a[i]
用临时变量temp
保存;
然后,此时的a[mid]
>temp
,说明插入位置在a[mid]
的左边,然后更新查找的边界,操作为right = mid - 1
;
更新完边界之后,我们 需要判断一下是否满足条件left <= right
,如果满足,说明明仍要继续查找,当right < left
时,left
指向的位置就是插入位置,从left
开始到有序区间的最右端的数据都要向后挪动一位(temp
的作用就在这里体现了);
- 第一轮插入完毕,接下来进行第二轮插入
首先要对变量left
、mid
、right
、i
分别进行更新
++i
,使变量i
重新指向无序区间的首个数据;
left = 0
,使变量left
重新指向有序区间左边界;
right = i - 1
,使变量right
重新指向有序区间的右边界;
mid = (left + right) / 2
,使变量mid
重新指向当前查找区间的中间值;
- ①临时变量
temp
保存a[i]
;
②比较得a[mid] < temp
,说明插入位置在右半区间 [mid+1, right],更新查找区间的左边界,即left = mid + 1
,此时left < right
,查找继续;
③边界发生变化,更新mid = (left + right) / 2
;
④比较得temp < a[mid]
,说明插入位置在左半区间 [left, mid-1],更新查找区间的右边界边界,即right = mid - 1
,此时left > right
,查找停止;
⑤此时left
指向的位置就是查找位置;
- ①有序区间内从
left
开始的数据都向后挪动一位;
②将temp
插入到left
指向的位置;
- 剩余数据的插入与上面的大同小异,唯一的不同点就是随着有序区间数据的增多,区间更新的次数也随之增加而已,这里就不再过多演示
2. 代码实现
typedef int DataType;
void BinaryInsertSort(DataType* a, int n)
{int i = 0;for (i = 1; i < n; i++) // 无序区间[1, n-1],n-1 次插入操作 {int temp = a[i]; // 临时变量保存a[i]int left = 0;int right = i - 1;// 二分查找插入位置while (left <= right){int mid = (left + right) / 2;if (a[mid] <= temp) // 插入位置在右半区间{left = mid + 1; // 左边界更新}else // 插入位置在左半区间{right = mid - 1;// 右边界更新}}//数据挪动int j = 0;for (j = i; j > left; j--){a[j] = a[j - 1];}// 数据插入a[left] = temp;}
}
3. 复杂度分析
时间复杂度
折半插入排序不同于直接插入排序的边比较边挪数据,该算法将比较和挪动的捆绑关系解放,通过减少比较次数来进行一个小幅度的优化,但是数据挪动的次数相较于直接插入排序是没有优化的。
在最坏情况下,比如{10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }
等
插入第1个数据,挪动1次;
插入第2个数据,挪动2次;
……
插入第10个数据,挪动10次;
……以此类推:
插入第n-1个数据,挪动n-1次;
在最坏情况下,虽然比较次数有所减少,但数据挪动次数却没有减少。
因此,结论是:折半插入排序的时间复杂度是O(N^2)。
空间复杂度
空间复杂度取决算法实现过程中额外空间消耗的大小,像
temp
、end
、i
、pos
这样的,常数个变量的开销的空间复杂度是O(1)。
四、2路插入排序
前面提到过,折半插入排序是在直接插入排序的基础上,实现了比较次数和数据挪动之间的关系解绑,而在接下来要探讨的2路插入排序则是在直接插入排序上尽可能减少数据的挪动。
1. 算法思想与操作分析
思想:
2路插入排序是一种典型的通过牺牲空间换取时间的算法,先开辟与原数据等长的数据空间,然后遍历原数据,在辅助空间中排好序然后拷贝回源数据空间。
图解思想和基本操作:
- 第一步:
①开辟等长的辅助排序空间,初始化为0,将源数组第一个数据拷贝过去;
②定义索引变量head
,tail
,指向assist
数组的第一个值;
③定义循环变量i
,用于遍历源数组进行数据插入。
- 第二步:
现在数据分成三种情况
①a[i] < assist[head]
,a[i]
插入到head
的前一个位置,更新head
;
②assist[tail] <= a[i]
,a[i]
插入到tail
的后一个位置,更新tail
;
③其余情况统一按直接插入排序处理;
接下来插入第一个数据:
a[i]
(== 6) < assist[head]
,属于第一种情况,head向前挪动一个位置,操作为head = (head - 1 + n) % n
这个就是这个算法的最核心之处了,如果你学过循环队列,那这个会很好理解,如果没有了解过这方面的知识,你可以把数组想象成一个首尾相接的圆
接下来插入第二个数据:
assist[head]
< a[i]
(== 7) < assist[tail]
,属于第三种情况将a[i]
插入有序区间 [head, tail]。
规定操作如下:
先让tail
向后移动一个位置,再定义变量end
控制数据挪动;
只有遇到 (end
的前一个数据) < a[i]
才停止挪动数据;
当 end 停止移动时,end指向的位置就是插入位置;
一般来说,tail 向后移动不会出现越界的情况,但为了代码的一致,统一对索引变量的移动进行取余操作;
当索引变量向后移动时,不再是++,而是变量 = (变量 + 1) % n
当索引变量向前移动时,不再是–,而是变量 = (变量 - 1 + n) % n
tail = (tail + 1) % n
,向后移动一位。
定义变量end = tail
,将end
的前一个数据向后挪动一位,再更新end
,即
assist[end] = assist[(end - 1 + n) % n]
end = (end - 1 + n) % n
。
当end = 0 时,end 的前一个位置的值为6 < a[i] (== 7),停止挪动、插入数据。
接下来插入第三个数据:
此时assist[tail]
<= a[i]
(== 7) ,属于第一种情况将a[i]
插入tail
的后一个位置。
操作为:
tail = (tail + 1) % n
assist[tail] = a[i];
三次插入操作分别讲述了算法操作过程中会遇到三种情况,图解分析就到此为止,就下来就是代码实现。
2. 代码实现
typedef int Datatype;
void TwoWayInsert(DataType* a, int n)
{// 辅助空间int* assist = (int*)calloc(n, sizeof(DataType));if (assist == NULL){printf("calloc failed\n");exit(-1);}assist[0] = a[0];// 索引变量,控制插入int head = 0, tail = 0;int i = 0;for (i = 1; i < n; i++){// < assist[head] 放头前if (assist[head] > a[i]){assist[head = (head - 1 + n) % n] = a[i];}// >= assist[tail] 放尾后else if (assist[tail] <= a[i]){assist[tail = (tail + 1) % n] = a[i];}// 其余统一按直接插入排序处理else{int end = ++tail;while (1){assist[end] = assist[(end - 1 + n) % n];end = (end - 1 + n) % n;// end前一个位置比a[i]小就退出if (assist[(end - 1 + n) % n] <= a[i]){break;}}assist[end] = a[i];}}for (i = 0; i < n; i++){a[i] = assist[head];head = (head + 1) % n;}free(assist);
}
3. 复杂度分析
时间复杂度
取决于移动元素和比较元素。
最坏情况:
放第一个元素,移动0,比较0,
放第二个元素,移动0,比较1,
放第三个元素,挪动1,比较2,
放第四个元素,挪动2,比较3,
放第五个元素,挪动3,比较4
…
放第n个元素,挪动(n-2),比较(n-1)
比较次数之和大于挪动次数之和,以比较为标准,则排序部分的时间复杂度为O(N^2)。
最后还要将辅助空间数据拷贝回源数据,该操作复杂度为O(N)。
因此,结论为2路插入排序的时间复杂度为O(N^2)。
空间复杂度
算法在执行过程中,额外的空间开销取决于源数据个数,总的空间开销为 未知数N + 常数个变量。
因此,结论为2路插入排序的时间复杂度为O(N)。
五、希尔排序
前面提到过,“对于直接插入排序,如果数据越接近于有序,那么它的排序效率越高”,但是,现实中的数据不总是接近于有序。
那么如何使数据更加接近于有序呢?
1959年,有一个名叫 DL.Shell 提出了一种解决方法,对直接插入排序进行了大幅度的性能优化,最后,这个方法被以它的提出者来命名,叫做 “希尔排序”,这就是希尔排序的由来。
1. 算法思想与操作分析
思想:
希尔排序,又叫做 “缩小增量排序”,“分组插入排序”。
它的基本思想如下:
- 将整个待排序数据序列以某个间隔(假设为gap)作为一组,划分成不同的子区间,分别进行直接插入排序;
- 不断缩小gap、重新划分子区间、分别进行直接插入排序;
- 直到整体数据接近于有序,再对全体元素进行一次直接插入排序。
图解分析基本操作:
以下为对一组简单的数据进行希尔排序的过程:
图中很清晰的展示了希尔排序是如何进行的:
- 定义一个增量
gap
,设置初始值为n/2
,将数据分为gap
组,分别对gap
组数据进行直接插入排序;gap /= 2
,缩小增量,再对新划分的gap
组数据进行直接插入排序;- 重复步骤 2,如果
gap > 1
,进行的是预排序,目的是将较大的数据放到后面,较小的数据挪到前面,使数据更接近于有序;如果gap = 1
,此时数据已经基本接近于有序,对数据整体进行一次直接插入排序,使数据完全有序。
2. 代码实现
version 1
根据上面基本操作分析,我们来将代码进行实现,实现过程中,个人建议从小到大写,即先写好对小组的直接插入排序,再用外循环控制增量gap
的缩小。
对分组进行直接插入排序时要注意gap
。
typedef int DataType;
void ShellSort(DataType* a, int left, int right)
{int gap = right;while (gap > 1){// 当 gap > 1 时进行的就是预排序// 当 gap = 1 时进行的就是直接插入排序gap /= 2;int i = 0;// 对分别划分出的gap组数据进行直接插入排序for (i = 0; i < gap; i++){int end = i;// 每组数据中,定义变量end来遍历有序区间,进行数据挪动// 注意间隔为gap,不再是1for (end = i; end < right - gap; end += gap){// 临时变量temp保存无序区间的第一个值int temp = a[end + gap];while (end >= 0){if (a[end] > temp){a[end + gap] = a[end];}else{break;}end -= gap;}a[end + gap] = temp;}}}
}
这样,代码就成功实现出来了,但是,这样的代码就是最优的吗?
我们接着往下看。
version 2
有人经过观察发现,下面两个循环在写法上可以进行合二为一。
何出此言?
typedef int DataType;
void ShellSort(DataType* a, int left, int right)
{int gap = right;while (gap > 1){// 当 gap > 1 时进行的就是预排序// 当 gap = 1 时进行的就是直接插入排序gap /= 2;int end = 0;// 对gap组进行多组并排for (end = 0; end < right - gap; end++){// 临时变量temp保存无序区间第一个值int temp = a[end + gap];while (end >= 0){if (a[end] > temp){a[end + gap] = a[end];}else{break;}end -= gap;}a[end + gap] = temp;}}
}
该写法相较于第一种写法,通过调整代码运行的逻辑结构,对代码进行简化,代码的易理解程度,个人认为相较于第一种有所下降。但这种方法进行调整的逻辑思维巧妙性,个人认为还是值得学习的。
version 3
探讨直接插入排序时,我们不是实现了两种方法吗,那版本二的代码能不能套进希尔排序呢——答案是可以的。
改动如下:
void ShellSort3(DataType a[], int left, int right)
{int gap = right;while (gap > 1){// 当 gap > 1 时进行的就是预排序// 当 gap = 1 时进行的就是直接插入排序gap /= 2;int tmp = 0;// 对gap组进行多组并排,i指向无序区间的第一个值for (int i = gap; i < right; i++){tmp = a[i];int pos = 0;// 上面的end是指向tmp的前一个位置,这里的pos直接指向tmp所在位置,// 当循环结束之后pos就是数据该插入的位置for (pos = i; pos >= gap && a[pos - gap] > tmp; pos -= gap){a[pos] = a[pos - gap];}a[pos] = tmp;}}
}
3. 复杂度分析
时间复杂度
希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些书中给出的希尔排序的时间复杂度都不固定:
比如:《数据结构(C语言版)》—严蔚敏
比如:《数据结构-用面相对象方法与C++描述》—殷人昆
个人这里gap的取值用的就是 shell 提出的gap = gap / 2,时间复杂度大概在O(N^1.5)。
空间复杂度
希尔排序过程中并未产生额外的线性空间开销,因此,它的空间复杂度为O(1)。
相关文章:
直接插入排序、折半插入排序、2路插入排序、希尔排序
本篇是排序专栏博客的第一篇,主要探讨以 “插入” 为核心思想的排序算法该如何实现 文章目录 一、前言二、直接插入排序1. 算法思想与操作分析2. 代码实现version 1version 2 3. 复杂度分析 三、折半插入排序1. 算法思想与操作分析2. 代码实现3. 复杂度分析 四、2路…...
HTML-列表标签
列表是一系列排列好的项目,主要分成两类:有序列表和无序列表。 有序列表是每个列表项前面有编号,呈现出顺序,就像下面这样。 1. 列表项 A 2. 列表项 B 3. 列表项 C无序列表则是列表项前面没有编号,只有一个列表符号&…...
计算机网络原理(一)
嘿! 新年的第一篇博客,大家新年快乐呀!希望大家新的一年要多多进步噢! 1.TCP/IP的四层/五层参考模型有哪些层,各层的特点是?计算机网络分层的好处是? TCP/IP 四层参考模型 应用层:直接为用户…...
扩散模型论文概述(二):Google系列工作【学习笔记】
视频链接:扩散模型论文概述(二):Google系列工作_哔哩哔哩_bilibili 本视频讲的是Google在图像生成的工作。 同样,第一张图片是神作,总结的太好了! 在生成式AI的时代,OpenAI和Google不…...
第四届计算机、人工智能与控制工程
第四届计算机、人工智能与控制工程 The 4th International Conference on Computer, Artificial Intelligence and Control Engineering 重要信息 大会官网:www.ic-caice.net 大会时间:2025年1月10-12日 大会地点:中国合肥 (安徽大学磬苑…...
UE4.27 Android环境下获取手机电量
获取电量方法 使用的方法时FAndroidMisc::GetBatteryLevel(); 出现的问题 但是在电脑上编译时发现,会发现编译无法通过。 因为安卓环境下编译时,包含 #include "Android/AndroidPlatformMisc.h" 头文件是可以正常链接的,但在电…...
【人工智能】基于Python与OpenCV构建简单车道检测算法:自动驾驶技术的入门与实践
《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 随着自动驾驶技术的快速发展,车道检测作为自动驾驶系统中的一个重要组成部分,起着至关重要的作用。本文将介绍如何利用Python与OpenCV库构…...
永磁同步电机控制算法--最大转矩电流比控制(牛顿迭代法)
一、原理介绍 搭建了基于牛顿迭代法的MTPA双闭环矢量控制系统 二、仿真验证 在MATLAB/simulink里面验证所提算法,采用和实验中一致的控制周期1e-4,电机部分计算周期为1e-6。仿真模型如下所示: 对直接公式计算法和牛顿迭代法进行仿真对比验…...
基于51单片机(STC32G12K128)和8X8彩色点阵屏(WS2812B驱动)的小游戏《贪吃蛇》
目录 系列文章目录前言一、效果展示二、原理分析三、各模块代码1、定时器02、矩阵按键模块3、8X8彩色点阵屏 四、主函数总结 系列文章目录 前言 《贪吃蛇》,一款经典的、怀旧的小游戏,单片机入门必写程序。 以《贪吃蛇》为载体,熟悉各种屏幕…...
Ceph 手动部署(CentOS9)
#Ceph手动部署、CentOS9、squid版本、数字版本19.2.0 #部署服务:块、对象、文件 一、部署前规划 1、兼容性确认 2、资源规划 节点类型节点名称操作系统CPU/内存硬盘网络组件安装集群节点CephAdm01CentOS94U/8GOS:40G,OSD:2*100GIP1:192.169.0.9(管理&集群),IP2:…...
Reactor测试框架之StepVerifier
Reactor测试框架之StepVerifier 测试步骤1、创建StepVerifier实例2、添加断言3、执行验证 代码实例 在响应式编程中,Reactor框架提供了StepVerifier测试类,用于对响应式序列进行断言和验证。StepVerifier主要用于对Publisher发出的元素序列进行逐步的、精…...
unity 播放 序列帧图片 动画
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、方法一:代码控制播放序列帧1、设置图片属性2、创建Image组件3、简单的代码控制4、挂载代码并赋值 二、方法二:直接使用1.Image上添加…...
1-markdown转网页样式页面 --[制作网页模板] 【测试代码下载】
markdown转网页 将Markdown转换为带有样式的网页页面通常涉及以下几个步骤:首先,需要使用Markdown解析器将Markdown文本转换为HTML;其次,应用CSS样式来美化HTML内容。此外,还可以加入JavaScript以增加交互性。下面我将…...
ubuntu 创建服务、查看服务日志
1. 在 /etc/systemd/system/ 下创建文件,名称为 xxx.service [Unit] DescriptionYour Service Description Afternetwork.target[Service] Typesimple ExecStart/path/to/your/service/executable Restarton-failure[Install] WantedBymulti-user.target2. 配置服务…...
[python3]Excel解析库-openpyxl
https://openpyxl.readthedocs.io/en/stable/ openpyxl 是一个用于读写 Excel 2010 xlsx/xlsm/xltx/xltm 文件的 Python 库。它允许开发者创建、修改和保存电子表格,而无需依赖 Microsoft Excel 软件本身。openpyxl 支持读取和写入 Excel 的工作簿(Work…...
使用 LlamaIndex 构建智能文档查询系统
使用 LlamaIndex 构建智能文档查询系统 1. 环境准备2. 初始化模型3. 加载文档4. 构建索引和查询引擎5. 生成扩展查询6. 主函数7. 总结 在现代信息检索系统中,如何高效地从大量文档中提取出有用的信息是一个重要的挑战。本文将介绍如何使用 LlamaIndex 构建一个智能文…...
C++——继承
目录 前言 1. 继承的概念和定义 1.1 继承的概念 1.2 继承的定义 1.2.1 定义格式 1.2.2 继承基类成员访问方式的变化 1.3 继承类模板 2. 基类和派生类之间的转换 3. 继承中的作用域 3.1 隐藏规则 3.2 考察继承作用域相关选择题 4. 派生类的默认成员函数 4.1 4个常…...
01:C语言的本质
C语言的本质 1、ARM架构与汇编2、局部变量初始化与空间分配2.1、局部变量的初始化2.1、局部变量数组初始化 3、全局变量/静态变量初始化化与空间分配4、堆空间5、函数 1、ARM架构与汇编 ARM简要架构如下:CPU,ARM(能读能写),Flash(…...
Jmeter进阶篇(32)Jmeter 在 MySQL 数据库压测中的应用
一、引言 在当今数字化时代,数据库性能的优化对于企业的发展至关重要。随着业务量的不断增长,数据库需要承受越来越大的压力。MySQL作为一种广泛使用的开源数据库,其性能和稳定性备受关注。为了确保数据库在高负载情况下能够正常运行,进行压测是必不可少的环节。Jmeter作为…...
TCPDump参数详解及示例
TCPDump参数详解及示例 TCPDump参数详解TCPDump -G的示例TCPDump -i any -s 2048 -G 600 -p udp -Z root -n -X -tt -w %Y_%m%d_%H%M_%S.pcap &的含义TCPDump是一款强大的网络数据包截获分析工具,可以将网络中传送的数据包的完全截获下来提供分析。它支持针对网络层、协议…...
Protocol Buffer
1、什么是 Protocol Buffers? Protocol Buffers (protobuf) 是一种序列化结构化数据的方法,由 Google 开发。它们提供了一种与语言无关、与平台无关且可扩展的机制,用于高效序列化结构化数据。 Protocol Buffers 中的…...
高等数学学习笔记 ☞ 连续与间断
1. 连续 1. 点连续定义: 设函数在点的某邻域内有定义,取附近的点,对应的函数值分别和, 令,当时,若,则称函数在点处连续。 记作。 此式为增量形式。 又知,则可改写为:。 …...
【three.js】Shader着色器
原始着色器材质RawShaderMaterial 两种着色器材质的 RawShaderMaterial 和 ShaderMaterial 的区别和用法 区别: ShaderMaterial 会自动将一些初始化着色器的参数添加到代码中(内置 attributes 和 uniforms) RawShaderMaterial 则什么都不会添…...
在 macOS 中,设置自动将文件夹排在最前
文章目录 1、第一步访达设置2、第二步排序方式 需要两步设置 1、第一步访达设置 按名称排序的窗口中 2、第二步排序方式 选择名称...
创建并配置华为云虚拟私有云
目录 私有云 创建虚拟私有云 私有云 私有云是一种云计算模式,它将云服务部署在企业或组织内部的私有基础设施上,仅供该企业或组织内部使用,不对外提供服务.私有云的主要特点包括: 私密性:私有云的资源(如…...
Spark是什么?Flink和Spark区别
Spark是什么?Flink和Spark区别 一、Spark二、Spark和Flink区别三、总结 一、Spark Apache Spark 是一个开源的大数据处理框架,主要用于大规模数据处理和分析。它支持多种数据处理模式,包括批处理、流处理、SQL 查询、机器学习和图处理等。 核…...
代码随想录 day 25
第七章 回溯算法 part04 491.递增子序列 本题和大家刚做过的 90.子集II 非常像,但又很不一样,很容易掉坑里。 https://programmercarl.com/0491.%E9%80%92%E5%A2%9E%E5%AD%90%E5%BA%8F%E5%88%97.html 视频讲解:https://www.bilibili.com/…...
数据仓库中的指标体系模型介绍
数据仓库中的指标体系介绍 文章目录 数据仓库中的指标体系介绍前言什么是指标体系指标体系设计有哪些模型?1. 指标分层模型2. 维度模型3. 指标树模型4. KPI(关键绩效指标)模型5. 主题域模型6.平衡计分卡(BSC)模型7.数据指标框架模…...
xr-frame 通过shader去除视频背景色,加载透明视频
目录 前言 实现思路 获取 XR 框架系统: 注册自定义效果 创建效果对象 渲染通道配置 着色器代码 顶点着色器 片元着色器(颜色分量g达到条件的片元将被透透明) effect-removeBlack 完整代码 wxml中使用 前言 实现了一个用于注册自定…...
论文解读 | NeurIPS'24 IRCAN:通过识别和重新加权上下文感知神经元来减轻大语言模型生成中的知识冲突...
点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入! 点击 阅读原文 观看作者讲解回放! 作者简介 史丹,天津大学博士生 内容简介 大语言模型(LLM)经过海量数据训练后编码了丰富的世界知识。最近的研究表明,…...
Kraft模式安装Kafka(含常规、容器两种安装方式)
一、#创作灵感# 公司使用Kafka的软件项目较多,故写技术笔记巩固知识要点 二、软件环境 - Kafka 3.9.0 官方下载地址:Kafka 3.9.0 - Docker Desktop 4.37 容器图形化工具 官方下载地址:Docker Desktop 4.37 特别说明 - Docker Desktop…...
旷视科技C++面试题及参考答案
在 Linux 系统下常用的命令有哪些? 在 Linux 系统中有许多常用命令。首先是文件和目录操作相关的命令。“ls” 命令用于列出目录的内容,它有很多选项,比如 “ls -l” 可以以长格式显示文件和目录的详细信息,包括文件权限、所有者、大小、修改时间等;“ls -a” 则会显示所有…...
IWOA-GRU和GRU时间序列预测(改进的鲸鱼算法优化门控循环单元)
时序预测 | MATLAB实现IWOA-GRU和GRU时间序列预测(改进的鲸鱼算法优化门控循环单元) 目录 时序预测 | MATLAB实现IWOA-GRU和GRU时间序列预测(改进的鲸鱼算法优化门控循环单元)预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 MATLAB实现IWOA-GRU和GRU时间序列预测…...
edeg插件/扩展推荐:助力生活工作
WeTab 此插件在我看来有2个作用 1.改变edeg的主页布局和样式,使其更加精简,无广告 2.提供付费webtab Ai(底层是chatGpt) 沉浸式翻译 此插件可翻译网页的内容 假设我们浏览github 翻译前 翻译后 Better Ruler 可以对网页的距离进行测量 适合写前端的小伙伴 用法示例:...
TPS和QPS的区别
TPS全称(Transactions Per Second)QPS全称(Queries Per Second)它们都是衡量系统性能的指标,都是表示单位时间内处理的事务或者查询的数量 TPS 定义:TPS指的是系统每秒可以处理的事务数量,一个…...
鸿蒙HarmonyOS开发:拨打电话、短信服务、网络搜索、蜂窝数据、SIM卡管理、observer订阅管理
文章目录 一、call模块(拨打电话)1、使用makeCall拨打电话2、获取当前通话状态3、判断是否存在通话4、检查当前设备是否具备语音通话能力 二、sms模块(短信服务)1、创建短信2、发送短信 三、radio模块(网络搜索&#x…...
如何处理 JavaScript 中的函数防抖问题?
在 JavaScript 中,函数防抖(Debouncing)是一种控制函数执行频率的技术,通常用于处理用户输入事件(例如键盘输入、滚动事件等)。防抖的核心思想是:在连续触发某个事件时,只有在事件停…...
sql server期末复习
表操作 创建create 删除drop 修改alter 数据操作 查询 select from <tableName> 插入 insert into <tableName> values 修改 update <tableName> set 删除 delete from <tableName> 授权与收回对数据的操作权限 授予 grant <权…...
初学STM32 --- 外部SRAM
目录 SRAM简介 SRAM特性: XM8A51216 功能框图 8080并口读时序编辑 8080并口写时序 SRAM 读写操作步骤 FSMC介绍 FSMC时序介绍 FSMC控制器对内核地址映射编辑 FSMC HAL库相关驱动 SRAM驱动步骤 SRAM简介 静态随机存取存储器(Static Random-Access Memory&am…...
XXX公司面试真题
一、一面问题 1.线程池的主要参数 核心线程数最大线程数空闲线程存活时间存活时间单位任务队列线程工厂拒绝策略允许核心线程超时 2. 线程的状态 新建状态就绪状态运行状态阻塞状态死亡状态 补充:线程阻塞的原因 线程调用sleep()方法进入睡眠状态 线程得到一个…...
MySQL 01 02 章——数据库概述与MySQL安装篇
一、数据库概述 (1)为什么要使用数据库 数据库可以实现持久化,什么是持久化:数据持久化意味着将内存中的数据保存到硬盘上加以“固化”持久化的主要作用是:将内存中的数据存储在关系型数据库中,当然也可以…...
[读书日志]8051软核处理器设计实战(基于FPGA)第四篇:verilog语法特性
第一篇https://blog.csdn.net/m0_74021449/article/details/144796689 第二篇https://blog.csdn.net/m0_74021449/article/details/144813103 第三篇https://blog.csdn.net/m0_74021449/article/details/144834117 4.verilog硬件描述语言基础 这部分主要讲述verilog基础语法…...
大模型高效推理综述
大模型高效推理综述 1 Introduction2 Preliminaries2.1 transformer架构的LLM2.2 大模型推理过程2.3 推理效率分析 3 TAXONOMY(分类)4.数据级别优化4.1输入压缩4.1.1 提示词裁剪(prompt pruning)4.1.2 提示词总结(prompt summary)…...
HTML5实现好看的博客网站、通用大作业网页模板源码
HTML5实现好看的博客网站、通用大作业网页模板源码 前言一、设计来源1.1 主界面1.2 列表界面1.3 文章界面 二、效果和源码2.1 动态效果2.2 源代码 源码下载结束语 HTML5实现好看的博客网站、通用大作业网页模板源码,博客网站源码,HTML模板源码࿰…...
在Microsoft Windows上安装MySQL
MySQL仅适用于Microsoft Windows 64位操作系统,在Microsoft Windows上安装MySQL有不同的方法:MSI、包含您解压缩的所有必要文件的标准二进制版本(打包为压缩文件)以及自己编译MySQL源文件。 注意:MySQL8.4服务器需要在…...
adaface人脸特征提取之ncnn推理
目录 1. 背景2. 准备工作2.1 ncnn库下载2.2 adaface模型下载2.3 模型转换 3. 代码实现4. 模型量化 1. 背景 最近项目要求Android端使用adaface做人脸特征提取,最终选择ncnn作为推理框架 2. 准备工作 2.1 ncnn库下载 https://github.com/Tencent/ncnn/tree/maste…...
iOS 逆向学习 - iOS Security Features:硬件与软件多重防护体系
iOS 逆向学习 - iOS Security Features:硬件与软件多重防护体系 iOS 安全特性全面解析:构筑多层次防御体系一、iOS 的硬件安全特性1. Secure Enclave(安全隔区)2. Hardware Root of Trust(硬件信任根)3. De…...
纯前端实现将pdf转为图片(插件pdfjs)
需求来源 预览简历功能在移动端,由于用了一层iframe把这个功能嵌套在了app端,再用一个iframe来预览,只有ios能看到,安卓就不支持,查了很多资料和插件,原理基本上都是用iframe实现的。最终转换思路…...
stm32HAL库使LED闪烁
PC13引脚为开漏接法 生成代码时设置为out put open drain gpio out put level 设置为high 1表示熄灭 我们将pa9引脚连接为推挽接法 生成代码时设置为 out put push pull Gpio out put level 设置为low 0 表示熄灭 代码使其亮起再延时0.5秒再熄灭再延时0.5秒...
《数据结构》期末考试测试题【中】
《数据结构》期末考试测试题【中】 21.循环队列队空的判断条件为?22. 单链表的存储密度比1?23.单链表的那些操作的效率受链表长度的影响?24.顺序表中某元素的地址为?25.m叉树第K层的结点数为?26. 在双向循环链表某节点…...