【C++】排序算法

news2024/11/15 11:16:25

目录

一、排序算法概述

二、初级排序算法

三、进阶排序算法

四、分治思想排序

五、哈希思想排序

六、分割思想排序


一、排序算法概述

在C语言中,通常需要手写排序算法实现对数组或链表的排序,但是在C++中,标准库中的<algorithm>头文件中已经实现了基于快排的不稳定排序算法 std::sort() ,以及稳定的排序算法 std::stable_sort()

排序算法通常会伴随着容器使用,当然有些时候,我们也可以直接通过容器的特性来实现对元素的去重和排序,比如 map 和 unordered_map 底层的红黑树,就可以在插入数据的时候实现排序。

虽然C++标准库中已经封装有了现成排序算法了,那么我们为何还要学习排序算法呢?

对于应聘者而言,排序算法无论是笔试还是面试,都是常考点,所以我们需要掌握排序算法的算法原理与代码实现,通过学习排序算法,能够加深我们对于代码的复杂度分析,同时也能加深我们对于数据的稳定性分析

复杂度分为时间复杂度和空间复杂度,在早期的程序中,内存往往是限制程序运行的关键因素,因此在算法设计的时候,都会尽可能在考虑代码效率的同时去考虑节约内存,从而做到时间复杂度和空间复杂度的相对平衡,但是随着硬件技术的发展,计算机的内存越来越大,已经不再是紧缺资源了,所以如今的算法设计,会尽可能地优先考虑时间复杂度,在最大化地降低时间复杂度之后,才会考虑去节约内存,甚至有些算法会考虑牺牲空间复杂度来提高效率,比如归并排序。

稳定性在排序算法中也是需要重点考虑的一个因素,稳定性是指在排序过程中,两个等值的元素它们的相对位置是否会在排序过程中改变,如果它们的位置不变,即这是稳定的排序算法,否则就是不稳定的排序算法。

排序算法经历了长远的发展历程,到如今最广为人知的排序算法有:冒泡排序、插入排序、选择排序、希尔排序、桶排序、归并排序、快速排序、计数排序、基数排序、桶排序、外排序……

算法思维进行分类的话,可以分为以下几类:

  1. 暴力求解思想:冒泡排序
  2. 基于插入思想:插入排序、希尔排序
  3. 基于选择思想:选择排序、堆排序
  4. 基于分治思想:归并排序、快速排序
  5. 基于哈希思想:计数排序、基数排序
  6. 基于分割思想:桶排序、外排序

算法稳定性进行分类的话,可以进行如下分类:

  • 稳定:冒泡排序、插入排序、归并排序、基数排序
  • 不稳定:选择排序、希尔排序、堆排序、计数排序、快速排序
  • 不确定:桶排序、外排序

二、初级排序算法

初级排序算法是指冒泡排序插入排序选择排序

初级排序算法时间复杂度高,很少会在项目中直接使用,但是初级排序算法的算法思想是其他排序算法的基础,我们可以做了解,以此来对比出其他排序算法的高效性。

// 冒泡排序
// 每次遍历都将最值移动到数组末端
// 时间复杂度:O(N^2)
void BubbleSort(std::vector<int>& arr) {
    int n = arr.size();
    for (int i = 0; i < n-1; i++) {
        bool swapped = false;
        for (int j = 0; j < n-i-1; j++) {
            if (arr[j] > arr[j+1]) {
                std::swap(arr[j], arr[j+1]);
                swapped = true;
            }
        }
        if (!swapped) {
            break;
        }
    }
}
// 插入排序
// 每次遍历都将当前元素往前进行比较,找到它适合插入的位置
// 时间复杂度和数组的原始有序度有关,为 O(N) ~ O(N^2)
void InsertSort(std::vector<int>& arr) {
    int n = arr.size();
    for (int i = 1; i < n; i++) {
        int key = arr[i];
        int j = i - 1;
        while (j >= 0 && arr[j] > key) {
            arr[j+1] = arr[j];
            j = j - 1;
        }
        arr[j+1] = key;
    }
}
// 选择排序
// 每次遍历会找到最小值和最大值将其放入数组的最前端和最后端
// 只是简单实现的话,可以每次遍历只选择一个最值进行交换
// 同时选择最小值和最大值进行交换,提高了效率
// 时间复杂度:O(N^2)
void SelectSort(std::vector<int>& arr) {
    int n = arr.size();
    for (int i = 0; i < n / 2; i++) {
        int minIndex = i;
        int maxIndex = i;
        
        for (int j = i + 1; j < n - i; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j;
            }
            if (arr[j] > arr[maxIndex]) {
                maxIndex = j;
            }
        }

        if (minIndex != i) {
            std::swap(arr[i], arr[minIndex]);
        }
        if (maxIndex == i) {
            maxIndex = minIndex;
        }
        if (maxIndex != n - i - 1) {
            std::swap(arr[n - i - 1], arr[maxIndex]);
        }
    }
}

