算法编程题-排序

news2024/11/22 19:48:30

算法编程题-排序

    • 比较型排序算法
      • 冒泡排序
      • 选择排序
      • 插入排序
      • 希尔排序
      • 堆排序
      • 快速排序
      • 归并排序
    • 非比较型排序算法
      • 计数排序
      • 基数排序

本文将对七中经典比较型排序算法进行介绍,并且给出golang语言的实现,还包括基数排序、计数排序等非比较型的算法的介绍和实现。

比较型排序算法

所谓的比较型排序算法就是算法中会使用数据之间的比较,只能数组保存的是能相关比较大小的数据即可使用该类算法,相比于非比较型排序算法适用面更广。
在实现上进行了一定的封装,支持泛型和自定义排序规则,默认传入一个比较函数less,按照less指定的小于关系进行“从小到大”排序。抽象接口代码如下:

type Sorter[T any] struct {
	less func(item1, item2 T) bool
}

func NewSorter[T any](less func(item1, item2 T) bool) *Sorter[T] {
	return &Sorter[T]{less: less}
}

冒泡排序

冒泡排序如其名,就是排序的过程和冒泡有点像。一个气泡从水底浮向水面,其体积是越来越大的。那么同理,在排序的过程中,也可以让一个个大的元素浮上去,从而完成整个的排序。代码实现如下:

// BubbleSort 冒泡排序,时间复杂度:O(n^2) 空间复杂度:O(1), 稳定
func (s *Sorter[T]) BubbleSort(arr []T) {
	n := len(arr)
	for i := 0; i < n; i++ {
		var bubbleFlag bool // 是否有冒泡
		for j := i; j+1 < n; j++ {
			if s.less(arr[j+1], arr[j]) {
				arr[j], arr[j+1] = arr[j+1], arr[j]
				bubbleFlag = true
			}
		}
		if !bubbleFlag { // 无冒泡,说明已经排序完成,提前退出
			break
		}
	}
}

冒泡排序时间复杂度是 O ( n 2 ) O(n^2) O(n2),空间复杂度为 O ( 1 ) O(1) O(1)。其是一种稳定的排序算法。在实现上可以记录一个标志,表明此一轮有没有发生冒泡,如果没有,说明数组已经完全有序,可以以前退出。

选择排序

选择排序同样也是人如其名,在每一轮中,选择剩余数组中的最小值,放入一个位置,经过n轮,完成排序。实现代码如下:

// SelectSort 选择排序,时间复杂度:(n ^ 2), 空间复杂度:O(1),不稳定
func (s *Sorter[T]) SelectSort(arr []T) {
	n := len(arr)
	for i := 0; i < n; i++ {
		minPtr := i
		for j := i + 1; j < n; j++ {
			if s.less(arr[j], arr[minPtr]) {
				minPtr = j
			}
		}
		arr[minPtr], arr[i] = arr[i], arr[minPtr]
	}
}

选择排序时间复杂度 O ( n 2 ) O(n^2) O(n2),空间复杂度为 O ( 1 ) O(1) O(1),是一种不稳定的排序算法。

插入排序

插入排序的排序过程为:维护一个有序序列,然后将待排序的数字找到一个合适的位置,然后插入进去,这样还是一个有序序列,依次将所有元素完成这一个操作,即可完成数组的排序。实现代码如下:

// InsertSort 插入排序,时间复杂度:O(n^2) 空间复杂度:O(1), 稳定
func (s *Sorter[T]) InsertSort(arr []T) {
	n := len(arr)
	for i := 1; i < n; i++ {
		for j := i; j > 0; j-- {
			if s.less(arr[j], arr[j-1]) {
				arr[j], arr[j-1] = arr[j-1], arr[j]
			} else {
				break
			}
		}
	}
}

