当前位置: 首页 > article >正文

数据结构5(初):排序

目录

1、排序的概念以及常见的排序算法

1.1、排序的概念

1.2、常见的排序算法

2、常见排序算法的实现

2.1、插入排序

2.1.1、直接插入排序

2.1.2、希尔排序

2.2、选择排序

2.2.1、直接选择排序

2.2.2、堆排序

2.3、交换排序

2.3.1、冒泡排序

2.3.2、快速排序

2.3.2.1、递归版本

2.3.2.2、非递归版本

2.4、归并排序

2.4.1、递归版本

2.4.2、非递归版本

2.5、归并排序和快速排序的优化

2.5.1、归并排序递归版本的优化

2.5.2、快速排序递归版本的优化

3、排序OJ


1、排序的概念以及常见的排序算法

1.1、排序的概念

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

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

内部排序:数据元素全部放在内存中的排序。就是在内存中对数据进行排序,这种排序一般数据量比较小。

外部排序:数据元素太多不能同时放在内存中,就需要使用外部排序。

1.2、常见的排序算法

2、常见排序算法的实现

2.1、插入排序

直接插入排序是一种简单的插入排序法,其基本思想是:把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。

实际中我们玩扑克牌时,就用了插入排序的思想,每次摸牌,插入到一个已经排好的序列中,这就是插入排序的思想。例如:

2.1.1、直接插入排序

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

直接插入排序的特性总结:

1. 元素集合越接近有序,直接插入排序算法的时间效率越高。

2. 时间复杂度:O(N^2)。最优为O(N)。

3. 空间复杂度:O(1)。

4. 稳定性:稳定。

例如:

//直接插入排序
void InsertSort(int* a, int n)
{for (int i = 0; i < n-1; i++){int end=i;int tmp=a[i+1];   //存数据while (end >= 0){if (a[end] > tmp)    //目前排的是升序{a[end + 1] = a[end];end--;}elsebreak;}a[end + 1] = tmp;}
}
2.1.2、希尔排序

希尔排序法又称缩小增量法。希尔排序是一种基于插入排序的排序算法,它通过将数据分成多个“子序列”对其进行排序,从而提高插入排序的效率。如图:先有一个gap,把相隔距离为gap的数据归为一组,然后对每个组进行插入排序,然后再减小gap重复上述步骤。gap越大排完越不接近有序。当gap为1时,排完就变成有序的了。

例如:

//希尔排序1
void ShellSort(int* a, int n)
{int gap=n;while (gap > 1){gap = gap / 3 + 1;      //选择3是因为这个数比较合适//在这个过程中,gap会变的越来越小for (int j = 0; j < gap; j++)    //分组{for (int i = j; i < n - gap; i += gap)      //插入排序{int end = i;int tmp = a[end + gap];while (end >= 0){if (a[end] > tmp){a[end + gap] = a[end];end -= gap;}elsebreak;}a[end + gap] = tmp;}}}
}

再比如:

//希尔排序2      //多组并排
void ShellSort2(int* a, int n)
{int gap = n;while (gap > 1){gap = gap / 3 + 1;              //选择3这个数是因为这个数比较合适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;}elsebreak;}a[end + gap] = tmp;}}
}

希尔排序的特性总结:

1. 希尔排序是对直接插入排序的优化。

2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。

3. 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些书中给出的希尔排序的时间复杂度都不固定。根据一些书上给出的值,我们暂且认为希尔排序的时间复杂度为O(N^1.3)。空间复杂度很显然为O(1)。

4. 稳定性:不稳定。

2.2、选择排序

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

2.2.1、直接选择排序

在元素集合中选择关键码最大(小)的数据元素 ,若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换 ,在剩余的未排好的集合中,重复上述步骤,直到集合剩余1个元素。

例如:

//选择排序(这个选择排序进行优化了一下,这个是从两头开始都排数)
void SelectSort(int* a, int n)
{int begin = 0, end = n - 1;while (begin < end){int maxi = begin, mini = begin;for (int i = begin; i <= end; i++){if (a[i] > a[maxi]){maxi = i;}if (a[i] < a[mini]){mini = i;}}Swap(&a[begin], &a[mini]);//如果maxi和begin重合,修正一下if (begin == maxi){maxi = mini;}Swap(&a[end], &a[maxi]);++begin;--end;}
}

直接选择排序的特性总结:

1. 直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用

2. 时间复杂度:O(N^2)

3. 空间复杂度:O(1)

4. 稳定性:不稳定

2.2.2、堆排序

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

例如:堆排序之前在树的部分说过。

//堆排序
void HeapSort(int* a, int n)
{for (int i = (n - 1 - 1) / 2; i >= 0; i--){AdjustDown(a, n, i);}//成功建堆int end = n - 1;while (end > 0){Swap(&a[0], &a[end]);//交换,为了不破坏堆的结构。AdjustDown(a, end, 0);//再从根开始调整堆的结构。--end;}
}

直接选择排序的特性总结:

1. 堆排序使用堆来选数,效率就高了很多。

2. 时间复杂度:O(N*logN)。

3. 空间复杂度:O(1)。

4. 稳定性:不稳定。

2.3、交换排序

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

2.3.1、冒泡排序

例如:

//冒泡排序
void BubbleSort(int* a, int n)
{for (int j = 0; j < n; j++){bool exchange = false;for (int i = 1; i < n - j; i++){if (a[i - 1] > a[i]){int tmp = a[i];a[i] = a[i - 1];a[i - 1] = tmp;exchange = true;}}if (exchange == false)break;}
}

冒泡排序的特性总结:

1. 时间复杂度:O(N^2)

2. 空间复杂度:O(1)

3. 稳定性:稳定

2.3.2、快速排序

其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

一般基准值的选择是以左边或者右边的值作为基准值。每次选择的基准值为中位数效率就很好,数组一旦有序,效率就会变成最坏,时间复杂度为O(N^2)。为了解决这个基准值选取的问题,我们可以使用三数取中法或者随机数取中法。

例如:三数取中法:首、尾、中间的值取中间值。

//三数取中
int GetMidIndex(int* a, int left, int right)//选择首、尾和中间的三个数,找到这三个数中既不是最大也不是最小的数。
{int mid = (left + right) / 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[mid] > a[right]){return mid;}else if (a[left]>a[right]){return right;}else{return left;}}
}

例如:随机数取中法:

//随机数选基准值法
int GetMidIndex2(int* a, int left, int right)
{srand(time(0));int mid = left + (rand() % (right - left));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[mid] > a[right]){return mid;}else if (a[left] > a[right]){return right;}else{return left;}}
}
2.3.2.1、递归版本

