八大排序算法细讲
目录
排序
概念
运用
常见排序算法
插入排序
直接插入排序
思想:
步骤(排升序):
代码部分:
时间复杂度:
希尔排序
思路
步骤
gap的取法
代码部分:
时间复杂度:
选择排序
直接选择排序
排升序思路:
排升序步骤:
代码部分:
时间复杂度:
堆排序
代码部分:
交换排序
冒泡排序
代码部分:
快速排序(递归版本)
思路:
hoare版本
排升序步骤:
相遇问题:
代码部分:
挖坑法版本
排升序思路:
代码部分:
前后指针版本:
排升序思路:
代码部分:
时间复杂度:
快速排序(非递归版本)
思路:
注意:
编辑
代码部分(找基准值部分用的是前后指针方法):
归并排序
思路:
排升序步骤:
代码部分:
时间复杂度:
非比较排序
计数排序
思路:
代码部分:
时间复杂度:
排序算法复杂度及稳定性分析
排序
概念
排序就是将一段记录,按照其中的某个或某些关键字大小,实现递增或递减的操作
运用
排序在我们的生活中运用也是极其广泛的,如:在购物软件中,根据不同条件来筛选商品;大学院校的排名……等等
常见排序算法
插入排序
直接插入排序
思想:
把待排序的记录按其关键码值的大小逐个插入到⼀个已经排好序的有序序列中,直到所有的记录插入完为止,得到⼀个新的有序序列
这种排序算法类似于玩扑克牌,就是依次将手中的牌进行排序
步骤(排升序):
1、先取出第二张牌与第一张进行比较,小的放前面,大的放后面
2、让后面的牌再进行上面那一步
这样看起来会比较抽象,举一个例子来实现就容易理解了
代码部分:
void InsertSort(int* arr, int n)
{for (int i = 0; i < n - 1; ++i){int end = i;int temp = arr[end + 1];while (end >= 0){if (arr[end] > temp){arr[end + 1] = arr[end];end--;}else{break;}}arr[end + 1] = temp;}
}
时间复杂度:
直接插入排序的时间复杂度为O(N^2),但在一般情况下是不会达到N^2的,只有在排序数组与要求排序方向相反时(也就是逆序),才会达到O(N^2)
这也就导致了一个问题,在面对逆序情况下,使用该排序算法,效率就会大大降低
面对这种情况,前人就在直接插入排序算法的基础上进行了改良,也就是接下来要讲的——希尔排序
希尔排序
根据上面的直接插入排序算法我们可以知道,在面对逆序数组时,算法复杂度太大了(O(N^2)),
所以前人就在该算法基础上进行了改良
思路
先选定一个整数,命名为gap,通常是gap=n/3+1,将带排序数组中元素根据gap值分为多组,也就是将相距gap值的元素分在同一组中,然后对每一组的元素进行排序,这是就完成一次排序,然后gap=gap/3+1,,再将数组根据gap值分为多组,进行插入排序,当gap=1时,就相当于进行直接插入排序算法。
步骤
步骤一(当gap>1):
1、将数组根据gap分为多组
2、将相距gap值的元素进行比较
注:步骤一也可以称为预排序,目的是为了:将数组转变为一个相对有序的情况,避免直接插入排序在面对逆序数组情况时时间复杂度变大
排升序时:小的元素在前面,大的元素在后面
排降序时:大的元素在前面,小的元素在后面
步骤二(当gap=1):
就相当于进行直接插入排序
举例可知
gap的取法
gap值的最初值取该数组的长度,当它进入while循环时,就先进行gap=gap/+1
然而,为什么是对gap/3,而不是除以其他值呢?
如果gap除以的值过小的话,比如:gap=gap/2,就会导致分的组太少,而每组内元素比较次数过多,while循环次数也会增多(因为gap值要不断除以2,直到gap=1时停止while循环)
如果gap除以的值过大的话,比如:gap=gap/8,就会导致分的组过多,而每组内元素比较次数较少,while循环次数少
所以gap除以的值要取适中的值,3则是较好的值
那为何还要加一呢?
加一的目的是为防止gap整除的值为0,这样可以防止gap=0时,直接退出循环,没有排序完全
代码部分:
void ShellSort(int* arr, int n)
{int gap = n;while (gap > 1)//gap不能等于1,如果为一进入循环,在gap/3+1中就会一直为1,就会死循环{gap = gap / 3 + 1;for (int i = 0; i < n - gap; ++i){int end = i;int temp = arr[end + gap];while (end >= 0){if (arr[end] > temp){arr[end + gap] = arr[end];end -= gap;}else{break;}}arr[end + gap] = temp;}}}
时间复杂度:
希尔排序算法的时间复杂度不好计算,大概为O(N^1.3)
选择排序
直接选择排序
排升序思路:
每一次循环,先从待排数组中找出最大和最小值,将最小值与待排数组的起始位置交换,最大值与待排数组的最后一个元素交换,直到所有待排数组元素排完
排升序步骤:
1、设立起始位置和最后一元素下标位置:begin、end,然后找到最大值和最小值下标
2、将最小值和起始元素交换、最大值和末尾元素交换
3、交换后,begin++、end--,然后进行[begin,end]区间元素的排序,按照上面两步
4、直到begin>end时结束排序
注:当begin与maxi、end与mini重叠时,会造成重复交换,所以就需要将maini和mini进行交换
代码部分:
void SelectSort(int* arr, int n)
{int begin = 0, end = n - 1;while (begin < end){int mini , maxi;mini = maxi = begin;for (int i = begin + 1; i <= end; ++i){if (arr[i] > arr[maxi]){maxi = i;}if (arr[i] < arr[mini]){mini = i;}}if (begin == maxi){maxi = mini;}Swap(&arr[begin], &arr[mini]);Swap(&arr[end], &arr[maxi]);begin++;end--;}
}
时间复杂度:
直接选择排序的时间复杂度很好理解,为O(N^2),因为它的效率不是很好,所以实际上很少会用到
堆排序
堆排序的讲解,在前面的文章已经讲解过了,就不在这里过多说明,有兴趣的朋友可以移步
二叉树:堆的建立和应用_二叉树的应用,两种创建方式-CSDN博客
代码部分:
void AdJustDown(int* arr, int parent, int n)//向下调整
{int child = parent * 2 + 1;while (child < n){//这里左右孩子的比较,c>c+1,交换建小堆;c<c+1,交换建大堆//建大堆,先找大孩子;建小堆,先找小孩子if (child + 1 < n && arr[child] < arr[child + 1]){child++;}//>建大堆//<建小堆if (arr[child] > arr[parent]){Swap(&arr[child], &arr[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}
void HeapSort(int* arr, int n)//向下调整算法建堆:时间复杂度O(n)
{//排升序建大堆//排降序建小堆//先建堆for (int i = (n - 1 - 1) / 2; i >= 0; i--){AdJustDown(arr, i, n);}//再排序int end = n - 1;while (end > 0){Swap(&arr[0], &arr[end]);//交换堆顶和尾结点AdJustDown(arr, 0, end);end--;}}
交换排序
冒泡排序
冒泡排序大家应该都不陌生,是我们C语言学习的第一个排序算法,它的时间复杂度为O(N^2),
关于它的思路步骤我就不过多说明了,它在实际当中也基本不会用到,它是起着一种教学作用的排序算法
代码部分:
void BubbleSort(int* arr, int n)
{int i = 0;for (i = 0; i < n - 1; ++i){int j = 0;int flag = 1;for (j = 0; j < n - 1 - i; ++j){if (arr[j] > arr[j + 1]){int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;flag = 0;}}if (flag == 1)//当提前完成排序后,就直接退出循环{break;}}
}
快速排序(递归版本)
快速排序可以说是排序算法中最重要的排序算法,在实际学习和工作中运用得最多,接下来我们来好好学习快速排序算法
思路:
任取待排数组中某一个元素作为基准值(key),然后将基准值放到正确位置上,按照基准值将数组分割成两个序列,左子序列中所有元素小于基准值,右子序列中所有元素大于基准值(这里排升序),然后再对左右子序列重复该过程,直到所有元素都排列再在相对应位置上为止
hoare版本
排升序步骤:
1、找基准值:
起始令首元素为基准值(key),设right和left,right为末尾元素下标,left为首元素下标,
让left从左往右找比基准值大的值,right从右往左找比基准值大的值,
找到以后将left与right指向的值进行交换,这个交换的前提是right>=left;
而当right小于left时right所指向的值就与key进行交换,这时key就回到了正确的位置
2、二分
根据key所在位置,对数组进行二分,将数组分为左右两个子序列,然后再对左右两个子序列进行上述操作
相遇问题:
1、相遇点值小于基准值
由此可知,当相遇点小于基准值时,left依旧减减
2、相遇点值大于基准值
由此可知,当相遇点大于基准值时,right依旧加加
3、当相遇点值等于基准值
这种情况看似两种都可以,但是当选择了right依旧减减时,就会导致面对下面这种情况时,时间复杂度大大提高
这种情况便是相遇点值与基准值相同的情况,在这种情况下,该排序算法的时间复杂度就会大大提高,无法进行高效的分割排序
其实这也是这种hoare版本快速排序在面对待排数组中重复元素过多情况下的弊端
代码部分:
int Hoare_QuickSort(int* arr, int left, int right)
{int keyi = left;left++;while (left <= right){//rigth从右往左找比基准值小的值while (left<=right && arr[right]>arr[keyi])//这里的arr[rigth]>arr[keyi]只能取大于号,不能加上等于号,//加上的话在面对数组全相等或有序数组时,时间复杂度会变大{right--;}//left从左往右找比基准值大的值while (left<=right && arr[left]<arr[keyi])//这里的情况和rigth是一样的{left++;}if (left <= right)//当left还未大于rigth时,就进行交换{Swap(&arr[left], &arr[right]);}}Swap(&arr[right], &arr[keyi]);keyi = right;return keyi;
}void QuickSort(int* arr, int left, int right)//排升序
{if (left >= right){return;}//找基准值int keyi = Hoare_QuickSort(arr, left, right);//二分//[left,keyi-1] keyi [keyi+1,right]QuickSort(arr, left, keyi - 1);QuickSort(arr, keyi + 1, right);}
挖坑法版本
排升序思路:
设立左右指针:left、right,先将基准值视为第一个坑:hole,
right从右往左找比基准值小的数,找到以后就放入到hole的位置,然后righ处就为新的坑;
left从左往右找比基准值大的数,找到以后就放入到hole的位置,然后left处就为新的坑;
当right==left时,就将保存的基准值放入到两者相遇处
就这样便完成了第一次基准值的寻找
找到以后就和hoare版本一样进行二分
注:
这种方法起始的left只能指向首元素;
和hoare版本不同的是,当right从右往左找比基准值小的值时,当遇到比基准值大的或者等于的值时,继续往左找;left也是一样的
代码部分:
int Hole_QuickSort(int* arr, int left, int right)
{int hole = left;int key = arr[hole];while (left < right){while (left<right && arr[right]>=key){right--;}//找到比基准值小的值arr[hole] = arr[right];hole = right;while (left<right && arr[left]<=key){left++;}//找到比基准值大的值arr[hole] = arr[left];hole = left;}//right和left相遇arr[hole] = key;return hole;
}void QuickSort(int* arr, int left, int right)//排升序
{if (left >= right){return;}//找基准值int keyi = Hole_QuickSort(arr, left, right);//二分//[left,keyi-1] keyi [keyi+1,right]QuickSort(arr, left, keyi - 1);QuickSort(arr, keyi + 1, right);}
前后指针版本:
排升序思路:
设立两个变量:pcur(用于探路,来找比基准值小的值),prev(在pcur的后面)
1、当找到比基准值小的值时,++prev,prev所指向的元素和pcur所指向的元素交换,然后++pcur
2、当pcur所指向的元素没有比基准值小时,++pcur
当pcur越界(pcur>right)时,就将基准值与prev所指向的元素交换,就这样就实现了将比基准值小的元素放在基准值左边,大的放在右边
注:
有时候prev++后的值正好等于pcur,这个时候就不需要发生交换
代码部分:
int lomuto_QuickSort(int* arr, int left, int right)
{int prev = left, pcur = prev + 1;int keyi = left;while (pcur <= right){if (arr[pcur] < arr[keyi]&&++prev != pcur){Swap(&arr[prev], &arr[pcur]);}pcur++;}Swap(&arr[prev], &arr[keyi]);keyi = prev;return keyi;
}void QuickSort(int* arr, int left, int right)//排升序
{if (left >= right){return;}//找基准值int keyi = lomuto_QuickSort(arr, left, right);//二分//[left,keyi-1] keyi [keyi+1,right]QuickSort(arr, left, keyi - 1);QuickSort(arr, keyi + 1, right);}
时间复杂度:
快速排序算法的时间复杂度为O(NlogN),在特殊情况下:待排数组中重复元素很多的时候,会到造成时间复杂度上升为O(N^2logN),这一点要记住,这与如何解决这一情况,在后面的文章中会着重讲解
快速排序(非递归版本)
我们讲解了递归版本的快速排序,那也会有非递归版本的快速排序
在非递归版本的快速排序和递归版本的快速排序有什么区别呢?
非递归版本的快速排序算法需要借助数据结构:栈来实现
思路:
我们首先需要建立一个栈,然后:
1、将数组的left和right下标入栈
2、进入一个循环(结束条件:栈为空),将从栈中出来的两个元素命名为begin和end
3、然后对[begin,end]这个区间来找基准值,找基准值的方法在上面已经说了三种方法,随便用那个都行
4、找完以后,根据基准值进行二分为左右两个子序列,再将左右两个子序列的首尾下标入栈,再重复上面的操作
注意:
1、当begin大于或等于keyi-1或者end小于或等于keyi+1时不进行入栈操作,也就是只有在begin<keyi-1或end>keyi+1的情况下才允许入栈操作
2、每次找完基准值后还要确定一次待排区间中下标是否都入栈了,首尾下标要再入一次栈,入栈条件也要满足上面的条件
3、建立了栈,在排完序后就需要进行销毁
如果对栈还有所不解的朋友,可以移步至【数据结构初阶】栈和队列的建立_实现线性表、栈和队列(要求顺序和链式两种实现)-CSDN博客
其实非递归版快速排序就是利用栈这一数据结构来模拟实现正常快速排序中的递归过程
代码部分(找基准值部分用的是前后指针方法):
void QuickSortNonR(int* arr, int left, int right)//非递归版本
{ST st;StackInit(&st);StackPush(&st, right);StackPush(&st, left);while (!StackEmpty(&st)){int begin = StackTop(&st);StackPop(&st);int end = StackTop(&st);StackPop(&st);int keyi = lomuto_QuickSort(arr, begin, end);if (end > keyi + 1){StackPush(&st, end);StackPush(&st, keyi+1);}if (begin < keyi - 1){StackPush(&st, keyi - 1);StackPush(&st, begin);}}StackDestroy(&st);}
归并排序
思路:
将待排序数组不断进行二分,直到划分为一个个有序的子序列,然后再将这些子序列两两合并,成一个有序数组
也就是先二分再合并
排升序步骤:
1、二分:
对数组取中间值(mid),进行二分,要保证数组最左边下标left要小于最右边下标right(left<right)
mid = left+(right-left)/2
根据mid分为左右两个子序列([left,mid-1],[mid+1,right])
直到left大于或等于right时停止二分
2、合并:
将相邻有序数组两两合并为一个有序数组,并将这个有序数组存储在一个临时数组(temp)中
要注意的是:每次放入临时数组结束后,两个数组中可能会有元素没有放入到临时数组中,所以循环结束后要对两个数组进行检查,再进行一次放入临时数组
3、将临时数组中元素放回原先数组中
代码部分:
void _MergeSort(int* arr, int left, int right, int* temp)
{//二分if (left >= right){return;}int mid = left + (right - left) / 2;_MergeSort(arr, left, mid,temp);_MergeSort(arr, mid+1, right,temp);//合并int begin1 = left, end1 = mid;int begin2 = mid+1, end2 = right;int i = begin1;while (begin1 <= end1 && begin2 <= end2){if (arr[begin1] < arr[begin2]){temp[i++] = arr[begin1++];}else{temp[i++] = arr[begin2++];}}//两个区间可能还有元素没有入tempwhile (begin1 <= end1){temp[i++] = arr[begin1++];}while (begin2 <= end2){temp[i++] = arr[begin2++];}//将temp中元素放回原数组中for (int i = left; i <= right; ++i){arr[i] = temp[i];}
}void MergeSort(int* arr, int n)
{int* temp = (int*)malloc(sizeof(int) * n);_MergeSort(arr, 0, n - 1, temp);free(temp);
}
时间复杂度:
归并排序算法时间复杂度为O(NlogN),它二分的次数为logN次,合并次数为N次
非比较排序
计数排序
思路:
1、
先找出数组中的最大、最小值,
用最大值和最小值来求出待排数组中元素的出现次数数组大小
用一次数组来存储元素出现次数:count,它的大小为range = max-min+1
2、
遍历数组,求出待排数组中各个元素出现的次数
将每个元素和最小值相减可以得出它在countg数组中的下标,则该对应下标存储的值就加一
3、
根据count数组向原数组中放入元素
arr[index] = i + min
注:
当min和max跨度很大时就会造成空间的浪费,那就不适合这种算法
代码部分:
void CountSort(int* arr, int n)
{//先找最大值和最小值int max = arr[0], min = arr[0];for (int i = 1; i < n; ++i){if (arr[i] > max){max = arr[i];}if (arr[i] < min){min = arr[i];}}int range = max - min + 1;int* count = (int*)malloc(sizeof(int) * range);if (count == NULL){perror("malloc,fail!");}//初始化数组memset(count, 0, sizeof(int*) * range);//统计次数for (int i = 0; i < n; ++i){count[arr[i] - min]++;}//将count中出现的次数还原到原数组中int index = 0;for (int i = 0; i < range; ++i){while (count[i]--){arr[index++] = i + min;}}
}
时间复杂度:
排序算法复杂度及稳定性分析
排序方法 | 平均情况 | 最好情况 | 最坏情况 | 辅助空间 | 稳定性 |
冒泡排序 | O(N^2) | O(N) | O(N^2) | O(1) | 稳定 |
直接选择排序 | O(N^2) | O(N^2) | O(N^2) | O(1) | 不稳定 |
直接插入排序 | O(N^2) | O(N) | O(N^2) | O(1) | 稳定 |
希尔排序 | O(NlogN)~O(N^2) | O(1.3) | O(N^2) | O(1) | 不稳定 |
堆排序 | O(NlogN) | O(NlogN) | O(NlogN) | O(1) | 不稳定 |
归并排序 | O(NlogN) | O(NlogN) | O(NlogN) | O(N) | 稳定 |
快速排序 | O(NlogN) | O(NlogN) | O(N^2) | O(logn)~O(N) | 不稳定 |
相关文章:

八大排序算法细讲
目录 排序 概念 运用 常见排序算法 插入排序 直接插入排序 思想: 步骤(排升序): 代码部分: 时间复杂度: 希尔排序 思路 步骤 gap的取法 代码部分: 时间复杂度: 选择排序 直接选…...

网络爬虫学习:借助DeepSeek完善爬虫软件,增加停止任务功能
一、引言 我从24年11月份开始学习网络爬虫应用开发,经过2个来月的努力,终于完成了开发一款网络爬虫软件的学习目标。这几天对本次学习及应用开发进行一下回顾总结。前面已经发布了两篇日志: 网络爬虫学习:应用selenium从搜*狐搜…...
docker安装es及分词器ik
系统是macos,docker是docker-desktop 拉取镜像 docker pull bitnami/elasticsearch 启动docker镜像 docker create -e "discovery.typesingle-node" \ --name elasticsearch1 -p 9200:9200 -p 9300:9300 \ bitnami/elasticsearch:8.17.1 测试是否好…...

【论文阅读】On the Security of “VOSA“
On the Security of Verifiable and Oblivious Secure Aggregation for Privacy-Preserving Federated Learning -- 关于隐私保护联邦中可验证与遗忘的安全聚合的安全性 论文来源摘要Introduction回顾 VOSA 方案对VOSA不可伪造性的攻击对于类型 I 的攻击对于类型 II 的攻击 论文…...
Docker 国内最新可用镜像源20250205
2年没用dockerhub了结果今天发现镜像无法拉取了,找了很多镜像都无效,连阿里云镜像都不行了,最后找到下面可以用的。 Docker镜像仓库备注hub.urlsa.us.kg可用http://hub.haod.eu.org可用http://hub.chxza.eu.org可用http://ccoc.eu.org部分地…...

(2025|ICLR,音频 LLM,蒸馏/ALLD,跨模态学习,语音质量评估,MOS)音频 LLM 可作为描述性语音质量评估器
Audio Large Language Models Can Be Descriptive Speech Quality Evaluators 目录 1. 概述 2. 研究背景与动机 3. 方法 3.1 语音质量评估数据集 3.2 ALLD 对齐策略 4. 实验结果分析 4.1 MOS 评分预测(数值评估) 4.2 迁移能力(在不同…...

使用 CSS 实现透明效果
在 CSS 中,实现透明效果有几种方法,具体使用哪种方法取决于具体需求。以下是一些常见的方法: 使用 opacity 属性: opacity 属性可以设置整个元素的透明度,包括其所有的子元素。 .transparent { opacity: 0.5; /* 0 表…...

4G核心网的演变与创新:从传统到虚拟化的跨越
4G核心网 随着移动通信技术的不断发展,4G核心网已经经历了从传统的硬件密集型架构到现代化、虚拟化网络架构的重大转型。这一演变不仅提升了网络的灵活性和可扩展性,也为未来的5G、物联网(LOT)和边缘计算等技术的发展奠定了基础。…...

数据库系统概论的第六版与第五版的区别,附pdf
我用夸克网盘分享了「数据库系统概论第五六版资源」,点击链接即可保存。 链接:https://pan.quark.cn/s/21a278378dee 第6版教材修订的主要内容 为了保持科学性、先进性和实用性,在第5版教材基础上对全书内容进行了修改、更新和充实。 在科…...

uniapp小程序自定义中间凸起样式底部tabbar
我自己写的自定义的tabbar效果图 废话少说咱们直接上代码,一步一步来 第一步: 找到根目录下的 pages.json 文件,在 tabBar 中把 custom 设置为 true,默认值是 false。list 中设置自定义的相关信息, pagePath&#x…...
自己实现的一个缓存数据库(搞着玩) .net Core/6/8/9
自己实现的一个缓存数据库(搞着玩) 想法来源特点说明 上代码主体基类测试类 注 想法来源 做过一个小型项目,客户要求易移植,不能使用收费的数据库,最好是一个包搞定,尝试过用sqlite,在部分linux…...
在Qt中,slots 关键字有什么用?
有下面的Qt代码: #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow>QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACEclass MainWindow : public QMainWindow {Q_OBJECTpublic:MainWindow(QWidget *parent nullptr…...
如何查看linux机器有几个cpu
在 Linux 机器上,你可以使用以下几种方法来查看 CPU 的数量(物理 CPU 和逻辑 CPU): 方法 1:使用 lscpu 命令 lscpu输出示例: CPU(s): 8 Thread(s) per core: 2 Core(s) per socket: 4 Soc…...
Swoole如何处理内存泄漏
Swoole处理内存泄漏的方式主要包括以下几个方面: 一、内存管理机制 Swoole的内存管理机制与普通PHP-CLI程序一致,但它在事件回调函数返回后会自动回收所有局部对象和变量,不需要手动unset。如果变量是一个资源类型,那么对应的资…...

Llama最新开源大模型Llama3.1
Meta公司于2024年7月23日发布了最新的开源大模型Llama 3.1,这是其在大语言模型领域的重要进展。以下是关于Llama 3.1的详细介绍: 参数规模与训练数据 Llama 3.1拥有4050亿(405B)参数,是目前开源领域中参数规模最大的…...

Pixflow - CL-DJI Drone LUTs 120个大疆Drone无人机相机航拍电影级镜头LUT调色预设
120组电影质感DJI大疆无人机航拍视频LOG&Rec 709还原颜色分级调色LUTs预设包Pixflow – CL-DJI Drone LUTs 使用基于城市外观和 DJI 无人机镜头的最佳 Drone Luts 颜色预设来提升您的视频。 120 个出色的颜色分级 LUTS,您可以将其与任何无人机视频素材一起使用…...

了解AI绘图,Stable Diffusion的使用
AI绘图对GPU算力要求较高。 个人电脑配置可参考: CPU:14600kf 盒装 显卡:RTX 4080金属大师 OC,16G显存 主板:z790吹雪d4 内存:芝奇皇家戟4000c18,162G 硬盘:宏基gm7000 1T 散热:追风…...

idea整合deepseek实现AI辅助编程
1.File->Settings 2.安装插件codegpt 3.注册deepseek开发者账号,DeepSeek开放平台 4.按下图指示创建API KEY 5.回到idea配置api信息,File->Settings->Tools->CodeGPT->Providers->Custom OpenAI API key填写deepseek的api key Chat…...
llama_index
目录 安装 llama_index 搜索引擎 用 DeepSeek API 替换本地 Ollama 模型 源代码: 安装 pip install llama_index llama_index 搜索引擎 llama_index框架构建搜索引擎_llamaindex使用正则表达式拆分文档-CSDN博客 用 DeepSeek API 替换本地 Ollama 模型 https…...
Spring Boot统一异常拦截实践指南
Spring Boot统一异常拦截实践指南 一、为什么需要统一异常处理 在Web应用开发中,异常处理是保证系统健壮性和用户体验的重要环节。传统开发模式中常见的痛点包括: 异常处理逻辑分散在各个Controller中错误响应格式不统一敏感异常信息直接暴露给客户端…...
【hadoop】Flink安装部署
一、单机模式 步骤: 1、使用XFTP将Flink安装包flink-1.13.5-bin-scala_2.11.tgz发送到master机器的主目录。 2、解压安装包: tar -zxvf ~/flink-1.13.5-bin-scala_2.11.tgz 3、修改文件夹的名字,将其改为flume,或者创建软连接…...

让音乐“看得见”:使用 HTML + JavaScript 实现酷炫的音频可视化播放器
在这个数字时代,音乐不仅是听觉的享受,更可以成为视觉的盛宴!本文用 HTML + JavaScript 实现了一个音频可视化播放器,它不仅能播放本地音乐、控制进度和音量,还能通过 Canvas 绘制炫酷的音频频谱图,让你“听见色彩,看见旋律”。 效果演示 核心功能 本项目主要包含以下…...
Android 集成 Firebase 指南
Firebase 是 Google 提供的一套移动开发平台,包含分析、认证、数据库、消息推送等多种服务。以下是在 Android 应用中集成 Firebase 的详细步骤: 1. 准备工作 安装 Android Studio - 确保使用最新版本 创建或打开 Android 项目 - 项目需要配置正确的包…...

PHP环境极速搭建
一、为什么选择phpStudy VS Code? 作为一名初次接触PHP的开发者,我深知环境配置往往是学习路上的第一道门槛。传统PHP环境搭建需要手动配置Apache/Nginx、PHP解释器、MySQL等多重组件,光是处理版本兼容性和依赖问题就可能耗费半天时间——这…...
Asp.Net Core基于StackExchange Redis 缓存
NuGet安装 StackExchange.Redis Microsoft.Extensions.Options 0. appsettings.json初始化配置 {"Logging": {"LogLevel": {"Default": "Information","Microsoft.AspNetCore": "Warning"}},"AllowedHos…...

行为设计模式之Command (命令)
行为设计模式之Command (命令) 前言: 需要发出请求的对象(调用者)和接收并执行请求的对象(执行者)之间没有直接依赖关系时。比如遥控器 每个按钮绑定一个command对象,这个Command对…...

3. 简述node.js特性与底层原理
😺😺😺 一、Node.js 底层原理(简化版) Node.js 是一个 基于 Chrome V8 引擎构建的 JavaScript 运行时,底层核心由几部分组成: 组成部分简要说明 1.V8 引擎 将 JS 编译成机器码执行࿰…...

算法练习-回溯
今天开始新的章节,关于算法中回溯法的练习,这部分题目的难度还是比较大的,但是十分锻炼人的思维与思考能力。 处理这类题目首先要注意几个基本点: 1.关于递归出口的设置,这是十分关键的,要避免死循环的产…...
Windows 下彻底删除 VsCode
彻底删除 VS Code (Visual Studio Code) 意味着不仅要卸载应用程序本身,还要删除所有相关的配置文件、用户数据、插件和缓存。这可以确保你有一个完全干净的状态,方便你重新安装或只是彻底移除它。 重要提示: 在执行以下操作之前,…...

【PDF PicKiller】PDF批量删除固定位置图片工具,默认解密,可去一般图、背景图、水印图!
PDF批量删除固定位置图片工具 PDF PicKiller <center>PDF PicKiller [Download](https://github.com/Peaceful-World-X/PDF-PicKiller)🤩 工具介绍🥳 主要功能🤪 软件使用🤪 参数解释🤪 关键代码🤩 项…...