插入排序的时间复杂度平均为 O ( n 2 ) O(n^2) O(n2),但是对于一个基本有序的数组进行排序,时间复杂度可以达到 O ( n ) O(n) O(n),空间复杂度为 O ( 1 ) O(1) O(1),是一种稳定的排序算法。
优化插入排序,可以从两个方面入手,减少找位置的时间或者移动元素的时间,每一轮这两个的时间都是 O ( n ) O(n) O(n)级别的,前者可以通过二分查找来优化,后者可以通过链表来优化,但是如何同时优化呢?笔者认为可以使用跳表,这样可以将插入排序的平均时间复杂度优化到 O ( n l o g n ) O(nlogn) O(nlogn),但是缺点在于实现复杂,且空间开销较大,相比于快速排序堆排序等,有点得不偿失。

希尔排序

希尔排序其实就是对于插入排序的优化,前文提到,插入排序在基本有序的数组排序效率比较高,那么可以考虑对于数组的子序列进行排序,具体的思路就是将子数组分为多个子序列,在每一轮中只对子序列内部进行插入排序。子序列分组的规则是每隔gap个的元素作为一个子序列,gap值在轮数下不断减小,直到为一后相当于是对全部数据进行插入排序,由于此时数组已经基本有序,所以最后一轮插入排序的效率很高。

// 希尔排序,时间复杂度: O(n^(3 / 2)) 空间复杂度:O(1), 不稳定
func (s *Sorter[T]) ShellSort(arr []T) {
	n := len(arr)
	gap := n >> 1
	for gap > 0 {
		for i := 0; i < gap; i++ {
			for j := i; j < n; j += gap {
				for k := i + gap; k < n; k += gap {
					if s.less(arr[k], arr[k-gap]) {
						arr[k], arr[k-gap] = arr[k-gap], arr[k]
					}
				}
			}
		}
		gap >>= 1
	}
}

希尔排序的时间复杂度为 O ( n 3 / 2 ) O(n ^ {3 / 2}) O(n3/2),但是最坏情况下也可能恶化成 O ( n 2 ) O(n^2) O(n2),空间复杂度为 O ( 1 ) O(1) O(1),是一种不稳定的排序算法,适用于中等规模的数据集排序。

堆排序

堆排序就是基于堆这种数据结构的性质,往往使用一个最小堆,将堆顶的元素取出,然后将最后一个元素放到堆顶后,从上到下进行调整,重复这一个过程,就能完成数组的排序。

type Heap[T any] struct {
	less   func(item1, item2 T) bool
	array  []T
	length int // 标识实际长度
}

// NewHeap 构建一个空的堆
func NewHeap[T any](less func(item1, item2 T) bool) *Heap[T] {
	return &Heap[T]{less: less, array: make([]T, 0), length: 0}
}

// NewHeapWithArr 根据数组构建一个堆
func NewHeapWithArr[T any](less func(item1, item2 T) bool, arr []T) *Heap[T] {
	h := &Heap[T]{less: less, array: arr, length: len(arr)}
	for i := 1; i < len(arr); i++ {
		h.siftUp(i)
	}
	return h
}

// Push 往堆h中插入一个元素
func (h *Heap[T]) Push(v T) {
	h.pushBack(v)
	h.siftUp(h.length - 1)
}

// Top 返回堆顶的元素
func (h *Heap[T]) Top() T {
	return h.array[0]
}

// Pop 移除堆顶的元素并返回
func (h *Heap[T]) Pop() T {
	ret := h.array[0]
	h.array[0] = h.array[h.length-1]
	h.length--
	h.siftDown(0)
	return ret
}

func (h *Heap[T]) ToArr() []T {
	return h.array
}

func (h *Heap[T]) IsEmpty() bool {
	return h.length == 0
}

// pushBack 在尾部插入一个元素
func (h *Heap[T]) pushBack(v T) {
	if len(h.array) == h.length {
		h.array = append(h.array, v)
	} else {
		h.array[h.length] = v
	}
	h.length++
}