快速排序递归版本的主框架:

void QuickSort(int* a, int begin,int end)
{if (begin >= end){return;}int keyi = PartSort(a, begin, end);QuickSort(a, begin, keyi - 1);QuickSort(a, keyi + 1, end);
}

其中PartSort有三个版本:

1、hoare版本

//Hoare版本
int PartSort(int* a, int left, int right)
{int midi = GetMidIndex(a, left, right);//三数取中,来优化快速排序。Swap(&a[left], &a[midi]);int keyi = left;//标准值keyiwhile (left < right){//右边找小while (left < right && a[right] >= a[keyi]){--right;}//左边找大while (left < right && a[left] <= a[keyi]){++left;}Swap(&a[left], &a[right]);//交换,让标准左边小,标准右边大。}Swap(&a[keyi], &a[left]);return left;
}

2、挖坑法

//挖坑法版本
int PartSort2(int* a, int left, int right)
{int midi = GetMidIndex(a, left, right);Swap(&a[left], &a[midi]);int key = a[left];int hole = left;while (left < right){//右边找小while (left < right && a[right] >= key){--right;}a[hole] = a[right];hole = right;//左边找大while (left < right && a[left] <= key){++left;}a[hole] = a[left];hole = left;}a[hole] = key;return hole;
}

3、前后指针法

//前后指针法版本
int PartSort3(int* a, int left, int right) 
{int midi = GetMidIndex(a, left, right);Swap(&a[left], &a[midi]);int prev = left;int cur = left + 1;int keyi = left;while (cur <= right){if (a[cur] < a[keyi] && ++prev != cur){Swap(&a[prev], &a[cur]);}++cur;}Swap(&a[prev], &a[keyi]);keyi = prev;return keyi;
}

这些版本的时间复杂度都为O(N),思想基本都是一致的,没有本质上的差别。相对来说hoare最难,前后指针法最容易理解。

2.3.2.2、非递归版本

例如:这里使用了栈这个数据结构的一些接口,可看之前写的文章中栈的实现。

//非递归的快速排序
void QuickSortNonR(int* a, int begin, int end)
{ST st;STInit(&st);STPush(&st, end);STPush(&st, begin);while (!STEmpty(&st)){int left = STTop(&st);STPop(&st);int right = STTop(&st);STPop(&st);int keyi = PartSort3(a, left, right);if (keyi + 1 < right){STPush(&st, right);STPush(&st, keyi + 1);}if (left < keyi - 1){STPush(&st, keyi-1);STPush(&st, left);}}STDestory(&st);
}

这个非递归版本的快速排序还可以使用队列来实现。 

快速排序的特性总结:

1. 快速排序整体的综合性能和使用场景都是比较好的。

2. 时间复杂度:O(N*logN)

3. 空间复杂度:O(logN)

4. 稳定性:不稳定

2.4、归并排序

归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。如图:

2.4.1、递归版本

例如:

//归并排序
void _MergeSort(int* a, int begin,int end,int* tmp)
{if (begin == end)return;int mid = (begin + end) / 2;_MergeSort(a, begin, mid, tmp);_MergeSort(a, mid + 1, end, tmp);int begin1 = begin, end1 = mid;int begin2 = mid + 1, end2 = end;int i = begin;while (begin1<=end1 && begin2<=end2){if (a[begin1] <= a[begin2]){tmp[i++] = a[begin1++];}else{tmp[i++] = a[begin2++];}}while (begin1<=end1){tmp[i++] = a[begin1++];}while (begin2 <= end2){tmp[i++] = a[begin2++];}memcpy(a+begin, tmp+begin, sizeof(int) * (end - begin + 1));
}void MergeSort(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);_MergeSort(a, 0, n - 1, tmp);free(tmp);
}
2.4.2、非递归版本