// void SelectionSort(std::vector<int>& arr) {
//     int n = arr.size();
//     for (int i = 0; i < n-1; i++) {
//         int minIndex = i;
//         for (int j = i+1; j < n; j++) {
//             if (arr[j] < arr[minIndex]) {
//                 minIndex = j;
//             }
//         }
//         std::swap(arr[i], arr[minIndex]);
//     }
// }

三、进阶排序算法

进阶排序算法是指在初级排序算法上进行了升级,从而实现的算法,如:希尔排序堆排序

希尔排序是插入排序的升级,堆排序是选择排序的升级

插入排序的时间复杂度受原始数组有序度的影响,所以希尔排序的核心思想就是先提高原始数组的有序度,然后再采用插入排序,所以对于希尔排序的具体实现就是先将原始数组的元素按照一个间隔进行分组,先确保每个分组的有序,最后不断缩小这个间隔,最后以此间隔为1,那么就是在进行插入排序了,这既是预排序机制。

堆排序利用二叉树的思想来实现对于数组最值的寻找,在进行升序排序的时候建大根堆,在进行降序排序的时候建小根堆,在建堆的时候,从后往前的父节点进行向下调整,在进行排序的时候,将最值范围内最后的元素交换,再不断降低排序范围从根节点往下进行调整。

堆排序常常用于解决Top-K的问题,若要从海量的数据中寻找K个最大值,我们可以建立一个空间复杂度为O(1)的小根堆,然后遍历海量数据,只要出现比堆顶元素大的数据,则删去堆顶元素,该数据入堆,时间复杂度是O(N)。

// 希尔排序
// 时间复杂度无法准确计算,在O(N)~O(N^2)之间,但远低于O(N^2)
void ShellSort(std::vector<int>& arr) {
    int n = arr.size();
    for (int gap = n / 2; gap > 0; gap /= 2) {
        for (int i = gap; i < n; i++) {
            int temp = arr[i];
            int j;
            for (j = i; j >= gap && arr[j - gap] > temp; j -= gap) {
                arr[j] = arr[j - gap];
            }
            arr[j] = temp;
        }
    }
}
// 堆排序
// 向下调整可以采用循环或者递归都可以
// 时间复杂度:O(N * log N)
void DownAdjust(int* arr, int parent, int n) {
	int child = parent * 2 + 1;
	while (child < n) {
		if (child + 1 < n && arr[child] < arr[child + 1])
			child++;
		if (arr[parent] < arr[child]) {
			Swap(&arr[parent], &arr[child]);
			parent = child;
			child = child * 2 + 1;
		}
		else {
			break;
		}
	}
}
 
void HeapSort(int* arr, int n) {
	int parent = (n - 2) / 2;	// 最后一个节点的父节点
	while (parent >= 0) {
		DownAdjust(arr, parent, n);
		--parent;
	}
	while (--n) {
		Swap(&arr[0], &arr[n]);
		DownAdjust(arr, 0, n);
	}
}

四、分治思想排序

分治思想的排序是指归并排序快速排序,它们的算法逻辑受二分法影响。

归并排序和快速排序算法各有优缺点,分不清孰优孰劣,只是应用场景不同。

在排序算法中,通常将额外消耗掉内存空间视为空间复杂度,大多数排序算法不会消耗额外的内存空间,即空间复杂度为O(1),但是归并排序的空间复杂度为O(N),从内存损耗的角度来看,快速排序算法更优,但是归并排序是稳定的排序算法,从稳定性来说,归并排序更优。

归并排序是先将数组无限分割,然后再将一块块分割后的数据进行填入额外开辟的空间中,再用额外空间中已经合并好的有序数据对原数组进行copy覆盖,先无限分割、再合并为一,最后实现了数组的排序。