// siftUp 从pos位置处开始往上调整
func (h *Heap[T]) siftUp(pos int) {
	if pos < 0 || pos >= h.length {
		return
	}
	i := pos
	j := (pos - 1) / 2
	for j >= 0 && h.less(h.array[i], h.array[j]) {
		h.array[i], h.array[j] = h.array[j], h.array[i]
		i = j
		j = (i - 1) / 2
	}
}

// siftDown 从pos位置处开始往下调整
func (h *Heap[T]) siftDown(pos int) {
	if pos < 0 || pos >= len(h.array) {
		return
	}
	i := 0
	j1 := 2*i + 1
	j2 := 2*i + 2
	for j1 < h.length {
		if h.less(h.array[j1], h.array[i]) && ((j2 >= h.length) || h.less(h.array[j1], h.array[j2])) {
			h.array[i], h.array[j1] = h.array[j1], h.array[i]
			i = j1
		} else if h.less(h.array[j2], h.array[i]) {
			h.array[i], h.array[j2] = h.array[j2], h.array[i]
			i = j2
		} else {
			break
		}
		j1 = 2*i + 1
		j2 = 2*i + 2
	}
}

// HeapSort 堆排序,时间复杂度:O(nlogn), 空间复杂度:O(1), 不稳定
func (s *Sorter[T]) HeapSort(arr []T) {
	h := NewHeapWithArr(s.less, arr)
	k := len(arr) - 1
	for !h.IsEmpty() {
		arr[k] = h.Pop()
		k--
	}
	for i := 0; i < len(arr) / 2; i++ {
		arr[i], arr[len(arr) - 1 - i] = arr[len(arr) - 1 - i], arr[i]
	}
}

堆排序的时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn),空间复杂度为 O ( n ) O(n) O(n),是一种不稳定的排序算法,适用于大数据量下且内存资源相对宝贵的条件下。

快速排序

快速排序是一种基于分制的思路,对于一个数组,从中选择一个基准点,以这个基准点,小于的数交换到左边取,大于的数交换到右边去,然后递归地对左边和右边的子数组进行同样的处理,从而完成整个排序过程。

// 快速排序实现,时间复杂度:O(nlogn), 空间复杂度:O(1), 不稳定
func (s *Sorter[T]) QuickSort(arr []T) {
	s.quickSortV1(arr, 0, len(arr)-1)
}

// 递归形式的排序
func (s *Sorter[T]) quickSortV1(arr []T, left, right int) {
	if left >= right { // 递归终点
		return
	}
	base := arr[left]
	basePtr := left
	i := left + 1
	for i <= right {
		if s.less(arr[i], base) {
			basePtr++
			if basePtr != i {
				arr[basePtr], arr[i] = arr[i], arr[basePtr]
			}
		}
		i++
	}
	arr[left] = arr[basePtr]
	arr[basePtr] = base
	s.quickSortV1(arr, left, basePtr-1)
	s.quickSortV1(arr, basePtr+1, right)
}

以上实现版本的快速排序时间复杂度是 O ( n l o g n ) O(nlogn) O(nlogn),空间复杂度为 O ( 1 ) O(1) O(1),是一种不稳定的排序算法,但是最坏情况下时间复杂度也会恶化到 O ( n 2 ) O(n^2) O(n2)。比如上面的实现在数组基本有序的情况下,会化身为时间刺客,如下图。

在这里插入图片描述
一种常见的优化手段是从数组中取三个数字,然后以这三个数字的中位数作为基准点,如下为相关代码实现:

// quickSortV3优化实现,基准取头尾中三数中的平均数
func (s *Sorter[T]) quickSortV3(arr []T, left, right int) {
	if left >= right { // 递归终点
		return
	}
	s.adjustBase(arr, left, right)
	base := arr[left]
	basePtr := left
	i := left + 1
	for i <= right {
		if s.less(arr[i], base) {
			basePtr++
			if basePtr != i {
				arr[basePtr], arr[i] = arr[i], arr[basePtr]
			}
		}
		i++
	}
	arr[left] = arr[basePtr]
	arr[basePtr] = base
	s.quickSortV3(arr, left, basePtr-1)
	s.quickSortV3(arr, basePtr+1, right)
}