法一:

//非递归版本
void MergeSortNonR(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);int gap = 1;while (gap<n){int j = 0;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;if (end1 >= n || begin2 >= n){break;}if (end2 >= n){end2 = n - 1;}while (begin1 <= end1 && begin2 <= end2){if (a[begin1] <= a[begin2]){tmp[j++] = a[begin1++];}else{tmp[j++] = a[begin2++];}}while (begin1 <= end1){tmp[j++] = a[begin1++];}while (begin2 <= end2){tmp[j++] = a[begin2++];}//归并一组,拷一组。memcpy(a + i, tmp + i, sizeof(int) * (end2 - i + 1));}gap *= 2;}free(tmp);
}

法二:

//解决方法2
void MergeSortNonR2(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);int gap = 1;while (gap < n){int j = 0;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;if (end1 >= n){end1 = n - 1;begin2 = n;end2 = n - 1;}else if (begin2 >= n){begin2 = n;end2 = n - 1;}else if (end2 >= n){end2 = n - 1;}while (begin1 <= end1 && begin2 <= end2){if (a[begin1] <= a[begin2]){tmp[j++] = a[begin1++];}else{tmp[j++] = a[begin2++];}}while (begin1 <= end1){tmp[j++] = a[begin1++];}while (begin2 <= end2){tmp[j++] = a[begin2++];}}memcpy(a, tmp, sizeof(int) * n);//整组拷贝gap *= 2;}free(tmp);
}

归并排序的特性总结:

1. 归并的缺点在于需要O(N)的空间复杂度,归并排序更多的是解决在硬盘中的外排序问题,另外归并排序本身是很快的,但是拷贝数据是一个硬伤。

2. 时间复杂度:O(N*logN)

3. 空间复杂度:O(N)

4. 稳定性:稳定

2.5、归并排序和快速排序的优化

2.5.1、归并排序递归版本的优化

这个优化主要是通过对小区间使用插入排序实现的。但是这个优化并不能从本质上改变归并排序的效率。

//针对递归版本的一些改进
//归并排序
void _MergeSort2(int* a, int begin, int end, int* tmp)
{if (begin == end)return;//小区间优化if (end - begin + 1 < 10){InsertSort(a + begin, end - begin + 1);return;}int mid = (begin + end) / 2;_MergeSort2(a, begin, mid, tmp);_MergeSort2(a, mid + 1, end, tmp);int begin1 = begin, end1 = mid;int begin2 = mid + 1, end2 = end;int i = begin;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] <= a[begin2]){tmp[i++] = a[begin1++];}else{tmp[i++] = a[begin2++];}}while (begin1 <= end1){tmp[i++] = a[begin1++];}while (begin2 <= end2){tmp[i++] = a[begin2++];}memcpy(a + begin, tmp + begin, sizeof(int) * (end - begin + 1));
}void MergeSort2(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);_MergeSort2(a, 0, n - 1, tmp);free(tmp);
}
2.5.2、快速排序递归版本的优化