void __MergeSort(int* arr, int begin, int end, int* tmp) {
	if (begin >= end)
		return;
 
	// 递归,先将数组无限分割,直到每个子数列的长度小于等于2
	int mid = (begin + end) / 2;
	_MergeSort(arr, begin, mid, tmp);
	_MergeSort(arr, mid + 1, end, tmp);
 
	int leftBegin = begin;
	int leftEnd = mid;
	int rightBegin = mid + 1;
	int rightEnd = end;
 
	int pos = begin;
	while (leftBegin <= leftEnd && rightBegin <= rightEnd) {
		// 从前往后同步遍历两个子数列,将相对较小的值先写入tmp中
		if (arr[leftBegin] < arr[rightBegin])
			tmp[pos++] = arr[leftBegin++];
		else
			tmp[pos++] = arr[rightBegin++];
	}
 
	// 将还没遍历完的子数列的值一次性写入tmp中
	while (leftBegin <= leftEnd) {
		tmp[pos++] = arr[leftBegin++];
	}
	while (rightBegin <= rightEnd) {
		tmp[pos++] = arr[rightBegin++];
	}
 
	// 内存数据copy,将临时存储有序子数列的tmp数组的值写入arr对应位置
	memcpy(arr + begin, tmp + begin, sizeof(int) * (end - begin + 1));
}
 
void MergeSort(int* arr, int n) {
	int* tmp = (int*)malloc(sizeof(int) * n);
	__MergeSort(arr, 0, n - 1, tmp);
	free(tmp);
	tmp = NULL;
}

快速排序的思想是找到一个关键Key值,每一次遍历都将比Key值小的数据放在Key左边,比Key值大的数据放在Key值右边,然后通过递归对Key值左右两边的子数组用同样的方法进行排序,最终实现了数组的排序。但是当子数组范围已经很小的时候,此时再通过递归调用的效率损耗是很大的,而且此时的数组有序度已经相当高了,所以归并排序可以配合着插入排序使用,即将子数组分割到一定的范围后,就不再分治,而是直接调用插入排序算法。

快速排序算法有多种实现方式,如Hoare法挖坑法前后指针法非递归法。虽然快排有多种实现方式,但是他们的算法原理是一样的。

// Hoare法
// 选左边为key值,则右边先走,最后左右相遇时比key值小
// 选右边为key值,则左边先走,最后左右相遇时比key值大
int __Hoare(std::vector<int>& arr, int begin, int end) {
    int ikey = begin;
    while (begin < end) {
        while (arr[end] >= arr[ikey] && end > begin) {
            --end;
        }
        while (arr[begin] <= arr[ikey] && begin < end) {
            ++begin;
        }
        std::swap(arr[begin], arr[end]);
    }
    swap(arr[ikey], arr[end]);
    return end;
}

void QuickSort(std::vector<int>& arr, int begin, int end) {
    if (begin >= end)
        return;

    int ikey = __Hoare(arr, begin, end);
    QuickSort(arr, begin, ikey - 1);
    QuickSort(arr, ikey + 1, end);
}

// 挖坑法
int __DigHole(std::vector<int>& arr, int begin, int end) {
    int key = arr[begin];
    while (begin < end) {
        while (arr[end] >= key && end > begin) {
            --end;
        }
        arr[begin] = arr[end];

        while (arr[begin] <= key && begin < end) {
            ++begin;
        }
        arr[end] = arr[begin];
    }
    arr[end] = key;
    return end;
}

void QuickSort(std::vector<int>& arr, int begin, int end) {
    if (begin >= end)
        return;

    int ikey = __DigHole(arr, begin, end);
    QuickSort(arr, begin, ikey - 1);
    QuickSort(arr, ikey + 1, end);
}

// 前后指针法
// 三数取中是快速排序算法的优化方案,目的是为了避免最坏情况的发送
// 除了三数取中,还可以在将子数组分到足够的小的范围的时候采用插入排序进行优化
// 时间复杂度:O(N * log N)
int __MidIndex(vector<int>& arr, int r, int m, int l) {
    if ((arr[r] - arr[m]) * (arr[m] - arr[l]) >= 0)
        return m;
    else if ((arr[m] - arr[r]) * (arr[r] - arr[l]) >= 0)
        return r;
    else
        return l;
}