// adjustBase 调整基准值,将头尾中三数中的平均数放在头部作为基准
func (s *Sorter[T]) adjustBase(arr []T, left, right int) {
	basePtrs := []int{left, right, (left + right) / 2}
	s1 := NewSorter(func(i, j int) bool {
		return s.less(arr[i], arr[j])
	})
	s1.InsertSort(basePtrs)
	arr[left], arr[basePtrs[1]] = arr[basePtrs[1]], arr[left]
}

但是以上方法对于一个全是相同数字的数组还是会恶化成 O ( n 2 ) O(n^2) O(n2)
在某些面试中,可能有些面试官要求实现一些递归算法的非递归版本,比如实现非递归版本的快速排序。递归在编程语言中的实质就是借助栈来实现的,所以这种题目本质上就是在模拟递归,代码实现如下:

// 非递归实现,借助栈来模拟递归
func (s *Sorter[T]) quickSortV2(arr []T, left, right int) {
	stack := NewStack[[2]int]()
	stack.Push([2]int{left, right})
	for !stack.IsEmpty() {
		state := stack.Pop()
		left, right := state[0], state[1]
		if left >= right {
			continue
		}
		base := arr[left]
		basePtr := left
		i := left + 1
		for i <= right {
			if s.less(arr[i], base) {
				basePtr++
				if basePtr != i {
					arr[basePtr], arr[i] = arr[i], arr[basePtr]
				}
			}
			i++
		}
		arr[left] = arr[basePtr]
		arr[basePtr] = base
		stack.Push([2]int{left, basePtr - 1})
		stack.Push([2]int{basePtr + 1, right})
	}
}

实际上,也可以不使用栈,使用队列或者其他的数据结构都是可以的。

归并排序

归并排序的重点在于归并上,对于两个已经有序的数组而言,可以合并到一个有序的数组中,时间复杂度为 O ( n ) O(n) O(n),这样,最小的段即一个数的数组,必然是有序的,小段合成大段,最后合并完成整个数组的排序。

// MergeSort 归并排序,时间复杂度:O(nlogn), 空间复杂度:O(n), 稳定
func (s *Sorter[T]) MergeSort(arr []T) []T {
	return s.mergeSortV1(arr)
}

// 递归形式的归并排序
func (s *Sorter[T]) mergeSortV1(arr []T) []T {
	if len(arr) <= 1 { // 递归终点
		return arr
	}
	// 递归过程
	leftArr := s.mergeSortV1(append([]T(nil), arr[:len(arr)/2]...))
	rightArr := s.mergeSortV1(append([]T(nil), arr[len(arr)/2:]...))
	// 合并
	i := 0
	j := 0
	k := 0
	for i < len(leftArr) || j < len(rightArr) {
		if i >= len(leftArr) || (j < len(rightArr) && s.less(rightArr[j], leftArr[i])) {
			arr[k] = rightArr[j]
			j++
			k++
		} else {
			arr[k] = leftArr[i]
			i++
			k++
		}
	}
	return arr
}

归并排序也可以实现非递归的形式,如下:

// 非递归形式的归并排序
func (s *Sorter[T]) mergeSortV2(arr []T) []T {
	segLen := 1 // 比较的段长
	for segLen < len(arr) {
		for p := 0; p < len(arr); p += 2 * segLen {
			leftArr := append([]T(nil), arr[p:min(p+segLen, len(arr))]...)
			rightArr := append([]T(nil), arr[min(p+segLen, len(arr)):min(p+2*segLen, len(arr))]...)
			// 合并
			i := 0
			j := 0
			k := 0
			for i < len(leftArr) || j < len(rightArr) {
				if i >= len(leftArr) || (j < len(rightArr) && s.less(rightArr[j], leftArr[i])) {
					arr[p+k] = rightArr[j]
					j++
					k++
				} else {
					arr[p+k] = leftArr[i]
					i++
					k++
				}
			}
		}
		segLen *= 2
	}
	return arr
}