这个三路划分主要针对的是一个元素全相等的数组的情况,因为元素全相等,快速排序的时间复杂度就变为了O(N^2)。随机数取中法主要是针对三数取中法可能会被一些特别例子针对而设计的一种方法。

//三路取中法(对快速排序的优化,采用了三路划分,以及随机数取中法)
void QuickSortRoad3(int* a, int begin, int end)
{if (begin >= end){return;}int left = begin;int right = end;int cur = left + 1;int midi = GetMidIndex2(a, left, right);Swap(&a[left], &a[midi]);int key = a[left];while (cur <= right){if (a[cur] < key){Swap(&a[left], &a[cur]);++left;++cur;}else if (a[cur] > key){Swap(&a[right], &a[cur]);--right;}else{++cur;}}QuickSortRoad3(a, begin, left - 1);QuickSortRoad3(a, right + 1, end);
}

3、排序OJ

可以尝试使用上面的排序来跑一跑下面的OJ题,观察这些排序的效率差异

排序OJ

相关文章:

数据结构5(初):排序

目录 1、排序的概念以及常见的排序算法 1.1、排序的概念 1.2、常见的排序算法 2、常见排序算法的实现 2.1、插入排序 2.1.1、直接插入排序 2.1.2、希尔排序 2.2、选择排序 2.2.1、直接选择排序 2.2.2、堆排序 2.3、交换排序 2.3.1、冒泡排序 2.3.2、快速排序 2.3.…...

表达式括号匹配(stack)(信息学奥赛一本通-1353)

【题目描述】 假设一个表达式有英文字母&#xff08;小写&#xff09;、运算符&#xff08;&#xff0c;—&#xff0c;∗&#xff0c;/&#xff09;和左右小&#xff08;圆&#xff09;括号构成&#xff0c;以“ ”作为表达式的结束符。请编写一个程序检查表达式中的左右圆括号…...

RabbitMQ 详细原理解析

RabbitMQ 是一个基于 AMQP&#xff08;Advanced Message Queuing Protocol&#xff09; 协议的开源消息代理中间件&#xff0c;广泛用于分布式系统中的异步通信、服务解耦、流量削峰等场景。其核心设计围绕生产者、消费者、队列、交换机和虚拟主机等组件&#xff0c;结合 AMQP …...

2025-03-23 学习记录--C/C++-C语言 sprintf()实现将多个值按指定格式拼接成字符串

C语言 sprintf()实现将多个值按指定格式拼接成字符串 举个例子 &#x1f330;&#xff1a;将字符串 “m” 与数字 0、1、2 动态拼接成 “m0”、“m1”、“m2”&#xff1a;&#x1f447;&#x1f3fb; #include <stdio.h> // 包含标准输入输出库&#xff0c;用于使用输入…...

【小程序开发】完整项目结构长啥样?

Hello,欢迎来到AI技术库。AI写代码的时代,人人都可以成为程序员。欢迎继续【小程序开发】系列课。上节课中,我们学习了【手把手教你小程序开发】什么是大前端?,本节课,我们学习第二篇 小程序的完整项目结构。 本文适合阅读对象: 1. 非计算机专业AI爱好者;2. 小程序开发…...

JVM的组成及各部分的作用

JVM&#xff08;Java虚拟机&#xff09;是Java程序运行的核心环境&#xff0c;负责将Java字节码转换为机器码并执行。以下是JVM的主要组成部分及其作用&#xff1a; 1. 类加载器子系统&#xff08;Class Loader Subsystem&#xff09; 作用 加载&#xff1a;将 .class 文件加载…...

计算机网络精讲day2———计算机网络的性能指标(下)

性能指标5&#xff1a;时延带宽积 时延带宽积传播时延*带宽 这里要注意是传播时延不是发送时延 重点&#xff1a;管道法解析时延带宽积 我们以一个圆柱形管道来代表链路&#xff0c;管道的长度是链路的传播时延&#xff08;以时间作为单位单位表示链路长度&#xff09;&#x…...

Android LiveData 的 `setValue` 与 `postValue` 区别详解

Android LiveData 的 setValue 与 postValue 区别详解 一、核心区别 线程限制 • setValue:必须且仅能在主线程调用,否则会抛出 IllegalStateException。 • postValue:可在任意线程调用,内部通过 Handler 将任务切换到主线程执行 setValue。 数据更新机制 • setValue:同…...

【多线程】初始线程和Thread类