int __Ptrptr(std::vector<int>& arr, int begin, int end) {
    int key = arr[begin];
    int prev = begin;
    int cur = begin + 1;
    while (cur <= end) {
        if (arr[cur] < key && ++prev != cur) {
            std::swap(arr[prev], arr[cur]);
        }
        ++cur;
    }
    std::swap(arr[begin], arr[prev]);
    return prev;
}

void QuickSort(std::vector<int>& arr, int begin, int end) {
    if (begin >= end)
        return;

    int ikey = (arr, 0, (begin + end) / 2, end);
    std::swap(arr[begin], arr[ikey]);

    ikey = __Ptrptr(arr, begin, end);
    QuickSort(arr, begin, ikey - 1);
    QuickSort(arr, ikey + 1, end);
}
// 非递归快排
// 在某些极端的情况下,大量的递归会导致堆栈移除,所以需要使用非递归快排算法
// 非递归快排的本质是通过栈或队列来实现对分治的下标控制
// 无论是Hoare法、挖坑法、前后指针法都可以改写为非递归形式
void QuickSort(std::vector<int>& arr, int begin, int end) {
    if (begin >= end)
        return;

    int ikey = (arr, 0, (begin + end) / 2, end);
    std::swap(arr[begin], arr[ikey]);

    std::stack<std::pair<int, int>> stk;
    stk.push(std::make_pair(begin, end));
    while (!stk.empty()) {
        int b = stk.top().first;
        int e = stk.top().second;
        stk.pop();

        //ikey = __Hoare(arr, b, e);
        //ikey = __DigHole(arr, b, e);
        ikey = __Ptrptr(arr, b, e);

        if (ikey - 1 > b)
            stk.push(std::make_pair(b, ikey - 1));
        if (ikey + 1 < e)
            stk.push(std::make_pair(ikey + 1, e));
    }
}

五、哈希思想排序

哈希思想的排序是指计数排序和基数排序,哈希思想的排序算法时间复杂度都非常低,但是他们都有一定的局限性,使用计数排序需要数组中的最大值和最小值差值不能太大,否则空间损耗很大,使用基数排序需要明确知道最大值的位数。

// 计数排序
// 时间复杂度取决于最值之差
void CountSort(std::vector<int>& arr) {
    int max = *std::max_element(arr.begin(), arr.end());
    int min = *std::min_element(arr.begin(), arr.end());
    int range = max - min + 1;

    std::vector<int> count(range);
    
    for (int i = 0; i < arr.size(); ++i) {
        count[arr[i] - min]++;
    }

    int j = 0;
    for (int i = 0; i < range; ++i) {
        while (count[i] != 0) {
            arr[j++] = i + min;
            count[i] -= 1;
        }
    }
}
// 基数排序
// 计数排序可以是做一种特殊的桶排序
// 时间复杂度为O(K * N)
// 设数据最大位数
#define K 3		
 
// 取模的类别数(桶数、基数)
#define RADIX 10
 
// 桶
queue<int> _q[RADIX];
 
// 获取val值对应桶的位置,即哈希映射
int GetPos(int a, int k)
{
	int pos = a % RADIX;
	while (k--)
	{
		a /= RADIX;
		pos = a % RADIX;
	}
	return pos;
} 
 
// 分发数据,将数组数据按模分发到哈希桶上
void Distribute(int* arr, int left, int right, int k)
{
	for (int i = left; i < right; ++i)
	{
		int pos = GetPos(arr[i], k);
		_q[pos].push(arr[i]);
	}
} 
 
// 收集数据,根据队列的特性从哈希桶上收集数据,存入数组
void Collect(int* arr)
{
	int pos = 0;
	for (int i = 0; i < RADIX; ++i)
	{
		while (!_q[i].empty())
		{
			arr[pos++] = _q[i].front();
			_q[i].pop();
		}
	}
} 
 
void RadixSort(int* arr, int n)
{
	int k = 0;
	while (k < K)
	{
		Distribute(arr, 0, n, k++);
		Collect(arr);
	}
}

六、分割思想排序

分割思想排序是指桶排序外排序

桶排序和外排序通常应用于理大量数据的排序,因为数据量太大而内存存不下,所以需要先将数据分割再进行排序。桶排序利用分布式思想,先将数据分割在多个桶中,每个桶中的数据量差不多,然后对每个桶中的数据进行排序最后再将数据合并,外排序是通过将数据存储在磁盘上来缓解内存不足的问题,通过内存与磁盘间进行多次数据的交换实现对全部数据的排序。