归并排序时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn),空间复杂度为 O ( n ) O(n) O(n),是一种稳定的排序算法。归并排序适用于大数据量且要求稳定的场景,毕竟同时间复杂度的排序算法快速排序和堆排序都是不稳定的。

非比较型排序算法

可以注意到以上的排序算法都需要通过比较元素的大小来交换位置或者其他的操作,这类算法统称为比较型排序算法。另外一类非比较型排序算法,不需要比较大小,但是其适用面比较小。

计数排序

所谓的计数排序就是维护一个数组,用来表示每一个元素出现的次数,然后遍历数组,将各个数字取出即可。

type IntSorter struct {
}

func NewIntSorter() *IntSorter {
	return &IntSorter{}
}

// 计数排序,时间复杂度:O(n+k) k为数据范围 空间复杂度:O(k) 稳定
// 适用于数据范围不大的情况下
func (s *IntSorter) CountSort(arr []int64) {
	minv := arr[0]
	maxv := arr[0]
	for _, item := range arr {
		minv = min(minv, item)
		maxv = max(maxv, item)
	}
	counts := make([]int64, maxv-minv+1)
	for _, item := range arr {
		counts[item-minv]++
	}
	k := 0
	for i := int64(0); i < maxv-minv+1; i++ {
		for j := int64(0); j < counts[i]; j++ {
			arr[k] = i + minv
			k++
		}
	}
}

计数排序的时间复杂度为 O ( n ) O(n) O(n)级别,空间复杂度为 O ( m ) O(m) O(m),其中m为数组中最大数减去最小数,可以看到,计数排序只适用于整数,且最好数据比较集中。

基数排序

以整数的基数排序来说明这一个过程。由于整数的每一位只有十种可能,从0到9,那么可以建立十个桶,遍历数组,按照最低位对应的数字放到对应的桶中,然后再将所有数组按照0号桶收集起来,然后从数字的低第二位做重复的操作,直到最大数字的最高位。代码实现如下:

func (s *IntSorter) RadixSort(arr []int) {
	var newBuckets func() []*List[int] = func() []*List[int] {
		buckets := make([]*List[int], 10)
		for i := 0; i < 10; i++ {
			buckets[i] = NewList[int]()
		}
		return buckets
	}
	buckets := newBuckets()
	oldBuckets := newBuckets()
	for _, num := range arr {
		oldBuckets[num%10].AppendNodeTail(NewListNode[int](num/10, num))
	}
	flag := true // 停止标志
	for flag {
		flag = false
		for i := 0; i < 10; i++ {
			for node := oldBuckets[i].Begin(); node != oldBuckets[i].End(); node = node.Next {
				if node.Key != 0 {
					flag = true
				}
				buckets[node.Key%10].AppendNodeTail(NewListNode[int](node.Key/10, node.Val))
			}
		}
		oldBuckets = buckets
		buckets = newBuckets()
	}
	// 此时所有数据都在零号桶里
	k := 0
	for node := oldBuckets[0].Begin(); node != oldBuckets[0].End(); node = node.Next {
		arr[k] = node.Val
		k++
	}
}

基数排序的时间复杂度也大致在 O ( n m ) O(nm) O(nm)左右,对于整数可以认为是 O ( n ) O(n) O(n),空间复杂度为 O ( n ) O(n) O(n),适用于整数或者字符串等。

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

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

相关文章

Jenkins修改LOGO

重启看的LOGO和登录页面左上角的LOGO 进入LOGO存在的目录 [roottest-server01 svgs]# pwd /opt/jenkins_data/war/images/svgs [roottest-server01 svgs]# ll logo.svg -rw-r--r-- 1 jenkins jenkins 29819 Oct 21 10:58 logo.svg #jenkins_data目录是我挂载到了/opt目录&…