一. 线程 1. 线程的引入 虽然进程已经可以解决并发编程这种问题&#xff0c;但是进程在频繁进行创建和销毁的时候&#xff0c;系统开销非常大&#xff0c;如果一个服务器向你发送多个请求&#xff0c;针对每一个请求&#xff0c;都需要创建一个进程来应答&#xff0c;每个进程…...

WebLogic中间件常见漏洞

一、后台弱⼝令GetShell 1.环境搭建 cd vulhub-master/weblogic/weak_password docker-compose up -d 2.访问网站并登陆后台 /console/login/LoginForm.jsp 默认账号密码&#xff1a;weblogic/Oracle123 3.点击部署&#xff0c;点击安装&#xff…...

[笔记.AI]多头自注意力机制(Multi-Head Attention)

多头自注意力是深度学习领域&#xff0c;特别是自然语言处理&#xff08;NLP&#xff09;和Transformer模型中的关键概念。其发展源于对序列数据中复杂依赖关系的建模需求&#xff0c;特别是在Transformer架构的背景下。 举例 比喻-读长篇文章 用一个简单的比喻来理解“多头注…...

【基于ROS的A*算法实现路径规划】A* | ROS | 路径规划 | Python

### 记录一下使用Python实现ROS平台A*算法路径规划 ### 代码可自取 &#xff1a;Xz/little_projecthttps://gitee.com/Xz_zh/little_project.git 目录 一、思路分析 二、算法实现 三、路径规划实现 一、思路分析 要求使用A*算法实现路径规划&#xff0c;可以将该任务分为三…...

keda基于postgresql伸缩dify-api服务

1 概述 dify-api使用postgresql来存储数据&#xff0c;在dify控制台每新建一个聊天机器的聊天框&#xff0c;就会在conversations表里新插入一条记录&#xff0c;并且不断地更新字段updated_at&#xff0c;示例如下&#xff1a; dify# select * from conversations limit 1; …...

趣味极简品牌海报艺术贴纸设计圆润边缘无衬线粗体装饰字体 Chunko Bold - Sans Serif Font

Chunko Bold 是一种功能强大的显示字体&#xff0c;体现了大胆极简主义的原则 – 当代设计的主流趋势。这种自信的字体将粗犷的几何形状与现代的趣味性相结合&#xff0c;具有圆润的边缘和强烈的存在感&#xff0c;与当今的极简主义设计方法完美契合。无论是用于鲜明的构图还是…...

VoLTE(Voice over Long-Term Evolution)

VoLTE&#xff0c;即Voice over Long-Term Evolution&#xff0c;是一种基于4G LTE网络的高质量语音通话技术。与传统的2G和3G网络中的语音通话不同&#xff0c;VoLTE将语音信号转换为数据包&#xff0c;通过LTE网络进行传输&#xff0c;从而实现了更快的连接速度和更高的通话质…...

指针,数组 易混题解析(一)

目录 一.相关知识点 1.数组名是什么&#xff1f; 两个例外&#xff1a; 2.strlen 3.sizeof 4. * ( ) 与 [ ] 的互换 二.一维数组 三.字符数组 1. 字符 &#xff08;1&#xff09;sizeof &#xff08;2&#xff09;strlen 2.字符串 &#xff08;1&#xff09;si…...

Java 基础篇:数组

前言 数组&#xff08;Array&#xff09;是 Java 中最基本的数据结构之一&#xff0c;它用于存储相同类型的元素&#xff0c;并且在内存中是连续存储的。数组具有高效的索引访问特点&#xff0c;但长度固定&#xff0c;不能动态调整。 本文将介绍数组的基本概念、声明和初始化方…...

从汽车 BCM 方案看国产 MCU 芯片的突围与挑战

摘要 &#xff1a;汽车车身控制模块&#xff08;BCM&#xff09;作为汽车电子系统的核心控制单元&#xff0c;其性能高度依赖于微控制单元&#xff08;MCU&#xff09;芯片。随着汽车智能化与电动化的发展&#xff0c;国产 MCU 芯片在 BCM 领域的应用逐渐扩大。本文结合行业数据…...

深入理解 Spring 框架中的 IOC 容器

一、Spring 框架概述 Spring 框架是一个轻量级的 Java 开发框架&#xff0c;由 Rod Johnson 在 2003 年创建。它的诞生旨在简化企业级应用开发的复杂性。Spring 框架提供了诸如 IoC&#xff08;控制反转&#xff09;和 AOP&#xff08;面向切面编程&#xff09;等核心功能&…...