通常情况下,桶排序是稳定的,它在每个桶中的排序算法会保证元素间的相对顺序,最后的合并过程也会保持稳定性,但是却并不绝对,因为无论是桶排序还是外排序,其稳定性都取决于其内部子数列的排序算法的选择。

// 桶排序
void BucketSort(std::vector<float>& arr) {
    int n = arr.size();
    std::vector<std::vector<float>> buckets(n);

    // 将元素分布到桶中
    // 将元素分布到桶中的算法由程序员自己决定,根据数据集决定
    // 将数值越小的数,放在越靠前的桶中
    for (int i = 0; i < n; i++) {
        float bucket_index = arr[i] / 10;
        if (bucket_index < 0)
            bucket_index = 0;
        else if (bucket_index >= n)
            bucket_index = n - 1;
        buckets[bucket_index].push_back(arr[i]);
    }

    // 对每个非空的桶进行排序
    for (int i = 0; i < n; i++) {
        if (!buckets[i].empty()) {
            std::sort(buckets[i].begin(), buckets[i].end());
        }
    }

    // 将排序后的元素放回原数组
    int index = 0;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < buckets[i].size(); j++) {
            arr[index++] = buckets[i][j];
        }
    }
}
// 外排序
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <string>

const int MAX_MEMORY_SIZE = 100; // 假设内存最多可以容纳100个元素

void externalSort(const std::string& inputFileName, const std::string& outputFileName) {
    // 读取数据并分块排序
    // ...(省略读取和排序步骤)

    // 文件归并
    // ...(省略文件归并步骤)
}

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

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

相关文章

【兔子机器人】实现从初始状态到站立

一、遥想星空up主的方法 由于我有卡位结构&#xff0c;无法做到劈腿&#xff0c;而且底盘也不一样&#xff0c;无法使用此方法 但是其代码思想是可以借鉴的。 参考视频&#xff1a; 【【开源啦&#xff01;】无刷轮腿平衡机器人】 【精准空降到 01:16】 https://www.bilibili…

C++类和对象一

#include <iostream> using namespace std;//设计一个学生类 class CStudent {public: //公有成员void InputData(){cout << "请输入学号";cin >> sno;cout << "请输入姓名";cin >> sname;cout << "请输入分…

RabbitMq踩坑记录

1、连接报错&#xff1a;Broker not available; cannot force queue declarations during start: java.io.IOException 2.1、原因&#xff1a;端口不对 2.2、解决方案&#xff1a; 检查你的连接配置&#xff0c;很可能是你的yml里面的端口配置的是15672&#xff0c;更改为5672即…

第110讲:Mycat实践指南:指定Hash算法分片下的水平分表详解

文章目录 1.应用指定Hash算法分片的概念2.使用应用指定Hash算法分片对某张表进行水平拆分2.1.在所有的分片节点中创建表结构2.2.配置Mycat实现应用指定Hash算法分片的水平分表2.2.1.配置Schema配置文件2.2.2.配置Rule分片规则配置文件2.2.3.配置Server配置文件2.2.4.重启Mycat …

交换机/路由器的存储介质-思科