【MyBatisPlus·最新教程】包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段

文章目录 一、MyBatis-Plus简介二、快速入门1、环境准备2、将mybatis项目改造成mybatis-plus项目&#xff08;1&#xff09;引入MybatisPlus依赖&#xff0c;代替MyBatis依赖&#xff08;2&#xff09;配置Mapper包扫描路径&#xff08;3&#xff09;定义Mapper接口并继承BaseM…

云讷科技Kerloud无人飞车专利发布

云讷科技Kerloud无人飞车获得了“一种室内外两用的四旋翼无人飞车”的实用新型专利证书&#xff0c;作为科教社区第一款四旋翼飞车&#xff0c;这项技术结合了无人机和无人车的优势&#xff0c;提供了一种能够在多种环境下使用的多功能飞行器。 这项设计的优势如下&#xff…

Applied Intelligence投稿

一、关于手稿格式&#xff1a; 1、该期刊是一个二区的&#xff0c;模板使用Springer nature格式&#xff0c; 期刊投稿要求&#xff0c;详细期刊投稿指南&#xff0c;大部分按Soringernature模板即可&#xff0c;图片表格声明参考文献命名要求需注意。 2、参考文献&#xff…

Spark SQL大数据分析快速上手-完全分布模式安装

【图书介绍】《Spark SQL大数据分析快速上手》-CSDN博客 《Spark SQL大数据分析快速上手》【摘要 书评 试读】- 京东图书 大数据与数据分析_夏天又到了的博客-CSDN博客 Hadoop完全分布式环境搭建步骤-CSDN博客,前置环境安装参看此博文 完全分布模式也叫集群模式。将Spark目…

零基础上手WebGIS+智慧校园实例(1)【html by js】

请点个赞收藏关注支持一下博主喵&#xff01;&#xff01;&#xff01; 等下再更新一下1. WebGIS矢量图形的绘制&#xff08;超级详细&#xff01;&#xff01;&#xff09;&#xff0c;2. WebGIS计算距离&#xff0c; 以及智慧校园实例 with 3个例子&#xff01;&#xff01;…

[开源] 告别黑苹果!用docker安装MacOS体验苹果系统

没用过苹果电脑的朋友可能会对苹果系统好奇&#xff0c;有人甚至会为了尝鲜MacOS去折腾黑苹果。如果你只是想体验一下MacOS&#xff0c;这里有个更简单更优雅的解决方案&#xff0c;用docker安装MacOS来体验苹果系统。 一、项目简介 项目描述 Docker 容器内的 OSX&#xff08…

IDEA:2023版远程服务器debug

很简单&#xff0c;但是很多文档没有写清楚&#xff0c;wocao 一、首先新建一个远程jvm 二、配置 三、把上面的参数复制出来 -agentlib:jdwptransportdt_socket,servery,suspendn,address5005 四、然后把这串代码放到服务器中&#xff08;这里的0.0.0.0意思是所有IP都能访问&a…

卷积神经网络的padding是什么?如何计算?

文章目录 为什么需要padding&#xff1f;1.Valid Padding&#xff08;有效填充&#xff09;2.Same Padding&#xff08;相同填充&#xff09;2.1.如何计算padding&#xff1f;1. 计算总 padding2. 分配 padding&#xff1a; 2.2.举例子1. 步幅为 1 的 Same Padding2. 步幅不为 …

介绍一下strncmp(c基础)

strncmp是strcmp的进阶版 链接介绍一下strcmp(c基础)-CSDN博客 作用 比较两个字符串的前n位 格式 #include <string.h> strncmp (arr1,arr2,n); 工作原理&#xff1a;strcmp函数按照ACII&#xff08;字符编码顺序&#xff09;比较两个字符串。它从两个字符串的第一…

列出D3的所有交互方法,并给出示例