深入理解 Java 中 instanceof 操作符

目录 1. instanceof 的基本用法 1.1 语法 1.2 示例 2. instanceof 的用途 2.1 类型检查 2.2 类型转换 2.3 多态编程 3. instanceof 的注意事项 3.1 null 检查 3.2 接口检查 3.3 继承关系 3.4 性能问题 4. instanceof 代码示例 4.1 多态处理 4.2 接口检查 4.3 n…...

2025前端面试题记录

vue项目目录的执行顺序是怎么样的&#xff1f; 1、package.json   在执行npm run dev时&#xff0c;会在当前目录寻找package.json文件&#xff0c;此文件包含了项目的名称版本、项目依赖等相关信息。 2、webpack.config.js(会被vue-cli脚手架隐藏) 3、vue.config.js   对…...

复变函数摘记2

复变函数摘记2 3. 级数3.1 复数项级数3.2 复变幂级数3.3 泰勒级数3.4 洛朗级数 3. 级数 \quad 复数项级数的一般项 α n a n i b n \alpha_na_n\text{i}b_n αn​an​ibn​ 为复数&#xff0c;与高等数学中无穷级数的分析方式类似&#xff0c;也是通过和函数来研究级数的收敛…...

光纤的频率和带宽

光纤通信中的频率和带宽涉及光波的物理特性以及通信系统的设计&#xff0c;以下是详细解释&#xff1a; ‌1. 光纤的工作频率‌ 光纤通信利用光波作为载波&#xff0c;工作频率主要在‌近红外波段‌&#xff0c;具体频段和对应的波长如下&#xff1a; ‌C波段&#xff08;Conve…...

高频面试题(含笔试高频算法整理)基本总结回顾67

干货分享&#xff0c;感谢您的阅读&#xff01; &#xff08;暂存篇---后续会删除&#xff0c;完整版和持续更新见高频面试题基本总结回顾&#xff08;含笔试高频算法整理&#xff09;&#xff09; 备注&#xff1a;引用请标注出处&#xff0c;同时存在的问题请在相关博客留言…...

Kafka--常见问题

1.为什么要使用 Kafka&#xff0c;起到什么作用 Kafka是一个高吞吐量、分布式、基于发布订阅的消息系统&#xff0c;它主要用于处理实时数据流 Kafka 设计上支持高吞吐量的消息传输&#xff0c;每秒可以处理数百万条消息。它能够在处理大量并发请求时&#xff0c;保持低延迟和…...

优选算法的睿智之林:前缀和专题(一)

专栏&#xff1a;算法的魔法世界 个人主页&#xff1a;手握风云 目录 一、前缀和 二、例题讲解 2.1. 一维前缀和 2.2. 二维前缀和 2.3. 寻找数组的中心下标 2.4. 除自身以外数组的乘积 一、前缀和 前缀和算法是一种用于处理数组或序列数据的算法&#xff0c;其核心思想是…...

嵌入式八股文学习——STL相关内容学习

文章目录 map和set的区别与实现1. map和set的区别2. 为什么set的元素和map的key不可修改&#xff1f; map和set的实现1. map的实现原理map的操作&#xff1a;map的特点&#xff1a; 2. set的实现原理set的操作&#xff1a;set的特点&#xff1a; map和set的底层原理&#xff08…...

【清华大学】AIGC发展研究(3.0版)

目录 AIGC发展研究报告核心内容一、团队简介二、AI哲学三、国内外大模型四、生成式内容&#xff08;一&#xff09;文本生成&#xff08;二&#xff09;图像生成&#xff08;三&#xff09;音乐生成&#xff08;四&#xff09;视频生成 五、各行业应用六、未来展望 AIGC发展研究…...

JavaSE1.0(基础语法之运算符)

算术运算符 基础运算之加 减 乘 除 取余&#xff08; - * / %&#xff09; 运算符之相加&#xff08; &#xff09; public static void main(String[] args) {System.out.println("Hello world!");int a 10;int b 20;int c a b;System.out.println(c);//…...

二十五、实战开发 uni-app x 项目(仿京东)- 前后端轮播图

定义了一个名为 Swiper 的Java类,用于表示一个轮播图实体。它使用了 Jakarta Persistence API (JPA) 来映射数据库表,并使用了 Lombok 库来简化代码。以下是对代码的详细讲解: 1. 包声明 package com.jd.jdmall.model; 这行代码声明了该类所在的包路径为 com.jd.jdmall.mode…...