交换机/路由器的存储介质-思科 本文主要介绍网络设备的存储介质组成。 RAM(random-accessmemory&#xff0c;随机访问存储器) RAM中内容断电丢失&#xff0c;主要用于运行操作系统、运行配置文件、IP 路由表:、ARP 缓存、数据包缓存区。 ROM(read-only memory&#xff0c;只…

多做【二叉搜索树】【数组转化为树】Leetcode 108. 将有序数组转换为二叉搜索树

【二叉搜索树】【数组转化为树】Leetcode 108. 将有序数组转换为二叉搜索树 解法1 递归 ---------------&#x1f388;&#x1f388; 108. 将有序数组转换为二叉搜索树 题目链接&#x1f388;&#x1f388;------------------- 解法1 递归 给你一个整数数组 nums &#xff0…

【Vue2】组件通信

父子通信 父 -> 子 子 -> 父 props 校验 props: {校验的属性名: {type: 类型, // Number String Boolean ...required: true, // 是否必填default: 默认值, // 默认值validator (value) {// 自定义校验逻辑return 是否通过校验}} },data 的数据是自己的 → 随便改pr…

【leetcode+深度/广度优先搜索】841. 钥匙和房间 (DFS,BFS)

leetcode-cn&#xff1a;leetcode面试75道精华&#xff1a;https://leetcode.cn/studyplan/leetcode-75/ 841.钥匙和房间&#xff1a;https://leetcode.cn/problems/keys-and-rooms/description/ 一、题目&#xff1a;841. 钥匙和房间 有 n 个房间&#xff0c;房间按从 0 到 n…

面试经典-16- 环形链表

题目 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置&#…

【数学建模】熵权法

之前我们学了层次分析法和topsis法&#xff0c;但是主观性十分强&#xff0c;有没有科学的方法得出权重呢&#xff1f;今天&#xff0c;我们来学习熵权法&#xff01; 基本概念&#xff1a; 熵权法&#xff0c;物理学名词&#xff0c;按照信息论基本原理的解释&#xff0c;信息…

尼伽OLED透明屏闪耀第24届中国零售业博览会,引领零售行业革新

2024 CHINA SHOP 第二十四届中国零售业博览会 3.13-15 上海 3.13-15日&#xff0c;第24届中国零售业博览会盛大开幕&#xff0c;起立科技&#xff08;旗下品牌&#xff1a;起鸿、尼伽&#xff09;携其自主研发的30寸OLED透明屏和移动AI透明屏机器人惊艳亮相&#xff0c;成为展…

租房网站|基于springboot框架+ Mysql+Java+B/S架构的租房网站设计与实现(可运行源码+数据库+设计文档+部署说明)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 目录 前台功能效果图 用户功能模块 管理员功能登录前台功能效果图 系统功能设计 数据库E-R图设计 lunwen参…

Redis-复制功能

0 序言 复制功能是Redis提供的多机功能中最基础的一个&#xff0c;这个功能是通过主从复制&#xff08;master-slave replication&#xff09;模式实现的&#xff0c;它允许用户为存储着目标数据库的服务器创建出多个拥有相同数据库副本的服务器&#xff0c;其中存储目标数据库…

【C++】stack、queue模拟实现+仿函数

stack、queue模拟实现仿函数 stack定义stack模拟实现 queue定义queue模拟实现 priority_queue定义priority_queue模拟实现 deque定义底层分析 容器适配器定义种类 仿函数控制类里面数据的比较逻辑回调函数仿函数两者区别 铁汁们&#xff0c;今天给大家分享一篇stack、queue模拟…

Kubernetes operator系列:webhook 知识学习【更新中】

云原生学习路线导航页&#xff08;持续更新中&#xff09; 本文是 Kubernetes operator学习 系列文章&#xff0c;本节会对 kubernetes webhook 知识进行学习 本文的所有代码&#xff0c;都存储于github代码库&#xff1a;https://github.com/graham924/share-code-operator-st…

【大厂AI课学习笔记NO.80】深度学习行业人才能力图谱

深度学习领域的就业岗位及所需关键技术、工具、能力分析 深度学习作为人工智能领域的一个重要分支&#xff0c;近年来得到了飞速的发展。随着技术的不断进步和应用场景的不断拓展&#xff0c;深度学习领域的就业岗位也日益增多。本文将从领军人才、产业研发人才、应用开发人才…

Lombok原理及实例(Java) - 简化JavaBean开发

Lombok 1.作用:简化javabean开发 2.使用:a.下插件 -> 如果是idea2022不用下载了,自带b.导lombok的jar包c.修改设置 1.lombok介绍 Lombok通过增加一些“处理程序”&#xff0c;可以让javabean变得简洁、快速。 Lombok能以注解形式来简化java代码&#xff0c;提高开发效…

HttpServer整合模块设计与实现(http模块五)

目录 类功能 类定义 类实现 编译测试 源码路标 类功能 类定义 // HttpServer模块功能设计 class HttpServer { private:using Handler std::function<void(const HttpRequest &, HttpResponse &)>;std::unordered_map<std::string, Handler> _get_r…

JS实现漂浮广告案例

<!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>漂浮广告</title><style>#link {…

每日一练:LeeCode-209、长度最小的子数组【滑动窗口+双指针】

每日一练&#xff1a;LeeCode-209、长度最小的子数组【滑动窗口双指针】 思路暴⼒解法滑动窗口 本文是力扣 每日一练&#xff1a;LeeCode-209、长度最小的子数组【滑动窗口双指针】 学习与理解过程&#xff0c;本文仅做学习之用&#xff0c;对本题感兴趣的小伙伴可以出门左拐 L…