D3.js 提供了丰富的交互方法&#xff0c;可以用来增强图表的用户交互体验。以下是一些常用的交互方法及其示例&#xff1a; 1. 鼠标事件 on("mouseover", function) 用途: 当鼠标悬停在元素上时触发。示例:svg.selectAll(".bar").on("mouseover&qu…

丹摩征文活动 | AI创新之路,DAMODEL助你一臂之力GPU

目录 前言—— DAMODEL&#xff08;丹摩智算&#xff09; 算力服务 直观的感受算力提供商的强大​ 平台功能介绍​ 镜像选择 云磁盘创建 总结 前言—— 只需轻点鼠标,开发者便可拥有属于自己的AI计算王国 - 从丰富的GPU实例选择,到高性能的云磁盘,再到预配置的深度学习…

基于大数据爬虫数据挖掘技术+Python的网络用户购物行为分析与可视化平台(源码+论文+PPT+部署文档教程等)

#1024程序员节&#xff5c;征文# 博主介绍&#xff1a;CSDN毕设辅导第一人、全网粉丝50W,csdn特邀作者、博客专家、腾讯云社区合作讲师、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老…

六、卷积神经网络(CNN)基础

卷积神经网络&#xff08;CNN&#xff09;基础 前言一、CNN概述二、卷积层2.1 卷积2.2 步幅(Stride)2.3 填充(Padding)2.4 多通道卷积2.5 多卷积计算2.6 特征图大小计算2.7 代码演示 三、池化层3.1 池化层计算3.1.1 最大池化层3.1.2 平均池化层 3.2 填充(Padding)3.3 步幅(Stri…

国标GB28181视频平台EasyCVR视频融合平台H.265/H.264转码业务流程

在当今数字化、网络化的视频监控领域&#xff0c;大中型项目对于视频监控管理平台的需求日益增长&#xff0c;特别是在跨区域、多设备、高并发的复杂环境中。EasyCVR视频监控汇聚管理平台正是为了满足这些需求而设计的&#xff0c;它不仅提供了全面的管理功能&#xff0c;还支持…

Jmeter中的断言(四)

13--XPath断言 功能特点 数据验证&#xff1a;验证 XML 响应数据是否包含或不包含特定的字段或值。支持 XPath 表达式&#xff1a;使用 XPath 表达式定位和验证 XML 数据中的字段。灵活配置&#xff1a;可以设置多个断言条件&#xff0c;满足复杂的测试需求。 配置步骤 添加…

实验室管理解决方案:Spring Boot技术

6系统测试 6.1概念和意义 测试的定义&#xff1a;程序测试是为了发现错误而执行程序的过程。测试(Testing)的任务与目的可以描述为&#xff1a; 目的&#xff1a;发现程序的错误&#xff1b; 任务&#xff1a;通过在计算机上执行程序&#xff0c;暴露程序中潜在的错误。 另一个…

【STM32】USART串口数据包

数据包的作用是将一个个单独的数据打包起来&#xff0c;方便进行多字节的数据通信 数据包格式 HEX数据包 文本数据包 数据包接收 HEX数据包接收&#xff08;固定包长&#xff09; 文本数据包接收&#xff08;可变包长&#xff09; 串口收发HEX数据包 接线图 Serial模块 se…

Ubuntu下的Eigen库的安装及基本使用教程

一、Eigen库介绍 简介 Eigen [1]目前最新的版本是3.4&#xff0c;除了C标准库以外&#xff0c;不需要任何其他的依赖包。Eigen使用的CMake建立配置文件和单元测试&#xff0c;并自动安装。如果使用Eigen库&#xff0c;只需包特定模块的的头文件即可。 基本功能 Eigen适用范…

tcpdump交叉编译

TCPDUMP在Libpcap上开发。 首先需要编译libcap。 网上那么多教程&#xff0c;下载地址都只给了一个英文的官网首页&#xff0c; 你尽可以试试&#xff0c;从里面找到下载地址都要费半天时间。 \color{red}网上那么多教程&#xff0c;下载地址都只给了一个英文的官网首页&#…